Merge "Move GSI AVB keys to vendor_boot if BOARD_MOVE_GSI_AVB_KEYS_TO_VENDOR_BOOT"
diff --git a/Android.bp b/Android.bp
deleted file mode 100644
index 0b4a925..0000000
--- a/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-filegroup {
- name: "android_filesystem_config_header",
- srcs: ["include/private/android_filesystem_config.h"],
-}
diff --git a/adb/Android.bp b/adb/Android.bp
index 8addf95..c361a14 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -25,6 +25,7 @@
"-Wextra",
"-Werror",
"-Wexit-time-destructors",
+ "-Wno-non-virtual-dtor",
"-Wno-unused-parameter",
"-Wno-missing-field-initializers",
"-Wthread-safety",
@@ -270,6 +271,8 @@
host_supported: true,
compile_multilib: "both",
min_sdk_version: "apex_inherit",
+ // This library doesn't use build::GetBuildNumber()
+ use_version_lib: false,
srcs: [
"sysdeps/env.cpp",
@@ -290,8 +293,9 @@
export_include_dirs: ["."],
visibility: [
- "//system/core/adb:__subpackages__",
"//bootable/recovery/minadbd:__subpackages__",
+ "//packages/modules/adb:__subpackages__",
+ "//system/core/adb:__subpackages__",
],
apex_available: [
@@ -496,6 +500,7 @@
],
visibility: [
"//bootable/recovery/minadbd",
+ "//packages/modules/adb:__subpackages__",
"//system/core/adb",
],
}
@@ -575,6 +580,7 @@
"com.android.adbd",
],
visibility: [
+ "//packages/modules/adb",
"//system/core/adb",
],
@@ -633,6 +639,7 @@
visibility: [
"//bootable/recovery/minadbd",
+ "//packages/modules/adb",
"//system/core/adb",
],
}
@@ -752,6 +759,8 @@
"mdns_test.cpp",
],
+ test_config: "adb_test.xml",
+
shared_libs: [
"liblog",
],
diff --git a/adb/README.md b/adb/README.md
new file mode 100644
index 0000000..224387c
--- /dev/null
+++ b/adb/README.md
@@ -0,0 +1,94 @@
+# ADB Internals
+
+If you are new to adb source code, you should start by reading [OVERVIEW.TXT](OVERVIEW.TXT) which describes the three components of adb pipeline.
+
+This document is here to boost what can be achieved within a "window of naive interest". You will not find function or class documentation here but rather the "big picture" which should allow you to build a mental map to help navigate the code.
+
+## Three components of adb pipeline
+
+As outlined in the overview, this codebase generates three components (Client, Server (a.k.a Host), and Daemon (a.k.a adbd)). The central part is the Server which runs on the Host computer. On one side the Server exposes a "Smart Socket" to Clients such as adb or DDMLIB. On the other side, the Server continuously monitors for connecting Daemons (as USB devices or TCP emulator). Communication with a device is done with a Transport.
+
+```
++----------+ +------------------------+
+| ADB +----------+ | ADB SERVER | +----------+
+| CLIENT | | | | (USB)| ADBD |
++----------+ | | Transport+-------------+ (DEVICE) |
+ | | | +----------+
++----------- | | |
+| ADB | v + | +----------+
+| CLIENT +--------->SmartSocket | (USB)| ADBD |
++----------+ ^ | (TCP/IP) Transport+-------------+ (DEVICE) |
+ | | | +----------+
++----------+ | | |
+| DDMLIB | | | Transport+--+ +----------+
+| CLIENT +----------+ | | | (TCP/IP)| ADBD |
++----------+ +------------------------+ +----------|(EMULATOR)|
+ +----------+
+```
+
+The Client and the Server are contained in the same executable and both run on the Host machine. Code sections specific to the Host is enclosed within `ADB_HOST` guard. adbd runs on the Android Device. Daemon specific code is enclosed in `!ADB_HOST` but also sometimes with-in `__ANDROID__` guard.
+
+
+## "SMART SOCKET" and TRANSPORT
+
+A smart socket is a simple TCP socket with a smart protocol built on top of it. This is what Clients connect onto from the Host side. The Client must always initiate communication via a human readable request but the response format varies. The smart protocol is documented in [SERVICES.TXT](SERVICES.TXT).
+
+On the other side, the Server communicate with a device via a Transport. adb initially targeted devices connecting over USB, which is restricted to a fixed number of data streams. Therefore, adb multiplexes multiple byte streams over a single pipe via Transport. When devices connecting over other mechanisms (e.g. emulators over TCP) were introduced, the existing transport protocol was maintained.
+
+## THREADING MODEL and FDEVENT system
+
+At the heart of both the Server and Daemon is a main thread running an fdevent loop, which is an platform-independent abstraction over poll/epoll/WSAPoll monitoring file descriptors events. Requests and services are usually server from the main thread but some service requests result in new threads being spawned.
+
+To allow for operations to run on the Main thread, fdevent features a RunQueue combined with an interrupt fd to force polling to return.
+
+```
++------------+ +-------------------------^
+| RUNQUEUE | | |
++------------+ | POLLING (Main thread) |
+| Function<> | | |
++------------+ | |
+| Function<> | ^-^-------^-------^------^^
++------------+ | | | |
+| ... | | | | |
++------------+ | | | |
+| | | | | |
+|============| | | | |
+|Interrupt fd+------+ +----+ +----+ +----+
++------------+ fd Socket Pipe
+```
+
+## ASOCKET, APACKET, and AMESSAGE
+
+The asocket, apacket, and amessage constructs exist only to wrap data while it transits on a Transport. An asocket handles a stream of apackets. An apacket consists in a amessage header featuring a command (`A_SYNC`, `A_OPEN`, `A_CLSE`, `A_WRTE`, `A_OKAY`, ...) followed by a payload (find more documentation in [protocol.txt](protocol.txt). There is no `A_READ` command because an asocket is unidirectional. To model a bi-directional stream, asocket have a peer which go in the opposite direction.
+
+An asocket features a buffer where the elemental unit is an apacket. Is traffic is inbound, the buffer stores apacket until they are consumed. If the traffic is oubound, the buffer store apackets until they are sent down the wire (with `A_WRTE` commands).
+
+```
++---------------------ASocket------------------------+
+ | |
+ | +----------------APacket Queue------------------+ |
+ | | | |
+ | | APacket APacket APacket | |
+ | | +--------+ +--------+ +--------+ | |
+ | | |AMessage| |AMessage| |AMessage| | |
+ | | +--------+ +--------+ +--------+ | |
+ | | | | | | | | | |
+ | | ..... | | | | | | | |
+ | | | Data | | Data | | Data | | |
+ | | | | | | | | | |
+ | | | | | | | | | |
+ | | +--------+ +--------+ +--------+ | |
+ | | | |
+ | +-----------------------------------------------+ |
+ +---------------------------------------------------+
+```
+
+This system allows to multiplex data streams on an unique byte stream. Without entering too much into details, the amessage fields arg1 and arg2 are used alike in the TCP protocol where local and remote ports identify an unique stream. Note that unlike TCP which feature an "unacknowledged-send window", an apacket is sent only after the previous one has been confirmed to be received.
+
+The two types of asocket (Remote and Local) differentiate between outbound and inbound traffic.
+
+## adbd <-> APPPLICATION communication
+
+This pipeline is detailed in [services.cpp](services.cpp). The JDWP extension implemented by Dalvik/ART are documented in:
+- platform/dalvik/+/master/docs/debugmon.html
+- platform/dalvik/+/master/docs/debugger.html
diff --git a/adb/adb_test.xml b/adb/adb_test.xml
new file mode 100644
index 0000000..cc3302d
--- /dev/null
+++ b/adb/adb_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Runs adbd_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="adbd_test->/data/local/tmp/adbd_test" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="adbd_test" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.adbd" />
+ </object>
+</configuration>
diff --git a/adb/apex/apex_manifest.json b/adb/apex/apex_manifest.json
index ff2df12..4a07bdc 100644
--- a/adb/apex/apex_manifest.json
+++ b/adb/apex/apex_manifest.json
@@ -1,4 +1,4 @@
{
"name": "com.android.adbd",
- "version": 1
+ "version": 300900700
}
diff --git a/adb/client/bugreport.cpp b/adb/client/bugreport.cpp
index f2e722a..b765a30 100644
--- a/adb/client/bugreport.cpp
+++ b/adb/client/bugreport.cpp
@@ -224,7 +224,8 @@
// 'bugreport' would generate a lot of output the user might not be prepared to handle).
fprintf(stderr,
"Failed to get bugreportz version: 'bugreportz -v' returned '%s' (code %d).\n"
- "If the device does not run Android 7.0 or above, try 'adb bugreport' instead.\n",
+ "If the device does not run Android 7.0 or above, try this instead:\n"
+ "\tadb bugreport > bugreport.txt\n",
bugz_output.c_str(), status);
return status != 0 ? status : -1;
}
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 43772ba..d9e69f7 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1149,7 +1149,7 @@
// If we were using a specific transport ID, there's nothing we can wait for.
if (previous_id == 0) {
adb_set_transport(previous_type, previous_serial, 0);
- wait_for_device("wait-for-device", 6000ms);
+ wait_for_device("wait-for-device", 12000ms);
}
return true;
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 8bbe2a8..2e8b975 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -1053,7 +1053,7 @@
if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length, dry_run)) {
return false;
}
- return sc.ReadAcknowledgements();
+ return sc.ReadAcknowledgements(sync);
#endif
}
@@ -1077,7 +1077,7 @@
return false;
}
}
- return sc.ReadAcknowledgements();
+ return sc.ReadAcknowledgements(sync);
}
static bool sync_recv_v1(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp
index dd117d2..1a071fd 100644
--- a/adb/client/incremental_utils.cpp
+++ b/adb/client/incremental_utils.cpp
@@ -305,6 +305,7 @@
static std::vector<int32_t> InstallationPriorityBlocks(borrowed_fd fd, Size fileSize) {
static constexpr std::array<std::string_view, 3> additional_matches = {
"resources.arsc"sv, "AndroidManifest.xml"sv, "classes.dex"sv};
+
auto [zip, _] = openZipArchive(fd, fileSize);
if (!zip) {
return {};
@@ -325,7 +326,7 @@
}
std::vector<int32_t> installationPriorityBlocks;
- ZipEntry entry;
+ ZipEntry64 entry;
std::string_view entryName;
while (Next(cookie, &entry, &entryName) == 0) {
if (entryName == "classes.dex"sv) {
@@ -358,7 +359,7 @@
std::vector<int32_t> PriorityBlocksForFile(const std::string& filepath, borrowed_fd fd,
Size fileSize) {
- if (!android::base::EndsWithIgnoreCase(filepath, ".apk"sv)) {
+ if (!android::base::EndsWithIgnoreCase(filepath, ".apk")) {
return {};
}
off64_t signerOffset = SignerBlockOffset(fd, fileSize);
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
index e2c27f1..c4052c3 100644
--- a/adb/crypto/Android.bp
+++ b/adb/crypto/Android.bp
@@ -39,8 +39,9 @@
export_include_dirs: ["include"],
visibility: [
- "//system/core/adb:__subpackages__",
"//bootable/recovery/minadbd:__subpackages__",
+ "//packages/modules/adb:__subpackages__",
+ "//system/core/adb:__subpackages__",
],
host_supported: true,
diff --git a/adb/daemon/adb_wifi.cpp b/adb/daemon/adb_wifi.cpp
index bce303b..2f9e9b4 100644
--- a/adb/daemon/adb_wifi.cpp
+++ b/adb/daemon/adb_wifi.cpp
@@ -42,7 +42,8 @@
static void adb_disconnected(void* unused, atransport* t) {
LOG(INFO) << "ADB wifi device disconnected";
- adbd_auth_tls_device_disconnected(auth_ctx, kAdbTransportTypeWifi, t->auth_id);
+ CHECK(t->auth_id.has_value());
+ adbd_auth_tls_device_disconnected(auth_ctx, kAdbTransportTypeWifi, t->auth_id.value());
}
// TODO(b/31559095): need bionic host so that we can use 'prop_info' returned
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 2edf582..1a1e4ad 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -207,15 +207,27 @@
}
static void adbd_auth_key_authorized(void* arg, uint64_t id) {
- LOG(INFO) << "adb client authorized";
+ LOG(INFO) << "adb client " << id << " authorized";
fdevent_run_on_main_thread([=]() {
- LOG(INFO) << "arg = " << reinterpret_cast<uintptr_t>(arg);
auto* transport = transport_from_callback_arg(arg);
if (!transport) {
- LOG(ERROR) << "authorization received for deleted transport, ignoring";
+ LOG(ERROR) << "authorization received for deleted transport (" << id << "), ignoring";
return;
}
- transport->auth_id = id;
+
+ if (transport->auth_id.has_value()) {
+ if (transport->auth_id.value() != id) {
+ LOG(ERROR)
+ << "authorization received, but auth id doesn't match, ignoring (expected "
+ << transport->auth_id.value() << ", got " << id << ")";
+ return;
+ }
+ } else {
+ // Older versions (i.e. dogfood/beta builds) of libadbd_auth didn't pass the initial
+ // auth id to us, so we'll just have to trust it until R ships and we can retcon this.
+ transport->auth_id = id;
+ }
+
adbd_auth_verified(transport);
});
}
@@ -265,14 +277,20 @@
static void adb_disconnected(void* unused, atransport* t) {
LOG(INFO) << "ADB disconnect";
- adbd_auth_notify_disconnect(auth_ctx, t->auth_id);
+ CHECK(t->auth_id.has_value());
+ adbd_auth_notify_disconnect(auth_ctx, t->auth_id.value());
}
void adbd_auth_confirm_key(atransport* t) {
LOG(INFO) << "prompting user to authorize key";
t->AddDisconnect(&adb_disconnect);
- adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(),
- transport_to_callback_arg(t));
+ if (adbd_auth_prompt_user_with_id) {
+ t->auth_id = adbd_auth_prompt_user_with_id(auth_ctx, t->auth_key.data(), t->auth_key.size(),
+ transport_to_callback_arg(t));
+ } else {
+ adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(),
+ transport_to_callback_arg(t));
+ }
}
void adbd_notify_framework_connected_key(atransport* t) {
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index a663871..50d7364 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -584,12 +584,11 @@
incoming_header_ = msg;
} else {
size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
- Block payload = std::move(block->payload);
if (block->payload.size() > bytes_left) {
HandleError("received too many bytes while waiting for payload");
return false;
}
- incoming_payload_.append(std::move(payload));
+ incoming_payload_.append(std::move(block->payload));
}
if (incoming_header_->data_length == incoming_payload_.size()) {
diff --git a/adb/libs/adbconnection/Android.bp b/adb/libs/adbconnection/Android.bp
index f7d2dc1..29ae060 100644
--- a/adb/libs/adbconnection/Android.bp
+++ b/adb/libs/adbconnection/Android.bp
@@ -39,6 +39,7 @@
defaults: ["adbd_defaults"],
visibility: [
"//art:__subpackages__",
+ "//packages/modules/adb/apex:__subpackages__",
"//system/core/adb/apex:__subpackages__",
],
apex_available: [
diff --git a/adb/pairing_auth/Android.bp b/adb/pairing_auth/Android.bp
index a43f4d0..806879d 100644
--- a/adb/pairing_auth/Android.bp
+++ b/adb/pairing_auth/Android.bp
@@ -40,6 +40,7 @@
visibility: [
"//art:__subpackages__",
+ "//packages/modules/adb:__subpackages__",
"//system/core/adb:__subpackages__",
],
diff --git a/adb/pairing_connection/Android.bp b/adb/pairing_connection/Android.bp
index 9595511..1886885 100644
--- a/adb/pairing_connection/Android.bp
+++ b/adb/pairing_connection/Android.bp
@@ -39,8 +39,9 @@
visibility: [
"//art:__subpackages__",
- "//system/core/adb:__subpackages__",
"//frameworks/base/services:__subpackages__",
+ "//packages/modules/adb:__subpackages__",
+ "//system/core/adb:__subpackages__",
// This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
"//bootable/recovery/minadbd:__subpackages__",
@@ -129,8 +130,9 @@
visibility: [
"//art:__subpackages__",
- "//system/core/adb:__subpackages__",
"//frameworks/base/services:__subpackages__",
+ "//packages/modules/adb:__subpackages__",
+ "//system/core/adb:__subpackages__",
],
recovery_available: false,
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
index 086d10e..ef97208 100644
--- a/adb/proto/Android.bp
+++ b/adb/proto/Android.bp
@@ -40,6 +40,7 @@
},
visibility: [
+ "//packages/modules/adb:__subpackages__",
"//system/core/adb:__subpackages__",
// This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
@@ -94,6 +95,7 @@
},
visibility: [
+ "//packages/modules/adb:__subpackages__",
"//system/core/adb:__subpackages__",
// This needs to be visible to minadbd, even though it's removed via exclude_shared_libs.
diff --git a/adb/test_device.py b/adb/test_device.py
index c1caafc..a92d4a7 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1271,6 +1271,31 @@
if temp_dir is not None:
shutil.rmtree(temp_dir)
+ def test_push_sync_multiple(self):
+ """Sync multiple host directories to a specific path."""
+
+ try:
+ temp_dir = tempfile.mkdtemp()
+ temp_files = make_random_host_files(in_dir=temp_dir, num_files=32)
+
+ device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'sync_src_dst')
+
+ # Clean up any stale files on the device.
+ device = adb.get_device() # pylint: disable=no-member
+ device.shell(['rm', '-rf', device_dir])
+ device.shell(['mkdir', '-p', device_dir])
+
+ host_paths = [os.path.join(temp_dir, x.base_name) for x in temp_files]
+ device.push(host_paths, device_dir, sync=True)
+
+ self.verify_sync(device, temp_files, device_dir)
+
+ self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+ finally:
+ if temp_dir is not None:
+ shutil.rmtree(temp_dir)
+
+
def test_push_dry_run_nonexistent_file(self):
"""Push with dry run."""
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
index e5204f3..1e00548 100644
--- a/adb/tls/Android.bp
+++ b/adb/tls/Android.bp
@@ -40,6 +40,7 @@
visibility: [
"//bootable/recovery/minadbd:__subpackages__",
+ "//packages/modules/adb:__subpackages__",
"//system/core/adb:__subpackages__",
],
diff --git a/adb/transport.cpp b/adb/transport.cpp
index c33d5af..93b4618 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -129,8 +129,8 @@
};
// Only retry for up to one minute.
- static constexpr const std::chrono::seconds kDefaultTimeout = 10s;
- static constexpr const size_t kMaxAttempts = 6;
+ static constexpr const std::chrono::seconds kDefaultTimeout = 3s;
+ static constexpr const size_t kMaxAttempts = 20;
// Protects all members.
std::mutex reconnect_mutex_;
diff --git a/adb/transport.h b/adb/transport.h
index b1f2744..d59be59 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -27,6 +27,7 @@
#include <list>
#include <memory>
#include <mutex>
+#include <optional>
#include <string>
#include <string_view>
#include <thread>
@@ -320,7 +321,7 @@
#if !ADB_HOST
// Used to provide the key to the framework.
std::string auth_key;
- uint64_t auth_id;
+ std::optional<uint64_t> auth_id;
#endif
bool IsTcpDevice() const { return type == kTransportLocal; }
diff --git a/bootstat/boot_event_record_store.h b/bootstat/boot_event_record_store.h
index f872c85..e852304 100644
--- a/bootstat/boot_event_record_store.h
+++ b/bootstat/boot_event_record_store.h
@@ -69,4 +69,4 @@
DISALLOW_COPY_AND_ASSIGN(BootEventRecordStore);
};
-#endif // BOOT_EVENT_RECORD_STORE_H_
\ No newline at end of file
+#endif // BOOT_EVENT_RECORD_STORE_H_
diff --git a/cli-test/cli-test.cpp b/cli-test/cli-test.cpp
index d6e27ee..d1ef1b4 100644
--- a/cli-test/cli-test.cpp
+++ b/cli-test/cli-test.cpp
@@ -146,6 +146,13 @@
test->befores.push_back(line);
} else if (Match(&line, "after:")) {
test->afters.push_back(line);
+ } else if (Match(&line, "expected-exit-status:")) {
+ char* end_p;
+ errno = 0;
+ test->exit_status = strtol(line.c_str(), &end_p, 10);
+ if (errno != 0 || *end_p != '\0') {
+ Die(0, "%s:%zu: bad exit status: \"%s\"", g_file, g_line, line.c_str());
+ }
} else if (Match(&line, "expected-stdout:")) {
// Collect tab-indented lines.
std::string text;
@@ -231,15 +238,15 @@
V("running command \"%s\"", test.command.c_str());
CapturedStdout test_stdout;
CapturedStderr test_stderr;
- int exit_status = system(test.command.c_str());
+ int status = system(test.command.c_str());
test_stdout.Stop();
test_stderr.Stop();
- V("exit status %d", exit_status);
- if (exit_status != test.exit_status) {
+ V("system() returned status %d", status);
+ if (WEXITSTATUS(status) != test.exit_status) {
failed = true;
fprintf(stderr, "Incorrect exit status: expected %d but %s\n", test.exit_status,
- ExitStatusToString(exit_status).c_str());
+ ExitStatusToString(status).c_str());
}
if (!CheckOutput("stdout", test_stdout.str(), test.expected_stdout, FILES)) failed = true;
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index ad10a1f..99cabdd 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -343,6 +343,12 @@
apex_available: [
"com.android.runtime",
],
+
+ product_variables: {
+ experimental_mte: {
+ cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
+ },
+ },
}
cc_binary {
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index d7cb972..5280121 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -40,6 +40,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <bionic/mte_kernel.h>
#include <bionic/reserved_signals.h>
#include <cutils/sockets.h>
#include <log/log.h>
@@ -486,6 +487,17 @@
continue;
}
+#ifdef ANDROID_EXPERIMENTAL_MTE
+ struct iovec iov = {
+ &info.tagged_addr_ctrl,
+ sizeof(info.tagged_addr_ctrl),
+ };
+ if (ptrace(PTRACE_GETREGSET, thread, NT_ARM_TAGGED_ADDR_CTRL,
+ reinterpret_cast<void*>(&iov)) == -1) {
+ info.tagged_addr_ctrl = -1;
+ }
+#endif
+
if (thread == g_target_thread) {
// Read the thread's registers along with the rest of the crash info out of the pipe.
ReadCrashInfo(input_pipe, &siginfo, &info.registers, &process_info);
@@ -585,8 +597,8 @@
}
// TODO: Use seccomp to lock ourselves down.
- unwindstack::UnwinderFromPid unwinder(256, vm_pid);
- if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+ unwindstack::UnwinderFromPid unwinder(256, vm_pid, unwindstack::Regs::CurrentArch());
+ if (!unwinder.Init()) {
LOG(FATAL) << "Failed to init unwinder object.";
}
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 108787e..5ed9e57 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -309,6 +309,11 @@
std::string result;
ConsumeFd(std::move(output_fd), &result);
ASSERT_MATCH(result, R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr 0xdead)");
+
+ if (mte_supported()) {
+ // Test that the default TAGGED_ADDR_CTRL value is set.
+ ASSERT_MATCH(result, R"(tagged_addr_ctrl: 000000000007fff3)");
+ }
}
TEST_F(CrasherTest, tagged_fault_addr) {
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 9bcbdb3..e103c82 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -82,16 +82,12 @@
thread.pid = getpid();
thread.tid = gettid();
thread.thread_name = get_thread_name(gettid());
- unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
- thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
+ thread.registers.reset(
+ unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
// TODO: Create this once and store it in a global?
unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
- if (unwinder.Init(arch)) {
- dump_backtrace_thread(output_fd, &unwinder, thread);
- } else {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
- }
+ dump_backtrace_thread(output_fd, &unwinder, thread);
}
__linker_disable_fallback_allocator();
}
@@ -237,6 +233,8 @@
// Fetch output fd from tombstoned.
unique_fd tombstone_socket, output_fd;
if (!tombstoned_connect(getpid(), &tombstone_socket, &output_fd, kDebuggerdNativeBacktrace)) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "missing crash_dump_fallback() in selinux policy?");
goto exit;
}
diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp
index f5a873c..c543a83 100644
--- a/debuggerd/libdebuggerd/backtrace.cpp
+++ b/debuggerd/libdebuggerd/backtrace.cpp
@@ -18,8 +18,9 @@
#include "libdebuggerd/backtrace.h"
-#include <errno.h>
#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
@@ -65,7 +66,11 @@
unwinder->SetRegs(thread.registers.get());
unwinder->Unwind();
if (unwinder->NumFrames() == 0) {
- _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d", thread.tid);
+ _LOG(&log, logtype::THREAD, "Unwind failed: tid = %d\n", thread.tid);
+ if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
+ _LOG(&log, logtype::THREAD, " Error code: %s\n", unwinder->LastErrorCodeString());
+ _LOG(&log, logtype::THREAD, " Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
+ }
return;
}
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
index 04c4b5c..30e75e1 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h
@@ -23,6 +23,7 @@
struct ThreadInfo {
std::unique_ptr<unwindstack::Regs> registers;
+ long tagged_addr_ctrl = -1;
pid_t uid;
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 7af99c9..d88c5a9 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -180,6 +180,9 @@
_LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", thread_info.pid,
thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str());
_LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid);
+ if (thread_info.tagged_addr_ctrl != -1) {
+ _LOG(log, logtype::HEADER, "tagged_addr_ctrl: %016lx\n", thread_info.tagged_addr_ctrl);
+ }
}
static std::string get_addr_string(uint64_t addr) {
@@ -404,7 +407,11 @@
unwinder->SetRegs(regs_copy.get());
unwinder->Unwind();
if (unwinder->NumFrames() == 0) {
- _LOG(log, logtype::THREAD, "Failed to unwind");
+ _LOG(log, logtype::THREAD, "Failed to unwind\n");
+ if (unwinder->LastErrorCode() != unwindstack::ERROR_NONE) {
+ _LOG(log, logtype::THREAD, " Error code: %s\n", unwinder->LastErrorCodeString());
+ _LOG(log, logtype::THREAD, " Error address: 0x%" PRIx64 "\n", unwinder->LastErrorAddress());
+ }
} else {
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
log_backtrace(log, unwinder, " ");
@@ -575,8 +582,8 @@
.siginfo = siginfo,
};
- unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
- if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
+ unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid, unwindstack::Regs::CurrentArch());
+ if (!unwinder.Init()) {
LOG(FATAL) << "Failed to init unwinder object.";
}
diff --git a/debuggerd/tombstoned/tombstoned.rc b/debuggerd/tombstoned/tombstoned.rc
index b4a1e71..c39f4e4 100644
--- a/debuggerd/tombstoned/tombstoned.rc
+++ b/debuggerd/tombstoned/tombstoned.rc
@@ -6,6 +6,3 @@
socket tombstoned_intercept seqpacket 0666 system system
socket tombstoned_java_trace seqpacket 0666 system system
writepid /dev/cpuset/system-background/tasks
-
-on post-fs-data
- start tombstoned
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index 6673543..85a19e5 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -126,7 +126,7 @@
shared_libs: [
"android.hardware.boot@1.0",
"android.hardware.boot@1.1",
- "android.hardware.fastboot@1.0",
+ "android.hardware.fastboot@1.1",
"android.hardware.health@2.0",
"libasyncio",
"libbase",
@@ -147,6 +147,7 @@
static_libs: [
"libgtest_prod",
"libhealthhalutils",
+ "libsnapshot_cow",
"libsnapshot_nobinder",
"update_metadata-protos",
],
@@ -251,7 +252,7 @@
darwin: {
srcs: ["usb_osx.cpp"],
},
- linux_glibc: {
+ linux: {
srcs: ["usb_linux.cpp"],
},
},
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 2553353..4601960 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -164,6 +164,28 @@
return device->WriteOkay(message);
}
+bool OemPostWipeData(FastbootDevice* device) {
+ auto fastboot_hal = device->fastboot_hal();
+ if (!fastboot_hal) {
+ return false;
+ }
+
+ Result ret;
+ auto ret_val = fastboot_hal->doOemSpecificErase([&](Result result) { ret = result; });
+ if (!ret_val.isOk()) {
+ return false;
+ }
+ if (ret.status == Status::NOT_SUPPORTED) {
+ return false;
+ } else if (ret.status != Status::SUCCESS) {
+ device->WriteStatus(FastbootResult::FAIL, ret.message);
+ } else {
+ device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
+ }
+
+ return true;
+}
+
bool EraseHandler(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() < 2) {
return device->WriteStatus(FastbootResult::FAIL, "Invalid arguments");
@@ -184,7 +206,18 @@
return device->WriteStatus(FastbootResult::FAIL, "Partition doesn't exist");
}
if (wipe_block_device(handle.fd(), get_block_device_size(handle.fd())) == 0) {
- return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
+ //Perform oem PostWipeData if Android userdata partition has been erased
+ bool support_oem_postwipedata = false;
+ if (partition_name == "userdata") {
+ support_oem_postwipedata = OemPostWipeData(device);
+ }
+
+ if (!support_oem_postwipedata) {
+ return device->WriteStatus(FastbootResult::OKAY, "Erasing succeeded");
+ } else {
+ //Write device status in OemPostWipeData(), so just return true
+ return true;
+ }
}
return device->WriteStatus(FastbootResult::FAIL, "Erasing failed");
}
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 1b0859f..35f3de0 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -22,7 +22,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/hardware/boot/1.0/IBootControl.h>
-#include <android/hardware/fastboot/1.0/IFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
#include <fs_mgr.h>
#include <fs_mgr/roots.h>
#include <healthhalutils/HealthHalUtils.h>
@@ -37,7 +37,7 @@
using ::android::hardware::hidl_string;
using ::android::hardware::boot::V1_0::IBootControl;
using ::android::hardware::boot::V1_0::Slot;
-using ::android::hardware::fastboot::V1_0::IFastboot;
+using ::android::hardware::fastboot::V1_1::IFastboot;
using ::android::hardware::health::V2_0::get_health_service;
namespace sph = std::placeholders;
@@ -139,7 +139,13 @@
bool FastbootDevice::HandleData(bool read, std::vector<char>* data) {
auto read_write_data_size = read ? this->get_transport()->Read(data->data(), data->size())
: this->get_transport()->Write(data->data(), data->size());
- if (read_write_data_size == -1 || static_cast<size_t>(read_write_data_size) != data->size()) {
+ if (read_write_data_size == -1) {
+ LOG(ERROR) << (read ? "read from" : "write to") << " transport failed";
+ return false;
+ }
+ if (static_cast<size_t>(read_write_data_size) != data->size()) {
+ LOG(ERROR) << (read ? "read" : "write") << " expected " << data->size() << " bytes, got "
+ << read_write_data_size;
return false;
}
return true;
diff --git a/fastboot/device/fastboot_device.h b/fastboot/device/fastboot_device.h
index bbe8172..23be721 100644
--- a/fastboot/device/fastboot_device.h
+++ b/fastboot/device/fastboot_device.h
@@ -24,7 +24,7 @@
#include <android/hardware/boot/1.0/IBootControl.h>
#include <android/hardware/boot/1.1/IBootControl.h>
-#include <android/hardware/fastboot/1.0/IFastboot.h>
+#include <android/hardware/fastboot/1.1/IFastboot.h>
#include <android/hardware/health/2.0/IHealth.h>
#include "commands.h"
@@ -53,7 +53,7 @@
return boot_control_hal_;
}
android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1() { return boot1_1_; }
- android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal() {
+ android::sp<android::hardware::fastboot::V1_1::IFastboot> fastboot_hal() {
return fastboot_hal_;
}
android::sp<android::hardware::health::V2_0::IHealth> health_hal() { return health_hal_; }
@@ -67,7 +67,7 @@
android::sp<android::hardware::boot::V1_0::IBootControl> boot_control_hal_;
android::sp<android::hardware::boot::V1_1::IBootControl> boot1_1_;
android::sp<android::hardware::health::V2_0::IHealth> health_hal_;
- android::sp<android::hardware::fastboot::V1_0::IFastboot> fastboot_hal_;
+ android::sp<android::hardware::fastboot::V1_1::IFastboot> fastboot_hal_;
std::vector<char> download_data_;
std::string active_slot_;
};
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index c653167..2caced4 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -248,7 +248,12 @@
}
ssize_t ClientUsbTransport::Read(void* data, size_t len) {
- if (handle_ == nullptr || len > SSIZE_MAX) {
+ if (handle_ == nullptr) {
+ LOG(ERROR) << "ClientUsbTransport: no handle";
+ return -1;
+ }
+ if (len > SSIZE_MAX) {
+ LOG(ERROR) << "ClientUsbTransport: maximum length exceeds bounds";
return -1;
}
char* char_data = static_cast<char*>(data);
@@ -258,6 +263,7 @@
auto bytes_read_now =
handle_->read(handle_.get(), char_data, bytes_to_read, true /* allow_partial */);
if (bytes_read_now < 0) {
+ PLOG(ERROR) << "ClientUsbTransport: read failed";
return bytes_read_total == 0 ? -1 : bytes_read_total;
}
bytes_read_total += bytes_read_now;
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index d33c987..4bf791e 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -526,12 +526,15 @@
static bool UnzipToMemory(ZipArchiveHandle zip, const std::string& entry_name,
std::vector<char>* out) {
- ZipEntry zip_entry;
+ ZipEntry64 zip_entry;
if (FindEntry(zip, entry_name, &zip_entry) != 0) {
fprintf(stderr, "archive does not contain '%s'\n", entry_name.c_str());
return false;
}
+ if (zip_entry.uncompressed_length > std::numeric_limits<size_t>::max()) {
+ die("entry '%s' is too large: %" PRIu64, entry_name.c_str(), zip_entry.uncompressed_length);
+ }
out->resize(zip_entry.uncompressed_length);
fprintf(stderr, "extracting %s (%zu MB) to RAM...\n", entry_name.c_str(),
@@ -637,14 +640,14 @@
static int unzip_to_file(ZipArchiveHandle zip, const char* entry_name) {
unique_fd fd(make_temporary_fd(entry_name));
- ZipEntry zip_entry;
+ ZipEntry64 zip_entry;
if (FindEntry(zip, entry_name, &zip_entry) != 0) {
fprintf(stderr, "archive does not contain '%s'\n", entry_name);
errno = ENOENT;
return -1;
}
- fprintf(stderr, "extracting %s (%" PRIu32 " MB) to disk...", entry_name,
+ fprintf(stderr, "extracting %s (%" PRIu64 " MB) to disk...", entry_name,
zip_entry.uncompressed_length / 1024 / 1024);
double start = now();
int error = ExtractEntryToFile(zip, &zip_entry, fd);
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index d6fd513..5ff01e1 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -740,15 +740,33 @@
unsigned long mountflags = entry.flags;
int ret = 0;
int save_errno = 0;
+ int gc_allowance = 0;
+ std::string opts;
+ bool try_f2fs_gc_allowance = is_f2fs(entry.fs_type) && entry.fs_checkpoint_opts.length() > 0;
+ Timer t;
+
do {
+ if (save_errno == EINVAL && try_f2fs_gc_allowance) {
+ PINFO << "Kernel does not support checkpoint=disable:[n]%, trying without.";
+ try_f2fs_gc_allowance = false;
+ }
+ if (try_f2fs_gc_allowance) {
+ opts = entry.fs_options + entry.fs_checkpoint_opts + ":" +
+ std::to_string(gc_allowance) + "%";
+ } else {
+ opts = entry.fs_options;
+ }
if (save_errno == EAGAIN) {
PINFO << "Retrying mount (source=" << source << ",target=" << target
- << ",type=" << entry.fs_type << ")=" << ret << "(" << save_errno << ")";
+ << ",type=" << entry.fs_type << ", gc_allowance=" << gc_allowance << "%)=" << ret
+ << "(" << save_errno << ")";
}
ret = mount(source.c_str(), target.c_str(), entry.fs_type.c_str(), mountflags,
- entry.fs_options.c_str());
+ opts.c_str());
save_errno = errno;
- } while (ret && save_errno == EAGAIN);
+ if (try_f2fs_gc_allowance) gc_allowance += 10;
+ } while ((ret && save_errno == EAGAIN && gc_allowance <= 100) ||
+ (ret && save_errno == EINVAL && try_f2fs_gc_allowance));
const char* target_missing = "";
const char* source_missing = "";
if (save_errno == ENOENT) {
@@ -764,6 +782,8 @@
if ((ret == 0) && (mountflags & MS_RDONLY) != 0) {
fs_mgr_set_blk_ro(source);
}
+ android::base::SetProperty("ro.boottime.init.mount." + Basename(target),
+ std::to_string(t.duration().count()));
errno = save_errno;
return ret;
}
@@ -1092,7 +1112,7 @@
bool UpdateCheckpointPartition(FstabEntry* entry, const std::string& block_device) {
if (entry->fs_mgr_flags.checkpoint_fs) {
if (is_f2fs(entry->fs_type)) {
- entry->fs_options += ",checkpoint=disable";
+ entry->fs_checkpoint_opts = ",checkpoint=disable";
} else {
LERROR << entry->fs_type << " does not implement checkpoints.";
}
@@ -1296,14 +1316,15 @@
// When multiple fstab records share the same mount_point, it will try to mount each
// one in turn, and ignore any duplicates after a first successful mount.
// Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
-int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
+MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
int error_count = 0;
CheckpointManager checkpoint_manager;
AvbUniquePtr avb_handle(nullptr);
+ bool userdata_mounted = false;
if (fstab->empty()) {
- return FS_MGR_MNTALL_FAIL;
+ return {FS_MGR_MNTALL_FAIL, userdata_mounted};
}
// Keep i int to prevent unsigned integer overflow from (i = top_idx - 1),
@@ -1343,7 +1364,7 @@
}
// Terrible hack to make it possible to remount /data.
- // TODO: refact fs_mgr_mount_all and get rid of this.
+ // TODO: refactor fs_mgr_mount_all and get rid of this.
if (mount_mode == MOUNT_MODE_ONLY_USERDATA && current_entry.mount_point != "/data") {
continue;
}
@@ -1380,7 +1401,7 @@
if (!avb_handle) {
LERROR << "Failed to open AvbHandle";
set_type_property(encryptable);
- return FS_MGR_MNTALL_FAIL;
+ return {FS_MGR_MNTALL_FAIL, userdata_mounted};
}
}
if (avb_handle->SetUpAvbHashtree(¤t_entry, true /* wait_for_verity_dev */) ==
@@ -1422,7 +1443,7 @@
if (status == FS_MGR_MNTALL_FAIL) {
// Fatal error - no point continuing.
- return status;
+ return {status, userdata_mounted};
}
if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
@@ -1437,11 +1458,14 @@
nullptr)) {
LERROR << "Encryption failed";
set_type_property(encryptable);
- return FS_MGR_MNTALL_FAIL;
+ return {FS_MGR_MNTALL_FAIL, userdata_mounted};
}
}
}
+ if (current_entry.mount_point == "/data") {
+ userdata_mounted = true;
+ }
// Success! Go get the next one.
continue;
}
@@ -1541,9 +1565,9 @@
#endif
if (error_count) {
- return FS_MGR_MNTALL_FAIL;
+ return {FS_MGR_MNTALL_FAIL, userdata_mounted};
} else {
- return encryptable;
+ return {encryptable, userdata_mounted};
}
}
@@ -1765,8 +1789,8 @@
}
LINFO << "Remounting /data";
// TODO(b/143970043): remove this hack after fs_mgr_mount_all is refactored.
- int result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
- return result == FS_MGR_MNTALL_FAIL ? -1 : 0;
+ auto result = fs_mgr_mount_all(fstab, MOUNT_MODE_ONLY_USERDATA);
+ return result.code == FS_MGR_MNTALL_FAIL ? -1 : 0;
}
return 0;
}
@@ -1948,21 +1972,19 @@
return true;
}
-static bool PrepareZramDevice(const std::string& loop, off64_t size, const std::string& bdev) {
- if (loop.empty() && bdev.empty()) return true;
+static bool PrepareZramBackingDevice(off64_t size) {
- if (bdev.length()) {
- return InstallZramDevice(bdev);
- }
+ constexpr const char* file_path = "/data/per_boot/zram_swap";
+ if (size == 0) return true;
// Prepare target path
- unique_fd target_fd(TEMP_FAILURE_RETRY(open(loop.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
+ unique_fd target_fd(TEMP_FAILURE_RETRY(open(file_path, O_RDWR | O_CREAT | O_CLOEXEC, 0600)));
if (target_fd.get() == -1) {
- PERROR << "Cannot open target path: " << loop;
+ PERROR << "Cannot open target path: " << file_path;
return false;
}
if (fallocate(target_fd.get(), 0, 0, size) < 0) {
- PERROR << "Cannot truncate target path: " << loop;
+ PERROR << "Cannot truncate target path: " << file_path;
return false;
}
@@ -1994,11 +2016,10 @@
continue;
}
- if (!PrepareZramDevice(entry.zram_loopback_path, entry.zram_loopback_size, entry.zram_backing_dev_path)) {
- LERROR << "Skipping losetup for '" << entry.blk_device << "'";
- }
-
if (entry.zram_size > 0) {
+ if (!PrepareZramBackingDevice(entry.zram_backingdev_size)) {
+ LERROR << "Failure of zram backing device file for '" << entry.blk_device << "'";
+ }
// A zram_size was specified, so we need to configure the
// device. There is no point in having multiple zram devices
// on a system (all the memory comes from the same pool) so
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 233d15f..63b7ad2 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -286,15 +286,10 @@
} else if (StartsWith(flag, "sysfs_path=")) {
// The path to trigger device gc by idle-maint of vold.
entry->sysfs_path = arg;
- } else if (StartsWith(flag, "zram_loopback_path=")) {
- // The path to use loopback for zram.
- entry->zram_loopback_path = arg;
- } else if (StartsWith(flag, "zram_loopback_size=")) {
- if (!ParseByteCount(arg, &entry->zram_loopback_size)) {
- LWARNING << "Warning: zram_loopback_size= flag malformed: " << arg;
+ } else if (StartsWith(flag, "zram_backingdev_size=")) {
+ if (!ParseByteCount(arg, &entry->zram_backingdev_size)) {
+ LWARNING << "Warning: zram_backingdev_size= flag malformed: " << arg;
}
- } else if (StartsWith(flag, "zram_backing_dev_path=")) {
- entry->zram_backing_dev_path = arg;
} else {
LWARNING << "Warning: unknown flag: " << flag;
}
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index 2a67b8c..11e3664 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -60,8 +60,20 @@
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
+
+struct MountAllResult {
+ // One of the FS_MGR_MNTALL_* returned code defined above.
+ int code;
+ // Whether userdata was mounted as a result of |fs_mgr_mount_all| call.
+ bool userdata_mounted;
+};
+
// fs_mgr_mount_all() updates fstab entries that reference device-mapper.
-int fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
+// Returns a |MountAllResult|. The first element is one of the FS_MNG_MNTALL_* return codes
+// defined above, and the second element tells whether this call to fs_mgr_mount_all was responsible
+// for mounting userdata. Later is required for init to correctly enqueue fs-related events as part
+// of userdata remount during userspace reboot.
+MountAllResult fs_mgr_mount_all(android::fs_mgr::Fstab* fstab, int mount_mode);
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h
index 7216402..4093445 100644
--- a/fs_mgr/include_fstab/fstab/fstab.h
+++ b/fs_mgr/include_fstab/fstab/fstab.h
@@ -36,6 +36,7 @@
std::string fs_type;
unsigned long flags = 0;
std::string fs_options;
+ std::string fs_checkpoint_opts;
std::string key_loc;
std::string metadata_key_dir;
std::string metadata_encryption;
@@ -51,9 +52,7 @@
off64_t logical_blk_size = 0;
std::string sysfs_path;
std::string vbmeta_partition;
- std::string zram_loopback_path;
- uint64_t zram_loopback_size = 512 * 1024 * 1024; // 512MB by default;
- std::string zram_backing_dev_path;
+ uint64_t zram_backingdev_size = 0;
std::string avb_keys;
struct FsMgrFlags {
diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp
index e425284..a0bc44d 100644
--- a/fs_mgr/libdm/Android.bp
+++ b/fs_mgr/libdm/Android.bp
@@ -99,7 +99,3 @@
"liblog",
],
}
-
-vts_config {
- name: "VtsKernelLibdmTest",
-}
diff --git a/fs_mgr/libdm/AndroidTest.xml b/fs_mgr/libdm/AndroidTest.xml
deleted file mode 100644
index b4e0c23..0000000
--- a/fs_mgr/libdm/AndroidTest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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 VtsKernelLibdmTest">
- <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="VtsKernelLibdmTest"/>
- <option name="binary-test-source" value="_32bit::DATA/nativetest/libdm_test/libdm_test" />
- <option name="binary-test-source" value="_64bit::DATA/nativetest64/libdm_test/libdm_test" />
- <option name="binary-test-type" value="gtest"/>
- <option name="test-timeout" value="1m"/>
- <option name="precondition-first-api-level" value="29" />
- </test>
-</configuration>
-
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 7912688..bb7d8b3 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -427,6 +427,20 @@
return true;
}
+// Accepts a device mapper device name (like system_a, vendor_b etc) and
+// returns its UUID.
+bool DeviceMapper::GetDmDeviceUuidByName(const std::string& name, std::string* uuid) {
+ struct dm_ioctl io;
+ InitIo(&io, name);
+ if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
+ PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
+ return false;
+ }
+
+ *uuid = std::string(io.uuid);
+ return true;
+}
+
bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
struct dm_ioctl io;
InitIo(&io, name);
diff --git a/fs_mgr/libdm/dm_target.cpp b/fs_mgr/libdm/dm_target.cpp
index 8788b5a..ef46eb9 100644
--- a/fs_mgr/libdm/dm_target.cpp
+++ b/fs_mgr/libdm/dm_target.cpp
@@ -284,6 +284,7 @@
std::vector<std::string> argv;
argv.push_back(std::to_string(start()));
argv.push_back(std::to_string(size()));
+ argv.push_back(control_device());
return android::base::Join(argv, " ");
}
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index abe9c4c..5d6db46 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -172,6 +172,13 @@
// could race with ueventd.
bool GetDmDevicePathByName(const std::string& name, std::string* path);
+ // Returns the device mapper UUID for a given name. If the device does not
+ // exist, false is returned, and the path parameter is not set.
+ //
+ // WaitForFile() should not be used in conjunction with this call, since it
+ // could race with ueventd.
+ bool GetDmDeviceUuidByName(const std::string& name, std::string* path);
+
// Returns a device's unique path as generated by ueventd. This will return
// true as long as the device has been created, even if ueventd has not
// processed it yet.
diff --git a/fs_mgr/libdm/include/libdm/dm_target.h b/fs_mgr/libdm/include/libdm/dm_target.h
index 57e3884..478a3c6 100644
--- a/fs_mgr/libdm/include/libdm/dm_target.h
+++ b/fs_mgr/libdm/include/libdm/dm_target.h
@@ -311,10 +311,15 @@
class DmTargetUser final : public DmTarget {
public:
- DmTargetUser(uint64_t start, uint64_t length) : DmTarget(start, length) {}
+ DmTargetUser(uint64_t start, uint64_t length, std::string control_device)
+ : DmTarget(start, length), control_device_(control_device) {}
std::string name() const override { return "user"; }
+ std::string control_device() const { return control_device_; }
std::string GetParameterString() const override;
+
+ private:
+ std::string control_device_;
};
} // namespace dm
diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp
index a779a78..9517bd3 100644
--- a/fs_mgr/liblp/Android.bp
+++ b/fs_mgr/liblp/Android.bp
@@ -107,7 +107,3 @@
name: "vts_kernel_liblp_test",
defaults: ["liblp_test_defaults"],
}
-
-vts_config {
- name: "VtsKernelLiblpTest",
-}
diff --git a/fs_mgr/liblp/AndroidTest.xml b/fs_mgr/liblp/AndroidTest.xml
deleted file mode 100644
index 2eb0ad1..0000000
--- a/fs_mgr/liblp/AndroidTest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?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 VtsKernelLiblpTest">
- <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="VtsKernelLiblpTest"/>
- <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_kernel_liblp_test/vts_kernel_liblp_test" />
- <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_kernel_liblp_test/vts_kernel_liblp_test" />
- <option name="binary-test-type" value="gtest"/>
- <option name="test-timeout" value="1m"/>
- <option name="precondition-first-api-level" value="29" />
- </test>
-</configuration>
-
diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp
index 3d3dde6..4696ff1 100644
--- a/fs_mgr/liblp/partition_opener.cpp
+++ b/fs_mgr/liblp/partition_opener.cpp
@@ -38,6 +38,9 @@
namespace {
std::string GetPartitionAbsolutePath(const std::string& path) {
+#if !defined(__ANDROID__)
+ return path;
+#else
if (android::base::StartsWith(path, "/")) {
return path;
}
@@ -56,6 +59,7 @@
}
}
return by_name;
+#endif
}
bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device_info) {
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index db50e58..b373d99 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -30,6 +30,7 @@
static_libs: [
"libdm",
"libfstab",
+ "libsnapshot_cow",
"update_metadata-protos",
],
whole_static_libs: [
@@ -38,7 +39,9 @@
"libfstab",
],
header_libs: [
+ "libchrome",
"libfiemap_headers",
+ "libupdate_engine_headers",
],
export_static_lib_headers: [
"update_metadata-protos",
@@ -71,9 +74,11 @@
"android/snapshot/snapshot.proto",
"device_info.cpp",
"snapshot.cpp",
+ "snapshot_reader.cpp",
"snapshot_stats.cpp",
"snapshot_stub.cpp",
"snapshot_metadata_updater.cpp",
+ "snapshot_writer.cpp",
"partition_cow_creator.cpp",
"return.cpp",
"utility.cpp",
@@ -134,6 +139,7 @@
],
export_include_dirs: ["include"],
srcs: [
+ "cow_decompress.cpp",
"cow_reader.cpp",
"cow_writer.cpp",
],
@@ -145,14 +151,48 @@
"libsnapshot_cow_defaults",
],
host_supported: true,
+ recovery_available: true,
shared_libs: [
"libbase",
- "libcrypto",
"liblog",
],
static_libs: [
+ "libbrotli",
"libz",
],
+ ramdisk_available: true,
+}
+
+cc_defaults {
+ name: "libsnapshot_snapuserd_defaults",
+ defaults: [
+ "fs_mgr_defaults",
+ ],
+ cflags: [
+ "-D_FILE_OFFSET_BITS=64",
+ "-Wall",
+ "-Werror",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "snapuserd_client.cpp",
+ ],
+}
+
+cc_library_static {
+ name: "libsnapshot_snapuserd",
+ defaults: [
+ "libsnapshot_snapuserd_defaults",
+ ],
+ recovery_available: true,
+ static_libs: [
+ "libcutils_sockets",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ ramdisk_available: true,
}
cc_library_static {
@@ -209,6 +249,7 @@
"libgmock",
"liblp",
"libsnapshot",
+ "libsnapshot_cow",
"libsnapshot_test_helpers",
"libsparse",
],
@@ -229,12 +270,6 @@
defaults: ["libsnapshot_test_defaults"],
}
-// For VTS 10
-vts_config {
- name: "VtsLibsnapshotTest",
- test_config: "VtsLibsnapshotTest.xml"
-}
-
cc_binary {
name: "snapshotctl",
srcs: [
@@ -243,6 +278,7 @@
static_libs: [
"libfstab",
"libsnapshot",
+ "libsnapshot_cow",
"update_metadata-protos",
],
shared_libs: [
@@ -306,12 +342,15 @@
"libgmock", // from libsnapshot_test_helpers
"liblog",
"liblp",
+ "libsnapshot_cow",
"libsnapshot_test_helpers",
"libprotobuf-mutator",
],
header_libs: [
+ "libchrome",
"libfiemap_headers",
"libstorage_literals_headers",
+ "libupdate_engine_headers",
],
proto: {
type: "full",
@@ -346,8 +385,13 @@
cc_defaults {
name: "snapuserd_defaults",
+ defaults: [
+ "fs_mgr_defaults",
+ ],
srcs: [
+ "snapuserd_server.cpp",
"snapuserd.cpp",
+ "snapuserd_daemon.cpp",
],
cflags: [
@@ -357,8 +401,12 @@
static_libs: [
"libbase",
+ "libbrotli",
+ "libcutils_sockets",
"liblog",
"libdm",
+ "libz",
+ "libsnapshot_cow",
],
}
@@ -374,7 +422,6 @@
ramdisk: true,
static_executable: true,
- system_shared_libs: [],
}
cc_test {
@@ -386,6 +433,7 @@
"cow_api_test.cpp",
],
cflags: [
+ "-D_FILE_OFFSET_BITS=64",
"-Wall",
"-Werror",
],
@@ -396,18 +444,25 @@
"libz",
],
static_libs: [
+ "libbrotli",
"libgtest",
"libsnapshot_cow",
],
test_min_api_level: 30,
auto_gen_config: true,
require_root: false,
+ host_supported: true,
}
cc_binary {
name: "make_cow_from_ab_ota",
host_supported: true,
device_supported: false,
+ cflags: [
+ "-D_FILE_OFFSET_BITS=64",
+ "-Wall",
+ "-Werror",
+ ],
static_libs: [
"libbase",
"libbspatch",
@@ -429,4 +484,74 @@
srcs: [
"make_cow_from_ab_ota.cpp",
],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_binary {
+ name: "estimate_cow_from_nonab_ota",
+ host_supported: true,
+ device_supported: false,
+ cflags: [
+ "-D_FILE_OFFSET_BITS=64",
+ "-Wall",
+ "-Werror",
+ ],
+ static_libs: [
+ "libbase",
+ "libbrotli",
+ "libbz",
+ "libcrypto",
+ "libgflags",
+ "liblog",
+ "libsnapshot_cow",
+ "libsparse",
+ "libz",
+ "libziparchive",
+ ],
+ srcs: [
+ "estimate_cow_from_nonab_ota.cpp",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test {
+ name: "cow_snapuserd_test",
+ defaults: [
+ "fs_mgr_defaults",
+ ],
+ srcs: [
+ "cow_snapuserd_test.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ shared_libs: [
+ "libbase",
+ "liblog",
+ ],
+ static_libs: [
+ "libbrotli",
+ "libgtest",
+ "libsnapshot_cow",
+ "libsnapshot_snapuserd",
+ "libcutils_sockets",
+ "libz",
+ "libdm",
+ ],
+ header_libs: [
+ "libstorage_literals_headers",
+ "libfiemap_headers",
+ ],
+ test_min_api_level: 30,
+ auto_gen_config: true,
+ require_root: false,
}
diff --git a/fs_mgr/libsnapshot/VtsLibsnapshotTest.xml b/fs_mgr/libsnapshot/VtsLibsnapshotTest.xml
deleted file mode 100644
index b53b51e..0000000
--- a/fs_mgr/libsnapshot/VtsLibsnapshotTest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 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 VtsLibsnapshotTest">
- <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="VtsLibsnapshotTest"/>
- <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_libsnapshot_test/vts_libsnapshot_test"/>
- <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_libsnapshot_test/vts_libsnapshot_test"/>
- <option name="binary-test-type" value="gtest"/>
- <option name="test-timeout" value="5m"/>
- </test>
-</configuration>
diff --git a/fs_mgr/libsnapshot/cow_api_test.cpp b/fs_mgr/libsnapshot/cow_api_test.cpp
index 3b3fc47..40d5efb 100644
--- a/fs_mgr/libsnapshot/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/cow_api_test.cpp
@@ -12,11 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <sys/stat.h>
+
+#include <cstdio>
#include <iostream>
#include <memory>
#include <string_view>
#include <android-base/file.h>
+#include <android-base/logging.h>
#include <gtest/gtest.h>
#include <libsnapshot/cow_reader.h>
#include <libsnapshot/cow_writer.h>
@@ -26,12 +30,12 @@
class CowTest : public ::testing::Test {
protected:
- void SetUp() override {
+ virtual void SetUp() override {
cow_ = std::make_unique<TemporaryFile>();
ASSERT_GE(cow_->fd, 0) << strerror(errno);
}
- void TearDown() override { cow_ = nullptr; }
+ virtual void TearDown() override { cow_ = nullptr; }
std::unique_ptr<TemporaryFile> cow_;
};
@@ -66,7 +70,7 @@
ASSERT_TRUE(writer.AddCopy(10, 20));
ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
- ASSERT_TRUE(writer.Finalize());
+ ASSERT_TRUE(writer.Flush());
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
@@ -101,7 +105,7 @@
ASSERT_EQ(op->compression, kCowCompressNone);
ASSERT_EQ(op->data_length, 4096);
ASSERT_EQ(op->new_block, 50);
- ASSERT_EQ(op->source, 104);
+ ASSERT_EQ(op->source, 106);
ASSERT_TRUE(reader.ReadData(*op, &sink));
ASSERT_EQ(sink.stream(), data);
@@ -141,7 +145,7 @@
data.resize(options.block_size, '\0');
ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
- ASSERT_TRUE(writer.Finalize());
+ ASSERT_TRUE(writer.Flush());
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
@@ -159,7 +163,7 @@
ASSERT_EQ(op->compression, kCowCompressGz);
ASSERT_EQ(op->data_length, 56); // compressed!
ASSERT_EQ(op->new_block, 50);
- ASSERT_EQ(op->source, 104);
+ ASSERT_EQ(op->source, 106);
ASSERT_TRUE(reader.ReadData(*op, &sink));
ASSERT_EQ(sink.stream(), data);
@@ -178,7 +182,7 @@
data.resize(options.block_size * 2, '\0');
ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
- ASSERT_TRUE(writer.Finalize());
+ ASSERT_TRUE(writer.Flush());
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
@@ -207,9 +211,11 @@
void* GetBuffer(size_t, size_t* actual) override { return StringSink::GetBuffer(1, actual); }
};
-TEST_F(CowTest, HorribleSink) {
+class CompressionTest : public CowTest, public testing::WithParamInterface<const char*> {};
+
+TEST_P(CompressionTest, HorribleSink) {
CowOptions options;
- options.compression = "gz";
+ options.compression = GetParam();
CowWriter writer(options);
ASSERT_TRUE(writer.Initialize(cow_->fd));
@@ -218,7 +224,7 @@
data.resize(options.block_size, '\0');
ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
- ASSERT_TRUE(writer.Finalize());
+ ASSERT_TRUE(writer.Flush());
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
@@ -235,6 +241,90 @@
ASSERT_EQ(sink.stream(), data);
}
+INSTANTIATE_TEST_SUITE_P(CowApi, CompressionTest, testing::Values("none", "gz", "brotli"));
+
+TEST_F(CowTest, GetSize) {
+ CowOptions options;
+ CowWriter writer(options);
+ if (ftruncate(cow_->fd, 0) < 0) {
+ perror("Fails to set temp file size");
+ FAIL();
+ }
+ ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+ std::string data = "This is some data, believe it";
+ data.resize(options.block_size, '\0');
+
+ ASSERT_TRUE(writer.AddCopy(10, 20));
+ ASSERT_TRUE(writer.AddRawBlocks(50, data.data(), data.size()));
+ ASSERT_TRUE(writer.AddZeroBlocks(51, 2));
+ auto size_before = writer.GetCowSize();
+ ASSERT_TRUE(writer.Flush());
+ auto size_after = writer.GetCowSize();
+ ASSERT_EQ(size_before, size_after);
+ struct stat buf;
+
+ if (fstat(cow_->fd, &buf) < 0) {
+ perror("Fails to determine size of cow image written");
+ FAIL();
+ }
+ ASSERT_EQ(buf.st_size, writer.GetCowSize());
+}
+
+TEST_F(CowTest, Append) {
+ CowOptions options;
+ auto writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->Initialize(cow_->fd));
+
+ std::string data = "This is some data, believe it";
+ data.resize(options.block_size, '\0');
+ ASSERT_TRUE(writer->AddRawBlocks(50, data.data(), data.size()));
+ ASSERT_TRUE(writer->Flush());
+
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ writer = std::make_unique<CowWriter>(options);
+ ASSERT_TRUE(writer->Initialize(cow_->fd, CowWriter::OpenMode::APPEND));
+
+ std::string data2 = "More data!";
+ data2.resize(options.block_size, '\0');
+ ASSERT_TRUE(writer->AddRawBlocks(51, data2.data(), data2.size()));
+ ASSERT_TRUE(writer->Flush());
+
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ struct stat buf;
+ ASSERT_EQ(fstat(cow_->fd, &buf), 0);
+ ASSERT_EQ(buf.st_size, writer->GetCowSize());
+
+ // Read back both operations.
+ CowReader reader;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+
+ StringSink sink;
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+
+ ASSERT_FALSE(iter->Done());
+ auto op = &iter->Get();
+ ASSERT_EQ(op->type, kCowReplaceOp);
+ ASSERT_TRUE(reader.ReadData(*op, &sink));
+ ASSERT_EQ(sink.stream(), data);
+
+ iter->Next();
+ sink.Reset();
+
+ ASSERT_FALSE(iter->Done());
+ op = &iter->Get();
+ ASSERT_EQ(op->type, kCowReplaceOp);
+ ASSERT_TRUE(reader.ReadData(*op, &sink));
+ ASSERT_EQ(sink.stream(), data2);
+
+ iter->Next();
+ ASSERT_TRUE(iter->Done());
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_decompress.cpp b/fs_mgr/libsnapshot/cow_decompress.cpp
new file mode 100644
index 0000000..faceafe
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_decompress.cpp
@@ -0,0 +1,264 @@
+//
+// Copyright (C) 2020 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 "cow_decompress.h"
+
+#include <utility>
+
+#include <android-base/logging.h>
+#include <brotli/decode.h>
+#include <zlib.h>
+
+namespace android {
+namespace snapshot {
+
+class NoDecompressor final : public IDecompressor {
+ public:
+ bool Decompress(size_t) override;
+};
+
+bool NoDecompressor::Decompress(size_t) {
+ size_t stream_remaining = stream_->Size();
+ while (stream_remaining) {
+ size_t buffer_size = stream_remaining;
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(sink_->GetBuffer(buffer_size, &buffer_size));
+ if (!buffer) {
+ LOG(ERROR) << "Could not acquire buffer from sink";
+ return false;
+ }
+
+ // Read until we can fill the buffer.
+ uint8_t* buffer_pos = buffer;
+ size_t bytes_to_read = std::min(buffer_size, stream_remaining);
+ while (bytes_to_read) {
+ size_t read;
+ if (!stream_->Read(buffer_pos, bytes_to_read, &read)) {
+ return false;
+ }
+ if (!read) {
+ LOG(ERROR) << "Stream ended prematurely";
+ return false;
+ }
+ if (!sink_->ReturnData(buffer_pos, read)) {
+ LOG(ERROR) << "Could not return buffer to sink";
+ return false;
+ }
+ buffer_pos += read;
+ bytes_to_read -= read;
+ stream_remaining -= read;
+ }
+ }
+ return true;
+}
+
+std::unique_ptr<IDecompressor> IDecompressor::Uncompressed() {
+ return std::unique_ptr<IDecompressor>(new NoDecompressor());
+}
+
+// Read chunks of the COW and incrementally stream them to the decoder.
+class StreamDecompressor : public IDecompressor {
+ public:
+ bool Decompress(size_t output_bytes) override;
+
+ virtual bool Init() = 0;
+ virtual bool DecompressInput(const uint8_t* data, size_t length) = 0;
+ virtual bool Done() = 0;
+
+ protected:
+ bool GetFreshBuffer();
+
+ size_t output_bytes_;
+ size_t stream_remaining_;
+ uint8_t* output_buffer_ = nullptr;
+ size_t output_buffer_remaining_ = 0;
+};
+
+static constexpr size_t kChunkSize = 4096;
+
+bool StreamDecompressor::Decompress(size_t output_bytes) {
+ if (!Init()) {
+ return false;
+ }
+
+ stream_remaining_ = stream_->Size();
+ output_bytes_ = output_bytes;
+
+ uint8_t chunk[kChunkSize];
+ while (stream_remaining_) {
+ size_t read = std::min(stream_remaining_, sizeof(chunk));
+ if (!stream_->Read(chunk, read, &read)) {
+ return false;
+ }
+ if (!read) {
+ LOG(ERROR) << "Stream ended prematurely";
+ return false;
+ }
+ if (!DecompressInput(chunk, read)) {
+ return false;
+ }
+
+ stream_remaining_ -= read;
+
+ if (stream_remaining_ && Done()) {
+ LOG(ERROR) << "Decompressor terminated early";
+ return false;
+ }
+ }
+ if (!Done()) {
+ LOG(ERROR) << "Decompressor expected more bytes";
+ return false;
+ }
+ return true;
+}
+
+bool StreamDecompressor::GetFreshBuffer() {
+ size_t request_size = std::min(output_bytes_, kChunkSize);
+ output_buffer_ =
+ reinterpret_cast<uint8_t*>(sink_->GetBuffer(request_size, &output_buffer_remaining_));
+ if (!output_buffer_) {
+ LOG(ERROR) << "Could not acquire buffer from sink";
+ return false;
+ }
+ return true;
+}
+
+class GzDecompressor final : public StreamDecompressor {
+ public:
+ ~GzDecompressor();
+
+ bool Init() override;
+ bool DecompressInput(const uint8_t* data, size_t length) override;
+ bool Done() override { return ended_; }
+
+ private:
+ z_stream z_ = {};
+ bool ended_ = false;
+};
+
+bool GzDecompressor::Init() {
+ if (int rv = inflateInit(&z_); rv != Z_OK) {
+ LOG(ERROR) << "inflateInit returned error code " << rv;
+ return false;
+ }
+ return true;
+}
+
+GzDecompressor::~GzDecompressor() {
+ inflateEnd(&z_);
+}
+
+bool GzDecompressor::DecompressInput(const uint8_t* data, size_t length) {
+ z_.next_in = reinterpret_cast<Bytef*>(const_cast<uint8_t*>(data));
+ z_.avail_in = length;
+
+ while (z_.avail_in) {
+ // If no more output buffer, grab a new buffer.
+ if (z_.avail_out == 0) {
+ if (!GetFreshBuffer()) {
+ return false;
+ }
+ z_.next_out = reinterpret_cast<Bytef*>(output_buffer_);
+ z_.avail_out = output_buffer_remaining_;
+ }
+
+ // Remember the position of the output buffer so we can call ReturnData.
+ auto avail_out = z_.avail_out;
+
+ // Decompress.
+ int rv = inflate(&z_, Z_NO_FLUSH);
+ if (rv != Z_OK && rv != Z_STREAM_END) {
+ LOG(ERROR) << "inflate returned error code " << rv;
+ return false;
+ }
+
+ size_t returned = avail_out - z_.avail_out;
+ if (!sink_->ReturnData(output_buffer_, returned)) {
+ LOG(ERROR) << "Could not return buffer to sink";
+ return false;
+ }
+ output_buffer_ += returned;
+ output_buffer_remaining_ -= returned;
+
+ if (rv == Z_STREAM_END) {
+ if (z_.avail_in) {
+ LOG(ERROR) << "Gz stream ended prematurely";
+ return false;
+ }
+ ended_ = true;
+ return true;
+ }
+ }
+ return true;
+}
+
+std::unique_ptr<IDecompressor> IDecompressor::Gz() {
+ return std::unique_ptr<IDecompressor>(new GzDecompressor());
+}
+
+class BrotliDecompressor final : public StreamDecompressor {
+ public:
+ ~BrotliDecompressor();
+
+ bool Init() override;
+ bool DecompressInput(const uint8_t* data, size_t length) override;
+ bool Done() override { return BrotliDecoderIsFinished(decoder_); }
+
+ private:
+ BrotliDecoderState* decoder_ = nullptr;
+};
+
+bool BrotliDecompressor::Init() {
+ decoder_ = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
+ return true;
+}
+
+BrotliDecompressor::~BrotliDecompressor() {
+ if (decoder_) {
+ BrotliDecoderDestroyInstance(decoder_);
+ }
+}
+
+bool BrotliDecompressor::DecompressInput(const uint8_t* data, size_t length) {
+ size_t available_in = length;
+ const uint8_t* next_in = data;
+
+ bool needs_more_output = false;
+ while (available_in || needs_more_output) {
+ if (!output_buffer_remaining_ && !GetFreshBuffer()) {
+ return false;
+ }
+
+ auto output_buffer = output_buffer_;
+ auto r = BrotliDecoderDecompressStream(decoder_, &available_in, &next_in,
+ &output_buffer_remaining_, &output_buffer_, nullptr);
+ if (r == BROTLI_DECODER_RESULT_ERROR) {
+ LOG(ERROR) << "brotli decode failed";
+ return false;
+ }
+ if (!sink_->ReturnData(output_buffer, output_buffer_ - output_buffer)) {
+ return false;
+ }
+ needs_more_output = (r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT);
+ }
+ return true;
+}
+
+std::unique_ptr<IDecompressor> IDecompressor::Brotli() {
+ return std::unique_ptr<IDecompressor>(new BrotliDecompressor());
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_decompress.h b/fs_mgr/libsnapshot/cow_decompress.h
new file mode 100644
index 0000000..f485256
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_decompress.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#pragma once
+
+#include <libsnapshot/cow_reader.h>
+
+namespace android {
+namespace snapshot {
+
+class IByteStream {
+ public:
+ virtual ~IByteStream() {}
+
+ // Read up to |length| bytes, storing the number of bytes read in the out-
+ // parameter. If the end of the stream is reached, 0 is returned.
+ virtual bool Read(void* buffer, size_t length, size_t* read) = 0;
+
+ // Size of the stream.
+ virtual size_t Size() const = 0;
+};
+
+class IDecompressor {
+ public:
+ virtual ~IDecompressor() {}
+
+ // Factory methods for decompression methods.
+ static std::unique_ptr<IDecompressor> Uncompressed();
+ static std::unique_ptr<IDecompressor> Gz();
+ static std::unique_ptr<IDecompressor> Brotli();
+
+ // |output_bytes| is the expected total number of bytes to sink.
+ virtual bool Decompress(size_t output_bytes) = 0;
+
+ void set_stream(IByteStream* stream) { stream_ = stream; }
+ void set_sink(IByteSink* sink) { sink_ = sink; }
+
+ protected:
+ IByteStream* stream_ = nullptr;
+ IByteSink* sink_ = nullptr;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/cow_reader.cpp b/fs_mgr/libsnapshot/cow_reader.cpp
index 86565c4..60093ab 100644
--- a/fs_mgr/libsnapshot/cow_reader.cpp
+++ b/fs_mgr/libsnapshot/cow_reader.cpp
@@ -17,22 +17,26 @@
#include <sys/types.h>
#include <unistd.h>
+#include <limits>
+
#include <android-base/file.h>
#include <android-base/logging.h>
#include <libsnapshot/cow_reader.h>
-#include <openssl/sha.h>
#include <zlib.h>
+#include "cow_decompress.h"
namespace android {
namespace snapshot {
CowReader::CowReader() : fd_(-1), header_(), fd_size_(0) {}
-static void SHA256(const void* data, size_t length, uint8_t out[32]) {
+static void SHA256(const void*, size_t, uint8_t[]) {
+#if 0
SHA256_CTX c;
SHA256_Init(&c);
SHA256_Update(&c, data, length);
SHA256_Final(out, &c);
+#endif
}
bool CowReader::Parse(android::base::unique_fd&& fd) {
@@ -69,16 +73,40 @@
return false;
}
+ if (header_.magic != kCowMagicNumber) {
+ LOG(ERROR) << "Header Magic corrupted. Magic: " << header_.magic
+ << "Expected: " << kCowMagicNumber;
+ return false;
+ }
+ if (header_.header_size != sizeof(CowHeader)) {
+ LOG(ERROR) << "Header size unknown, read " << header_.header_size << ", expected "
+ << sizeof(CowHeader);
+ return false;
+ }
+
+ if ((header_.major_version != kCowVersionMajor) ||
+ (header_.minor_version != kCowVersionMinor)) {
+ LOG(ERROR) << "Header version mismatch";
+ LOG(ERROR) << "Major version: " << header_.major_version
+ << "Expected: " << kCowVersionMajor;
+ LOG(ERROR) << "Minor version: " << header_.minor_version
+ << "Expected: " << kCowVersionMinor;
+ return false;
+ }
+
uint8_t header_csum[32];
{
CowHeader tmp = header_;
memset(&tmp.header_checksum, 0, sizeof(tmp.header_checksum));
+ memset(header_csum, 0, sizeof(uint8_t) * 32);
+
SHA256(&tmp, sizeof(tmp), header_csum);
}
if (memcmp(header_csum, header_.header_checksum, sizeof(header_csum)) != 0) {
LOG(ERROR) << "header checksum is invalid";
return false;
}
+
return true;
}
@@ -140,6 +168,8 @@
}
uint8_t csum[32];
+ memset(csum, 0, sizeof(uint8_t) * 32);
+
SHA256(ops_buffer.get(), header_.ops_size, csum);
if (memcmp(csum, header_.ops_checksum, sizeof(csum)) != 0) {
LOG(ERROR) << "ops checksum does not match";
@@ -149,7 +179,7 @@
return std::make_unique<CowOpIter>(std::move(ops_buffer), header_.ops_size);
}
-bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len) {
+bool CowReader::GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read) {
// Validate the offset, taking care to acknowledge possible overflow of offset+len.
if (offset < sizeof(header_) || offset >= header_.ops_offset || len >= fd_size_ ||
offset + len > header_.ops_offset) {
@@ -160,104 +190,66 @@
PLOG(ERROR) << "lseek to read raw bytes failed";
return false;
}
- if (!android::base::ReadFully(fd_, buffer, len)) {
- PLOG(ERROR) << "read raw bytes failed";
+ ssize_t rv = TEMP_FAILURE_RETRY(::read(fd_.get(), buffer, len));
+ if (rv < 0) {
+ PLOG(ERROR) << "read failed";
return false;
}
+ *read = rv;
return true;
}
+class CowDataStream final : public IByteStream {
+ public:
+ CowDataStream(CowReader* reader, uint64_t offset, size_t data_length)
+ : reader_(reader), offset_(offset), data_length_(data_length) {
+ remaining_ = data_length_;
+ }
+
+ bool Read(void* buffer, size_t length, size_t* read) override {
+ size_t to_read = std::min(length, remaining_);
+ if (!to_read) {
+ *read = 0;
+ return true;
+ }
+ if (!reader_->GetRawBytes(offset_, buffer, to_read, read)) {
+ return false;
+ }
+ offset_ += *read;
+ remaining_ -= *read;
+ return true;
+ }
+
+ size_t Size() const override { return data_length_; }
+
+ private:
+ CowReader* reader_;
+ uint64_t offset_;
+ size_t data_length_;
+ size_t remaining_;
+};
+
bool CowReader::ReadData(const CowOperation& op, IByteSink* sink) {
- uint64_t offset = op.source;
-
+ std::unique_ptr<IDecompressor> decompressor;
switch (op.compression) {
- case kCowCompressNone: {
- size_t remaining = op.data_length;
- while (remaining) {
- size_t amount = remaining;
- void* buffer = sink->GetBuffer(amount, &amount);
- if (!buffer) {
- LOG(ERROR) << "Could not acquire buffer from sink";
- return false;
- }
- if (!GetRawBytes(offset, buffer, amount)) {
- return false;
- }
- if (!sink->ReturnData(buffer, amount)) {
- LOG(ERROR) << "Could not return buffer to sink";
- return false;
- }
- remaining -= amount;
- offset += amount;
- }
- return true;
- }
- case kCowCompressGz: {
- auto input = std::make_unique<Bytef[]>(op.data_length);
- if (!GetRawBytes(offset, input.get(), op.data_length)) {
- return false;
- }
-
- z_stream z = {};
- z.next_in = input.get();
- z.avail_in = op.data_length;
- if (int rv = inflateInit(&z); rv != Z_OK) {
- LOG(ERROR) << "inflateInit returned error code " << rv;
- return false;
- }
-
- while (z.total_out < header_.block_size) {
- // If no more output buffer, grab a new buffer.
- if (z.avail_out == 0) {
- size_t amount = header_.block_size - z.total_out;
- z.next_out = reinterpret_cast<Bytef*>(sink->GetBuffer(amount, &amount));
- if (!z.next_out) {
- LOG(ERROR) << "Could not acquire buffer from sink";
- return false;
- }
- z.avail_out = amount;
- }
-
- // Remember the position of the output buffer so we can call ReturnData.
- auto buffer = z.next_out;
- auto avail_out = z.avail_out;
-
- // Decompress.
- int rv = inflate(&z, Z_NO_FLUSH);
- if (rv != Z_OK && rv != Z_STREAM_END) {
- LOG(ERROR) << "inflate returned error code " << rv;
- return false;
- }
-
- // Return the section of the buffer that was updated.
- if (z.avail_out < avail_out && !sink->ReturnData(buffer, avail_out - z.avail_out)) {
- LOG(ERROR) << "Could not return buffer to sink";
- return false;
- }
-
- if (rv == Z_STREAM_END) {
- // Error if the stream has ended, but we didn't fill the entire block.
- if (z.total_out != header_.block_size) {
- LOG(ERROR) << "Reached gz stream end but did not read a full block of data";
- return false;
- }
- break;
- }
-
- CHECK(rv == Z_OK);
-
- // Error if the stream is expecting more data, but we don't have any to read.
- if (z.avail_in == 0) {
- LOG(ERROR) << "Gz stream ended prematurely";
- return false;
- }
- }
- return true;
- }
+ case kCowCompressNone:
+ decompressor = IDecompressor::Uncompressed();
+ break;
+ case kCowCompressGz:
+ decompressor = IDecompressor::Gz();
+ break;
+ case kCowCompressBrotli:
+ decompressor = IDecompressor::Brotli();
+ break;
default:
LOG(ERROR) << "Unknown compression type: " << op.compression;
return false;
}
+
+ CowDataStream stream(this, op.source, op.data_length);
+ decompressor->set_stream(&stream);
+ decompressor->set_sink(sink);
+ return decompressor->Decompress(header_.block_size);
}
} // namespace snapshot
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
new file mode 100644
index 0000000..1d6c104
--- /dev/null
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -0,0 +1,506 @@
+// 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 <linux/fs.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <chrono>
+#include <iostream>
+#include <memory>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <libdm/loop_control.h>
+#include <libsnapshot/cow_writer.h>
+#include <libsnapshot/snapuserd_client.h>
+#include <storage_literals/storage_literals.h>
+
+namespace android {
+namespace snapshot {
+
+using namespace android::storage_literals;
+using android::base::unique_fd;
+using LoopDevice = android::dm::LoopDevice;
+using namespace std::chrono_literals;
+
+class SnapuserdTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ cow_system_ = std::make_unique<TemporaryFile>();
+ ASSERT_GE(cow_system_->fd, 0) << strerror(errno);
+
+ cow_product_ = std::make_unique<TemporaryFile>();
+ ASSERT_GE(cow_product_->fd, 0) << strerror(errno);
+
+ cow_system_1_ = std::make_unique<TemporaryFile>();
+ ASSERT_GE(cow_system_1_->fd, 0) << strerror(errno);
+
+ cow_product_1_ = std::make_unique<TemporaryFile>();
+ ASSERT_GE(cow_product_1_->fd, 0) << strerror(errno);
+
+ // Create temp files in the PWD as selinux
+ // allows kernel domin to read from that directory only
+ // on userdebug/eng builds. Creating files under /data/local/tmp
+ // will have selinux denials.
+ std::string path = android::base::GetExecutableDirectory();
+
+ system_a_ = std::make_unique<TemporaryFile>(path);
+ ASSERT_GE(system_a_->fd, 0) << strerror(errno);
+
+ product_a_ = std::make_unique<TemporaryFile>(path);
+ ASSERT_GE(product_a_->fd, 0) << strerror(errno);
+
+ size_ = 100_MiB;
+ }
+
+ void TearDown() override {
+ cow_system_ = nullptr;
+ cow_product_ = nullptr;
+
+ cow_system_1_ = nullptr;
+ cow_product_1_ = nullptr;
+ }
+
+ std::unique_ptr<TemporaryFile> system_a_;
+ std::unique_ptr<TemporaryFile> product_a_;
+
+ std::unique_ptr<LoopDevice> system_a_loop_;
+ std::unique_ptr<LoopDevice> product_a_loop_;
+
+ std::unique_ptr<TemporaryFile> cow_system_;
+ std::unique_ptr<TemporaryFile> cow_product_;
+
+ std::unique_ptr<TemporaryFile> cow_system_1_;
+ std::unique_ptr<TemporaryFile> cow_product_1_;
+
+ unique_fd sys_fd_;
+ unique_fd product_fd_;
+ size_t size_;
+
+ int system_blksize_;
+ int product_blksize_;
+ std::string system_device_name_;
+ std::string product_device_name_;
+
+ std::string system_device_ctrl_name_;
+ std::string product_device_ctrl_name_;
+
+ std::unique_ptr<uint8_t[]> random_buffer_1_;
+ std::unique_ptr<uint8_t[]> random_buffer_2_;
+ std::unique_ptr<uint8_t[]> zero_buffer_;
+ std::unique_ptr<uint8_t[]> system_buffer_;
+ std::unique_ptr<uint8_t[]> product_buffer_;
+
+ void Init();
+ void CreateCowDevice(std::unique_ptr<TemporaryFile>& cow);
+ void CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow);
+ void CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow);
+ void DeleteDmUser(std::unique_ptr<TemporaryFile>& cow, std::string snapshot_device);
+ void StartSnapuserdDaemon();
+ void CreateSnapshotDevices();
+ void SwitchSnapshotDevices();
+
+ std::string GetSystemControlPath() {
+ return std::string("/dev/dm-user-") + system_device_ctrl_name_;
+ }
+ std::string GetProductControlPath() {
+ return std::string("/dev/dm-user-") + product_device_ctrl_name_;
+ }
+
+ void TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>& buffer);
+ SnapuserdClient client_;
+};
+
+void SnapuserdTest::Init() {
+ unique_fd rnd_fd;
+ loff_t offset = 0;
+ std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
+
+ rnd_fd.reset(open("/dev/random", O_RDONLY));
+ ASSERT_TRUE(rnd_fd > 0);
+
+ random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
+ random_buffer_2_ = std::make_unique<uint8_t[]>(size_);
+ system_buffer_ = std::make_unique<uint8_t[]>(size_);
+ product_buffer_ = std::make_unique<uint8_t[]>(size_);
+ zero_buffer_ = std::make_unique<uint8_t[]>(size_);
+
+ // Fill random data
+ for (size_t j = 0; j < (size_ / 1_MiB); j++) {
+ ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
+ true);
+
+ ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_2_.get() + offset, 1_MiB, 0),
+ true);
+
+ offset += 1_MiB;
+ }
+
+ for (size_t j = 0; j < (800_MiB / 1_MiB); j++) {
+ ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
+ ASSERT_EQ(android::base::WriteFully(system_a_->fd, random_buffer.get(), 1_MiB), true);
+ }
+
+ for (size_t j = 0; j < (800_MiB / 1_MiB); j++) {
+ ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
+ ASSERT_EQ(android::base::WriteFully(product_a_->fd, random_buffer.get(), 1_MiB), true);
+ }
+
+ // Create loopback devices
+ system_a_loop_ = std::make_unique<LoopDevice>(std::string(system_a_->path), 10s);
+ ASSERT_TRUE(system_a_loop_->valid());
+
+ product_a_loop_ = std::make_unique<LoopDevice>(std::string(product_a_->path), 10s);
+ ASSERT_TRUE(product_a_loop_->valid());
+
+ sys_fd_.reset(open(system_a_loop_->device().c_str(), O_RDONLY));
+ ASSERT_TRUE(sys_fd_ > 0);
+
+ product_fd_.reset(open(product_a_loop_->device().c_str(), O_RDONLY));
+ ASSERT_TRUE(product_fd_ > 0);
+
+ // Read from system partition from offset 0 of size 100MB
+ ASSERT_EQ(ReadFullyAtOffset(sys_fd_, system_buffer_.get(), size_, 0), true);
+
+ // Read from product partition from offset 0 of size 100MB
+ ASSERT_EQ(ReadFullyAtOffset(product_fd_, product_buffer_.get(), size_, 0), true);
+}
+
+void SnapuserdTest::CreateCowDevice(std::unique_ptr<TemporaryFile>& cow) {
+ //================Create a COW file with the following operations===========
+ //
+ // Create COW file which is gz compressed
+ //
+ // 0-100 MB of replace operation with random data
+ // 100-200 MB of copy operation
+ // 200-300 MB of zero operation
+ // 300-400 MB of replace operation with random data
+
+ CowOptions options;
+ options.compression = "gz";
+ CowWriter writer(options);
+
+ ASSERT_TRUE(writer.Initialize(cow->fd));
+
+ // Write 100MB random data to COW file which is gz compressed from block 0
+ ASSERT_TRUE(writer.AddRawBlocks(0, random_buffer_1_.get(), size_));
+
+ size_t num_blocks = size_ / options.block_size;
+ size_t blk_start_copy = num_blocks;
+ size_t blk_end_copy = blk_start_copy + num_blocks;
+ size_t source_blk = 0;
+
+ // Copy blocks - source_blk starts from 0 as snapuserd
+ // has to read from block 0 in system_a partition
+ //
+ // This initializes copy operation from block 0 of size 100 MB from
+ // /dev/block/mapper/system_a or product_a
+ for (size_t i = blk_start_copy; i < blk_end_copy; i++) {
+ ASSERT_TRUE(writer.AddCopy(i, source_blk));
+ source_blk += 1;
+ }
+
+ size_t blk_zero_copy_start = blk_end_copy;
+ size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks;
+
+ // 100 MB filled with zeroes
+ ASSERT_TRUE(writer.AddZeroBlocks(blk_zero_copy_start, num_blocks));
+
+ // Final 100MB filled with random data which is gz compressed
+ size_t blk_random2_replace_start = blk_zero_copy_end;
+
+ ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_2_.get(), size_));
+
+ // Flush operations
+ ASSERT_TRUE(writer.Flush());
+
+ ASSERT_EQ(lseek(cow->fd, 0, SEEK_SET), 0);
+}
+
+void SnapuserdTest::CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow) {
+ std::string cmd;
+ system_device_name_.clear();
+ system_device_ctrl_name_.clear();
+
+ // Create a COW device. Number of sectors is chosen random which can
+ // hold at least 400MB of data
+
+ int err = ioctl(sys_fd_.get(), BLKGETSIZE, &system_blksize_);
+ ASSERT_GE(err, 0);
+
+ std::string str(cow->path);
+ std::size_t found = str.find_last_of("/\\");
+ ASSERT_NE(found, std::string::npos);
+ system_device_name_ = str.substr(found + 1);
+
+ // Create a control device
+ system_device_ctrl_name_ = system_device_name_ + "-ctrl";
+ cmd = "dmctl create " + system_device_name_ + " user 0 " + std::to_string(system_blksize_);
+ cmd += " " + system_device_ctrl_name_;
+
+ system(cmd.c_str());
+}
+
+void SnapuserdTest::DeleteDmUser(std::unique_ptr<TemporaryFile>& cow, std::string snapshot_device) {
+ std::string cmd;
+
+ cmd = "dmctl delete " + snapshot_device;
+ system(cmd.c_str());
+
+ cmd.clear();
+
+ std::string str(cow->path);
+ std::size_t found = str.find_last_of("/\\");
+ ASSERT_NE(found, std::string::npos);
+ std::string device_name = str.substr(found + 1);
+
+ cmd = "dmctl delete " + device_name;
+
+ system(cmd.c_str());
+}
+
+void SnapuserdTest::CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow) {
+ std::string cmd;
+ product_device_name_.clear();
+ product_device_ctrl_name_.clear();
+
+ // Create a COW device. Number of sectors is chosen random which can
+ // hold at least 400MB of data
+
+ int err = ioctl(product_fd_.get(), BLKGETSIZE, &product_blksize_);
+ ASSERT_GE(err, 0);
+
+ std::string str(cow->path);
+ std::size_t found = str.find_last_of("/\\");
+ ASSERT_NE(found, std::string::npos);
+ product_device_name_ = str.substr(found + 1);
+ product_device_ctrl_name_ = product_device_name_ + "-ctrl";
+ cmd = "dmctl create " + product_device_name_ + " user 0 " + std::to_string(product_blksize_);
+ cmd += " " + product_device_ctrl_name_;
+
+ system(cmd.c_str());
+}
+
+void SnapuserdTest::StartSnapuserdDaemon() {
+ int ret;
+
+ ret = client_.StartSnapuserd();
+ ASSERT_EQ(ret, 0);
+
+ ret = client_.InitializeSnapuserd(cow_system_->path, system_a_loop_->device(),
+ GetSystemControlPath());
+ ASSERT_EQ(ret, 0);
+
+ ret = client_.InitializeSnapuserd(cow_product_->path, product_a_loop_->device(),
+ GetProductControlPath());
+ ASSERT_EQ(ret, 0);
+}
+
+void SnapuserdTest::CreateSnapshotDevices() {
+ std::string cmd;
+
+ cmd = "dmctl create system-snapshot -ro snapshot 0 " + std::to_string(system_blksize_);
+ cmd += " " + system_a_loop_->device();
+ cmd += " /dev/block/mapper/" + system_device_name_;
+ cmd += " P 8";
+
+ system(cmd.c_str());
+
+ cmd.clear();
+
+ cmd = "dmctl create product-snapshot -ro snapshot 0 " + std::to_string(product_blksize_);
+ cmd += " " + product_a_loop_->device();
+ cmd += " /dev/block/mapper/" + product_device_name_;
+ cmd += " P 8";
+
+ system(cmd.c_str());
+}
+
+void SnapuserdTest::SwitchSnapshotDevices() {
+ std::string cmd;
+
+ cmd = "dmctl create system-snapshot-1 -ro snapshot 0 " + std::to_string(system_blksize_);
+ cmd += " " + system_a_loop_->device();
+ cmd += " /dev/block/mapper/" + system_device_name_;
+ cmd += " P 8";
+
+ system(cmd.c_str());
+
+ cmd.clear();
+
+ cmd = "dmctl create product-snapshot-1 -ro snapshot 0 " + std::to_string(product_blksize_);
+ cmd += " " + product_a_loop_->device();
+ cmd += " /dev/block/mapper/" + product_device_name_;
+ cmd += " P 8";
+
+ system(cmd.c_str());
+}
+
+void SnapuserdTest::TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>& buffer) {
+ loff_t offset = 0;
+ // std::unique_ptr<uint8_t[]> buffer = std::move(buf);
+
+ std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
+
+ //================Start IO operation on dm-snapshot device=================
+ // This will test the following paths:
+ //
+ // 1: IO path for all three operations and interleaving of operations.
+ // 2: Merging of blocks in kernel during metadata read
+ // 3: Bulk IO issued by kernel duing merge operation
+
+ // Read from snapshot device of size 100MB from offset 0. This tests the
+ // 1st replace operation.
+ //
+ // IO path:
+ //
+ // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_compressed_cow (replace
+ // op)->decompress_cow->return
+
+ ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+ // Update the offset
+ offset += size_;
+
+ // Compare data with random_buffer_1_.
+ ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_1_.get(), size_), 0);
+
+ // Clear the buffer
+ memset(snapuserd_buffer.get(), 0, size_);
+
+ // Read from snapshot device of size 100MB from offset 100MB. This tests the
+ // copy operation.
+ //
+ // IO path:
+ //
+ // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_from_(system_a/product_a) partition
+ // (copy op) -> return
+ ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+ // Update the offset
+ offset += size_;
+
+ // Compare data with buffer.
+ ASSERT_EQ(memcmp(snapuserd_buffer.get(), buffer.get(), size_), 0);
+
+ // Read from snapshot device of size 100MB from offset 200MB. This tests the
+ // zero operation.
+ //
+ // IO path:
+ //
+ // dm-snap->dm-snap-persistent->dm-user->snapuserd->fill_memory_with_zero
+ // (zero op) -> return
+ ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+ // Compare data with zero filled buffer
+ ASSERT_EQ(memcmp(snapuserd_buffer.get(), zero_buffer_.get(), size_), 0);
+
+ // Update the offset
+ offset += size_;
+
+ // Read from snapshot device of size 100MB from offset 300MB. This tests the
+ // final replace operation.
+ //
+ // IO path:
+ //
+ // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_compressed_cow (replace
+ // op)->decompress_cow->return
+ ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
+
+ // Compare data with random_buffer_2_.
+ ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_2_.get(), size_), 0);
+}
+
+TEST_F(SnapuserdTest, ReadWrite) {
+ unique_fd snapshot_fd;
+
+ Init();
+
+ CreateCowDevice(cow_system_);
+ CreateCowDevice(cow_product_);
+
+ CreateSystemDmUser(cow_system_);
+ CreateProductDmUser(cow_product_);
+
+ StartSnapuserdDaemon();
+
+ CreateSnapshotDevices();
+
+ snapshot_fd.reset(open("/dev/block/mapper/system-snapshot", O_RDONLY));
+ ASSERT_TRUE(snapshot_fd > 0);
+ TestIO(snapshot_fd, system_buffer_);
+
+ snapshot_fd.reset(open("/dev/block/mapper/product-snapshot", O_RDONLY));
+ ASSERT_TRUE(snapshot_fd > 0);
+ TestIO(snapshot_fd, product_buffer_);
+
+ snapshot_fd.reset(-1);
+
+ // Sequence of operations for transition
+ CreateCowDevice(cow_system_1_);
+ CreateCowDevice(cow_product_1_);
+
+ // Create dm-user which creates new control devices
+ CreateSystemDmUser(cow_system_1_);
+ CreateProductDmUser(cow_product_1_);
+
+ // Send the path information to second stage daemon through vector
+ std::vector<std::vector<std::string>> vec{
+ {cow_system_1_->path, system_a_loop_->device(), GetSystemControlPath()},
+ {cow_product_1_->path, product_a_loop_->device(), GetProductControlPath()}};
+
+ // Start the second stage deamon and send the devices information through
+ // vector.
+ ASSERT_EQ(client_.RestartSnapuserd(vec), 0);
+
+ // TODO: This is not switching snapshot device but creates a new table;
+ // Second stage daemon will be ready to serve the IO request. From now
+ // onwards, we can go ahead and shutdown the first stage daemon
+ SwitchSnapshotDevices();
+
+ DeleteDmUser(cow_system_, "system-snapshot");
+ DeleteDmUser(cow_product_, "product-snapshot");
+
+ // Stop the first stage daemon
+ ASSERT_EQ(client_.StopSnapuserd(true), 0);
+
+ // Test the IO again with the second stage daemon
+ snapshot_fd.reset(open("/dev/block/mapper/system-snapshot-1", O_RDONLY));
+ ASSERT_TRUE(snapshot_fd > 0);
+ TestIO(snapshot_fd, system_buffer_);
+
+ snapshot_fd.reset(open("/dev/block/mapper/product-snapshot-1", O_RDONLY));
+ ASSERT_TRUE(snapshot_fd > 0);
+ TestIO(snapshot_fd, product_buffer_);
+
+ snapshot_fd.reset(-1);
+
+ DeleteDmUser(cow_system_1_, "system-snapshot-1");
+ DeleteDmUser(cow_product_1_, "product-snapshot-1");
+
+ // Stop the second stage daemon
+ ASSERT_EQ(client_.StopSnapuserd(false), 0);
+}
+
+} // namespace snapshot
+} // namespace android
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/fs_mgr/libsnapshot/cow_writer.cpp b/fs_mgr/libsnapshot/cow_writer.cpp
index ea8e534..f96f174 100644
--- a/fs_mgr/libsnapshot/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/cow_writer.cpp
@@ -21,8 +21,10 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <brotli/encode.h>
+#include <libsnapshot/cow_reader.h>
#include <libsnapshot/cow_writer.h>
-#include <openssl/sha.h>
#include <zlib.h>
namespace android {
@@ -30,6 +32,48 @@
static_assert(sizeof(off_t) == sizeof(uint64_t));
+using android::base::borrowed_fd;
+using android::base::unique_fd;
+
+bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
+ if (!ValidateNewBlock(new_block)) {
+ return false;
+ }
+ return EmitCopy(new_block, old_block);
+}
+
+bool ICowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
+ if (size % options_.block_size != 0) {
+ LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of "
+ << options_.block_size;
+ return false;
+ }
+
+ uint64_t num_blocks = size / options_.block_size;
+ uint64_t last_block = new_block_start + num_blocks - 1;
+ if (!ValidateNewBlock(last_block)) {
+ return false;
+ }
+ return EmitRawBlocks(new_block_start, data, size);
+}
+
+bool ICowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
+ uint64_t last_block = new_block_start + num_blocks - 1;
+ if (!ValidateNewBlock(last_block)) {
+ return false;
+ }
+ return EmitZeroBlocks(new_block_start, num_blocks);
+}
+
+bool ICowWriter::ValidateNewBlock(uint64_t new_block) {
+ if (options_.max_blocks && new_block >= options_.max_blocks.value()) {
+ LOG(ERROR) << "New block " << new_block << " exceeds maximum block count "
+ << options_.max_blocks.value();
+ return false;
+ }
+ return true;
+}
+
CowWriter::CowWriter(const CowOptions& options) : ICowWriter(options), fd_(-1) {
SetupHeaders();
}
@@ -39,17 +83,48 @@
header_.magic = kCowMagicNumber;
header_.major_version = kCowVersionMajor;
header_.minor_version = kCowVersionMinor;
+ header_.header_size = sizeof(CowHeader);
header_.block_size = options_.block_size;
}
-bool CowWriter::Initialize(android::base::unique_fd&& fd) {
- owned_fd_ = std::move(fd);
- return Initialize(android::base::borrowed_fd{owned_fd_});
+bool CowWriter::ParseOptions() {
+ if (options_.compression == "gz") {
+ compression_ = kCowCompressGz;
+ } else if (options_.compression == "brotli") {
+ compression_ = kCowCompressBrotli;
+ } else if (options_.compression == "none") {
+ compression_ = kCowCompressNone;
+ } else if (!options_.compression.empty()) {
+ LOG(ERROR) << "unrecognized compression: " << options_.compression;
+ return false;
+ }
+ return true;
}
-bool CowWriter::Initialize(android::base::borrowed_fd fd) {
+bool CowWriter::Initialize(unique_fd&& fd, OpenMode mode) {
+ owned_fd_ = std::move(fd);
+ return Initialize(borrowed_fd{owned_fd_}, mode);
+}
+
+bool CowWriter::Initialize(borrowed_fd fd, OpenMode mode) {
fd_ = fd;
+ if (!ParseOptions()) {
+ return false;
+ }
+
+ switch (mode) {
+ case OpenMode::WRITE:
+ return OpenForWrite();
+ case OpenMode::APPEND:
+ return OpenForAppend();
+ default:
+ LOG(ERROR) << "Unknown open mode in CowWriter";
+ return false;
+ }
+}
+
+bool CowWriter::OpenForWrite() {
// This limitation is tied to the data field size in CowOperation.
if (header_.block_size > std::numeric_limits<uint16_t>::max()) {
LOG(ERROR) << "Block size is too large";
@@ -61,41 +136,56 @@
return false;
}
- if (options_.compression == "gz") {
- compression_ = kCowCompressGz;
- } else if (!options_.compression.empty()) {
- LOG(ERROR) << "unrecognized compression: " << options_.compression;
- return false;
- }
-
// Headers are not complete, but this ensures the file is at the right
// position.
if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) {
PLOG(ERROR) << "write failed";
return false;
}
+
+ header_.ops_offset = header_.header_size;
return true;
}
-bool CowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
- header_.num_ops++;
+bool CowWriter::OpenForAppend() {
+ auto reader = std::make_unique<CowReader>();
+ if (!reader->Parse(fd_) || !reader->GetHeader(&header_)) {
+ return false;
+ }
+ options_.block_size = header_.block_size;
+ // Reset this, since we're going to reimport all operations.
+ header_.num_ops = 0;
+
+ auto iter = reader->GetOpIter();
+ while (!iter->Done()) {
+ auto& op = iter->Get();
+ AddOperation(op);
+
+ iter->Next();
+ }
+
+ // Free reader so we own the descriptor position again.
+ reader = nullptr;
+
+ // Seek to the end of the data section.
+ if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+ PLOG(ERROR) << "lseek failed";
+ return false;
+ }
+ return true;
+}
+
+bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
CowOperation op = {};
op.type = kCowCopyOp;
op.new_block = new_block;
op.source = old_block;
- ops_ += std::basic_string<uint8_t>(reinterpret_cast<uint8_t*>(&op), sizeof(op));
-
+ AddOperation(op);
return true;
}
-bool CowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
- if (size % header_.block_size != 0) {
- LOG(ERROR) << "AddRawBlocks: size " << size << " is not a multiple of "
- << header_.block_size;
- return false;
- }
-
+bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
uint64_t pos;
if (!GetDataPos(&pos)) {
return false;
@@ -103,8 +193,6 @@
const uint8_t* iter = reinterpret_cast<const uint8_t*>(data);
for (size_t i = 0; i < size / header_.block_size; i++) {
- header_.num_ops++;
-
CowOperation op = {};
op.type = kCowReplaceOp;
op.new_block = new_block_start + i;
@@ -120,7 +208,7 @@
LOG(ERROR) << "Compressed block is too large: " << data.size() << " bytes";
return false;
}
- if (!android::base::WriteFully(fd_, data.data(), data.size())) {
+ if (!WriteRawData(data.data(), data.size())) {
PLOG(ERROR) << "AddRawBlocks: write failed";
return false;
}
@@ -132,26 +220,24 @@
pos += header_.block_size;
}
- ops_ += std::basic_string<uint8_t>(reinterpret_cast<uint8_t*>(&op), sizeof(op));
+ AddOperation(op);
iter += header_.block_size;
}
- if (!compression_ && !android::base::WriteFully(fd_, data, size)) {
+ if (!compression_ && !WriteRawData(data, size)) {
PLOG(ERROR) << "AddRawBlocks: write failed";
return false;
}
return true;
}
-bool CowWriter::AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
+bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
for (uint64_t i = 0; i < num_blocks; i++) {
- header_.num_ops++;
-
CowOperation op = {};
op.type = kCowZeroOp;
op.new_block = new_block_start + i;
op.source = 0;
- ops_ += std::basic_string<uint8_t>(reinterpret_cast<uint8_t*>(&op), sizeof(op));
+ AddOperation(op);
}
return true;
}
@@ -171,6 +257,24 @@
}
return std::basic_string<uint8_t>(buffer.get(), dest_len);
}
+ case kCowCompressBrotli: {
+ auto bound = BrotliEncoderMaxCompressedSize(length);
+ if (!bound) {
+ LOG(ERROR) << "BrotliEncoderMaxCompressedSize returned 0";
+ return {};
+ }
+ auto buffer = std::make_unique<uint8_t[]>(bound);
+
+ size_t encoded_size = bound;
+ auto rv = BrotliEncoderCompress(
+ BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW, BROTLI_DEFAULT_MODE, length,
+ reinterpret_cast<const uint8_t*>(data), &encoded_size, buffer.get());
+ if (!rv) {
+ LOG(ERROR) << "BrotliEncoderCompress failed";
+ return {};
+ }
+ return std::basic_string<uint8_t>(buffer.get(), encoded_size);
+ }
default:
LOG(ERROR) << "unhandled compression type: " << compression_;
break;
@@ -178,27 +282,28 @@
return {};
}
-static void SHA256(const void* data, size_t length, uint8_t out[32]) {
+// TODO: Fix compilation issues when linking libcrypto library
+// when snapuserd is compiled as part of ramdisk.
+static void SHA256(const void*, size_t, uint8_t[]) {
+#if 0
SHA256_CTX c;
SHA256_Init(&c);
SHA256_Update(&c, data, length);
SHA256_Final(out, &c);
+#endif
}
-bool CowWriter::Finalize() {
- auto offs = lseek(fd_.get(), 0, SEEK_CUR);
- if (offs < 0) {
- PLOG(ERROR) << "lseek failed";
- return false;
- }
- header_.ops_offset = offs;
+bool CowWriter::Flush() {
header_.ops_size = ops_.size();
+ memset(header_.ops_checksum, 0, sizeof(uint8_t) * 32);
+ memset(header_.header_checksum, 0, sizeof(uint8_t) * 32);
+
SHA256(ops_.data(), ops_.size(), header_.ops_checksum);
SHA256(&header_, sizeof(header_), header_.header_checksum);
- if (lseek(fd_.get(), 0, SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek start failed";
+ if (lseek(fd_.get(), 0, SEEK_SET)) {
+ PLOG(ERROR) << "lseek failed";
return false;
}
if (!android::base::WriteFully(fd_, &header_, sizeof(header_))) {
@@ -209,13 +314,23 @@
PLOG(ERROR) << "lseek ops failed";
return false;
}
- if (!android::base::WriteFully(fd_, ops_.data(), ops_.size())) {
+ if (!WriteFully(fd_, ops_.data(), ops_.size())) {
PLOG(ERROR) << "write ops failed";
return false;
}
+
+ // Re-position for any subsequent writes.
+ if (lseek(fd_.get(), header_.ops_offset, SEEK_SET) < 0) {
+ PLOG(ERROR) << "lseek ops failed";
+ return false;
+ }
return true;
}
+uint64_t CowWriter::GetCowSize() {
+ return header_.ops_offset + header_.num_ops * sizeof(CowOperation);
+}
+
bool CowWriter::GetDataPos(uint64_t* pos) {
off_t offs = lseek(fd_.get(), 0, SEEK_CUR);
if (offs < 0) {
@@ -226,5 +341,18 @@
return true;
}
+void CowWriter::AddOperation(const CowOperation& op) {
+ header_.num_ops++;
+ ops_.insert(ops_.size(), reinterpret_cast<const uint8_t*>(&op), sizeof(op));
+}
+
+bool CowWriter::WriteRawData(const void* data, size_t size) {
+ if (!android::base::WriteFully(fd_, data, size)) {
+ return false;
+ }
+ header_.ops_offset += size;
+ return true;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp b/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
new file mode 100644
index 0000000..2a0136b
--- /dev/null
+++ b/fs_mgr/libsnapshot/estimate_cow_from_nonab_ota.cpp
@@ -0,0 +1,432 @@
+//
+// Copyright (C) 2020 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 <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <gflags/gflags.h>
+#include <libsnapshot/cow_writer.h>
+#include <openssl/sha.h>
+#include <sparse/sparse.h>
+#include <ziparchive/zip_archive.h>
+
+DEFINE_string(source_tf, "", "Source target files (dir or zip file)");
+DEFINE_string(ota_tf, "", "Target files of the build for an OTA");
+DEFINE_string(compression, "gz", "Compression (options: none, gz, brotli)");
+
+namespace android {
+namespace snapshot {
+
+using android::base::borrowed_fd;
+using android::base::unique_fd;
+
+static constexpr size_t kBlockSize = 4096;
+
+void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
+ unsigned int, const char* message) {
+ if (severity == android::base::ERROR) {
+ fprintf(stderr, "%s\n", message);
+ } else {
+ fprintf(stdout, "%s\n", message);
+ }
+}
+
+class TargetFilesPackage final {
+ public:
+ explicit TargetFilesPackage(const std::string& path);
+
+ bool Open();
+ bool HasFile(const std::string& path);
+ std::unordered_set<std::string> GetDynamicPartitionNames();
+ unique_fd OpenFile(const std::string& path);
+ unique_fd OpenImage(const std::string& path);
+
+ private:
+ std::string path_;
+ unique_fd fd_;
+ std::unique_ptr<ZipArchive, decltype(&CloseArchive)> zip_;
+};
+
+TargetFilesPackage::TargetFilesPackage(const std::string& path)
+ : path_(path), zip_(nullptr, &CloseArchive) {}
+
+bool TargetFilesPackage::Open() {
+ fd_.reset(open(path_.c_str(), O_RDONLY));
+ if (fd_ < 0) {
+ PLOG(ERROR) << "open failed: " << path_;
+ return false;
+ }
+
+ struct stat s;
+ if (fstat(fd_.get(), &s) < 0) {
+ PLOG(ERROR) << "fstat failed: " << path_;
+ return false;
+ }
+ if (S_ISDIR(s.st_mode)) {
+ return true;
+ }
+
+ // Otherwise, assume it's a zip file.
+ ZipArchiveHandle handle;
+ if (OpenArchiveFd(fd_.get(), path_.c_str(), &handle, false)) {
+ LOG(ERROR) << "Could not open " << path_ << " as a zip archive.";
+ return false;
+ }
+ zip_.reset(handle);
+ return true;
+}
+
+bool TargetFilesPackage::HasFile(const std::string& path) {
+ if (zip_) {
+ ZipEntry64 entry;
+ return !FindEntry(zip_.get(), path, &entry);
+ }
+
+ auto full_path = path_ + "/" + path;
+ return access(full_path.c_str(), F_OK) == 0;
+}
+
+unique_fd TargetFilesPackage::OpenFile(const std::string& path) {
+ if (!zip_) {
+ auto full_path = path_ + "/" + path;
+ unique_fd fd(open(full_path.c_str(), O_RDONLY));
+ if (fd < 0) {
+ PLOG(ERROR) << "open failed: " << full_path;
+ return {};
+ }
+ return fd;
+ }
+
+ ZipEntry64 entry;
+ if (FindEntry(zip_.get(), path, &entry)) {
+ LOG(ERROR) << path << " not found in archive: " << path_;
+ return {};
+ }
+
+ TemporaryFile temp;
+ if (temp.fd < 0) {
+ PLOG(ERROR) << "mkstemp failed";
+ return {};
+ }
+
+ LOG(INFO) << "Extracting " << path << " from " << path_ << " ...";
+ if (ExtractEntryToFile(zip_.get(), &entry, temp.fd)) {
+ LOG(ERROR) << "could not extract " << path << " from " << path_;
+ return {};
+ }
+ if (lseek(temp.fd, 0, SEEK_SET) < 0) {
+ PLOG(ERROR) << "lseek failed";
+ return {};
+ }
+ return unique_fd{temp.release()};
+}
+
+unique_fd TargetFilesPackage::OpenImage(const std::string& path) {
+ auto fd = OpenFile(path);
+ if (fd < 0) {
+ return {};
+ }
+
+ LOG(INFO) << "Unsparsing " << path << " ...";
+ std::unique_ptr<struct sparse_file, decltype(&sparse_file_destroy)> s(
+ sparse_file_import(fd.get(), false, false), &sparse_file_destroy);
+ if (!s) {
+ return fd;
+ }
+
+ TemporaryFile temp;
+ if (temp.fd < 0) {
+ PLOG(ERROR) << "mkstemp failed";
+ return {};
+ }
+ if (sparse_file_write(s.get(), temp.fd, false, false, false) < 0) {
+ LOG(ERROR) << "sparse_file_write failed";
+ return {};
+ }
+ if (lseek(temp.fd, 0, SEEK_SET) < 0) {
+ PLOG(ERROR) << "lseek failed";
+ return {};
+ }
+
+ fd.reset(temp.release());
+ return fd;
+}
+
+std::unordered_set<std::string> TargetFilesPackage::GetDynamicPartitionNames() {
+ auto fd = OpenFile("META/misc_info.txt");
+ if (fd < 0) {
+ return {};
+ }
+
+ std::string contents;
+ if (!android::base::ReadFdToString(fd, &contents)) {
+ PLOG(ERROR) << "read failed";
+ return {};
+ }
+
+ std::unordered_set<std::string> set;
+
+ auto lines = android::base::Split(contents, "\n");
+ for (const auto& line : lines) {
+ auto parts = android::base::Split(line, "=");
+ if (parts.size() == 2 && parts[0] == "dynamic_partition_list") {
+ auto partitions = android::base::Split(parts[1], " ");
+ for (const auto& name : partitions) {
+ if (!name.empty()) {
+ set.emplace(name);
+ }
+ }
+ break;
+ }
+ }
+ return set;
+}
+
+class NonAbEstimator final {
+ public:
+ NonAbEstimator(const std::string& ota_tf_path, const std::string& source_tf_path)
+ : ota_tf_path_(ota_tf_path), source_tf_path_(source_tf_path) {}
+
+ bool Run();
+
+ private:
+ bool OpenPackages();
+ bool AnalyzePartition(const std::string& partition_name);
+ std::unordered_map<std::string, uint64_t> GetBlockMap(borrowed_fd fd);
+
+ std::string ota_tf_path_;
+ std::string source_tf_path_;
+ std::unique_ptr<TargetFilesPackage> ota_tf_;
+ std::unique_ptr<TargetFilesPackage> source_tf_;
+ uint64_t size_ = 0;
+};
+
+bool NonAbEstimator::Run() {
+ if (!OpenPackages()) {
+ return false;
+ }
+
+ auto partitions = ota_tf_->GetDynamicPartitionNames();
+ if (partitions.empty()) {
+ LOG(ERROR) << "No dynamic partitions found in META/misc_info.txt";
+ return false;
+ }
+ for (const auto& partition : partitions) {
+ if (!AnalyzePartition(partition)) {
+ return false;
+ }
+ }
+
+ int64_t size_in_mb = int64_t(double(size_) / 1024.0 / 1024.0);
+
+ std::cout << "Estimated COW size: " << size_ << " (" << size_in_mb << "MiB)\n";
+ return true;
+}
+
+bool NonAbEstimator::OpenPackages() {
+ ota_tf_ = std::make_unique<TargetFilesPackage>(ota_tf_path_);
+ if (!ota_tf_->Open()) {
+ return false;
+ }
+ if (!source_tf_path_.empty()) {
+ source_tf_ = std::make_unique<TargetFilesPackage>(source_tf_path_);
+ if (!source_tf_->Open()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static std::string SHA256(const std::string& input) {
+ std::string hash(32, '\0');
+ SHA256_CTX c;
+ SHA256_Init(&c);
+ SHA256_Update(&c, input.data(), input.size());
+ SHA256_Final(reinterpret_cast<unsigned char*>(hash.data()), &c);
+ return hash;
+}
+
+bool NonAbEstimator::AnalyzePartition(const std::string& partition_name) {
+ auto path = "IMAGES/" + partition_name + ".img";
+ auto fd = ota_tf_->OpenImage(path);
+ if (fd < 0) {
+ return false;
+ }
+
+ unique_fd source_fd;
+ uint64_t source_size = 0;
+ std::unordered_map<std::string, uint64_t> source_blocks;
+ if (source_tf_) {
+ auto dap = source_tf_->GetDynamicPartitionNames();
+
+ source_fd = source_tf_->OpenImage(path);
+ if (source_fd >= 0) {
+ struct stat s;
+ if (fstat(source_fd.get(), &s)) {
+ PLOG(ERROR) << "fstat failed";
+ return false;
+ }
+ source_size = s.st_size;
+
+ std::cout << "Hashing blocks for " << partition_name << "...\n";
+ source_blocks = GetBlockMap(source_fd);
+ if (source_blocks.empty()) {
+ LOG(ERROR) << "Could not build a block map for source partition: "
+ << partition_name;
+ return false;
+ }
+ } else {
+ if (dap.count(partition_name)) {
+ return false;
+ }
+ LOG(ERROR) << "Warning: " << partition_name
+ << " has no incremental diff since it's not in the source image.";
+ }
+ }
+
+ TemporaryFile cow;
+ if (cow.fd < 0) {
+ PLOG(ERROR) << "mkstemp failed";
+ return false;
+ }
+
+ CowOptions options;
+ options.block_size = kBlockSize;
+ options.compression = FLAGS_compression;
+
+ auto writer = std::make_unique<CowWriter>(options);
+ if (!writer->Initialize(borrowed_fd{cow.fd})) {
+ LOG(ERROR) << "Could not initialize COW writer";
+ return false;
+ }
+
+ LOG(INFO) << "Analyzing " << partition_name << " ...";
+
+ std::string zeroes(kBlockSize, '\0');
+ std::string chunk(kBlockSize, '\0');
+ std::string src_chunk(kBlockSize, '\0');
+ uint64_t next_block_number = 0;
+ while (true) {
+ if (!android::base::ReadFully(fd, chunk.data(), chunk.size())) {
+ if (errno) {
+ PLOG(ERROR) << "read failed";
+ return false;
+ }
+ break;
+ }
+
+ uint64_t block_number = next_block_number++;
+ if (chunk == zeroes) {
+ if (!writer->AddZeroBlocks(block_number, 1)) {
+ LOG(ERROR) << "Could not add zero block";
+ return false;
+ }
+ continue;
+ }
+
+ uint64_t source_offset = block_number * kBlockSize;
+ if (source_fd >= 0 && source_offset <= source_size) {
+ off64_t offset = block_number * kBlockSize;
+ if (android::base::ReadFullyAtOffset(source_fd, src_chunk.data(), src_chunk.size(),
+ offset)) {
+ if (chunk == src_chunk) {
+ continue;
+ }
+ } else if (errno) {
+ PLOG(ERROR) << "pread failed";
+ return false;
+ }
+ }
+
+ auto hash = SHA256(chunk);
+ if (auto iter = source_blocks.find(hash); iter != source_blocks.end()) {
+ if (!writer->AddCopy(block_number, iter->second)) {
+ return false;
+ }
+ continue;
+ }
+
+ if (!writer->AddRawBlocks(block_number, chunk.data(), chunk.size())) {
+ return false;
+ }
+ }
+
+ if (!writer->Flush()) {
+ return false;
+ }
+
+ struct stat s;
+ if (fstat(cow.fd, &s) < 0) {
+ PLOG(ERROR) << "fstat failed";
+ return false;
+ }
+
+ size_ += s.st_size;
+ return true;
+}
+
+std::unordered_map<std::string, uint64_t> NonAbEstimator::GetBlockMap(borrowed_fd fd) {
+ std::string chunk(kBlockSize, '\0');
+
+ std::unordered_map<std::string, uint64_t> block_map;
+ uint64_t block_number = 0;
+ while (true) {
+ if (!android::base::ReadFully(fd, chunk.data(), chunk.size())) {
+ if (errno) {
+ PLOG(ERROR) << "read failed";
+ return {};
+ }
+ break;
+ }
+ auto hash = SHA256(chunk);
+ block_map[hash] = block_number;
+ block_number++;
+ }
+ return block_map;
+}
+
+} // namespace snapshot
+} // namespace android
+
+using namespace android::snapshot;
+
+int main(int argc, char** argv) {
+ android::base::InitLogging(argv, android::snapshot::MyLogger);
+ gflags::SetUsageMessage("Estimate VAB disk usage from Non A/B builds");
+ gflags::ParseCommandLineFlags(&argc, &argv, false);
+
+ if (FLAGS_ota_tf.empty()) {
+ std::cerr << "Must specify -ota_tf on the command-line." << std::endl;
+ return 1;
+ }
+
+ NonAbEstimator estimator(FLAGS_ota_tf, FLAGS_source_tf);
+ if (!estimator.Run()) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
index 6d500e7..4a6bd4e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_format.h
@@ -45,6 +45,9 @@
uint16_t major_version;
uint16_t minor_version;
+ // Size of this struct.
+ uint16_t header_size;
+
// Offset to the location of the operation sequence, and size of the
// operation sequence buffer. |ops_offset| is also the end of the
// raw data region.
@@ -98,6 +101,7 @@
static constexpr uint8_t kCowCompressNone = 0;
static constexpr uint8_t kCowCompressGz = 1;
+static constexpr uint8_t kCowCompressBrotli = 2;
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
index a3b1291..3998776 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h
@@ -61,9 +61,6 @@
// Return an iterator for retrieving CowOperation entries.
virtual std::unique_ptr<ICowOpIter> GetOpIter() = 0;
- // Get raw bytes from the data section.
- virtual bool GetRawBytes(uint64_t offset, void* buffer, size_t len) = 0;
-
// Get decoded bytes from the data section, handling any decompression.
// All retrieved data is passed to the sink.
virtual bool ReadData(const CowOperation& op, IByteSink* sink) = 0;
@@ -92,10 +89,15 @@
bool Parse(android::base::borrowed_fd fd);
bool GetHeader(CowHeader* header) override;
+
+ // Create a CowOpIter object which contains header_.num_ops
+ // CowOperation objects. Get() returns a unique CowOperation object
+ // whose lifeteime depends on the CowOpIter object
std::unique_ptr<ICowOpIter> GetOpIter() override;
- bool GetRawBytes(uint64_t offset, void* buffer, size_t len) override;
bool ReadData(const CowOperation& op, IByteSink* sink) override;
+ bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
+
private:
android::base::unique_fd owned_fd_;
android::base::borrowed_fd fd_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index 5a2cbd6..2bc0171 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -16,6 +16,7 @@
#include <stdint.h>
+#include <optional>
#include <string>
#include <android-base/unique_fd.h>
@@ -27,6 +28,9 @@
struct CowOptions {
uint32_t block_size = 4096;
std::string compression;
+
+ // Maximum number of blocks that can be written.
+ std::optional<uint64_t> max_blocks;
};
// Interface for writing to a snapuserd COW. All operations are ordered; merges
@@ -39,13 +43,32 @@
// Encode an operation that copies the contents of |old_block| to the
// location of |new_block|.
- virtual bool AddCopy(uint64_t new_block, uint64_t old_block) = 0;
+ bool AddCopy(uint64_t new_block, uint64_t old_block);
// Encode a sequence of raw blocks. |size| must be a multiple of the block size.
- virtual bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
+ bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
// Encode a sequence of zeroed blocks. |size| must be a multiple of the block size.
- virtual bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0;
+ bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks);
+
+ // Flush all pending writes. This must be called before closing the writer
+ // to ensure that the correct headers and footers are written.
+ virtual bool Flush() = 0;
+
+ // Return number of bytes the cow image occupies on disk.
+ virtual uint64_t GetCowSize() = 0;
+
+ // Returns true if AddCopy() operations are supported.
+ virtual bool SupportsCopyOperation() const { return true; }
+
+ const CowOptions& options() { return options_; }
+
+ protected:
+ virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0;
+ virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
+ virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) = 0;
+
+ bool ValidateNewBlock(uint64_t new_block);
protected:
CowOptions options_;
@@ -53,28 +76,37 @@
class CowWriter : public ICowWriter {
public:
+ enum class OpenMode { WRITE, APPEND };
+
explicit CowWriter(const CowOptions& options);
// Set up the writer.
- bool Initialize(android::base::unique_fd&& fd);
- bool Initialize(android::base::borrowed_fd fd);
+ bool Initialize(android::base::unique_fd&& fd, OpenMode mode = OpenMode::WRITE);
+ bool Initialize(android::base::borrowed_fd fd, OpenMode mode = OpenMode::WRITE);
- bool AddCopy(uint64_t new_block, uint64_t old_block) override;
- bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
- bool AddZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
+ bool Flush() override;
- // Finalize all COW operations and flush pending writes.
- bool Finalize();
+ uint64_t GetCowSize() override;
+
+ protected:
+ virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+ virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
+ virtual bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
private:
void SetupHeaders();
+ bool ParseOptions();
+ bool OpenForWrite();
+ bool OpenForAppend();
bool GetDataPos(uint64_t* pos);
+ bool WriteRawData(const void* data, size_t size);
+ void AddOperation(const CowOperation& op);
std::basic_string<uint8_t> Compress(const void* data, size_t length);
private:
android::base::unique_fd owned_fd_;
android::base::borrowed_fd fd_;
- CowHeader header_;
+ CowHeader header_{};
int compression_ = 0;
// :TODO: this is not efficient, but stringstream ubsan aborts because some
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
index 4457de3..13f19aa 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
@@ -15,6 +15,7 @@
#pragma once
#include <libsnapshot/snapshot.h>
+#include <payload_consumer/file_descriptor.h>
#include <gmock/gmock.h>
@@ -37,6 +38,8 @@
(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path),
(override));
+ MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
+ (const android::fs_mgr::CreateLogicalPartitionParams& params), (override));
MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
MOCK_METHOD(bool, CreateLogicalAndSnapshotPartitions,
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index a4a3150..1bc972e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -36,6 +36,7 @@
#include <libsnapshot/auto_device.h>
#include <libsnapshot/return.h>
+#include <libsnapshot/snapshot_writer.h>
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
@@ -173,11 +174,21 @@
// Map a snapshotted partition for OTA clients to write to. Write-protected regions are
// determined previously in CreateSnapshots.
+ //
// |snapshot_path| must not be nullptr.
+ //
+ // This method will return false if ro.virtual_ab.compression.enabled is true.
virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path) = 0;
- // Unmap a snapshot device that's previously mapped with MapUpdateSnapshot.
+ // Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
+ // must be suffixed.
+ virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+ const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;
+
+ // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
+ // OpenSnapshotWriter. All outstanding open descriptors, writers, or
+ // readers must be deleted before this is called.
virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0;
// If this returns true, first-stage mount must call
@@ -288,6 +299,8 @@
Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
std::string* snapshot_path) override;
+ std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+ const android::fs_mgr::CreateLogicalPartitionParams& params) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;
bool CreateLogicalAndSnapshotPartitions(
@@ -506,9 +519,39 @@
std::string GetSnapshotDeviceName(const std::string& snapshot_name,
const SnapshotStatus& status);
+ // Reason for calling MapPartitionWithSnapshot.
+ enum class SnapshotContext {
+ // For writing or verification (during update_engine).
+ Update,
+
+ // For mounting a full readable device.
+ Mount,
+ };
+
+ struct SnapshotPaths {
+ // Target/base device (eg system_b), always present.
+ std::string target_device;
+
+ // COW path (eg system_cow). Not present if no COW is needed.
+ std::string cow_device;
+
+ // dm-snapshot instance. Not present in Update mode for VABC.
+ std::string snapshot_device;
+ };
+
+ // Helpers for OpenSnapshotWriter.
+ std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
+ const std::string& partition_name,
+ const SnapshotStatus& status,
+ const SnapshotPaths& paths);
+ std::unique_ptr<ISnapshotWriter> OpenKernelSnapshotWriter(LockedFile* lock,
+ const std::string& partition_name,
+ const SnapshotStatus& status,
+ const SnapshotPaths& paths);
+
// Map the base device, COW devices, and snapshot device.
bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
- std::string* path);
+ SnapshotContext context, SnapshotPaths* paths);
// Map the COW devices, including the partition in super and the images.
// |params|:
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
index 7a27fad..cda2bee 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
@@ -15,6 +15,7 @@
#pragma once
#include <libsnapshot/snapshot.h>
+#include <payload_consumer/file_descriptor.h>
namespace android::snapshot {
@@ -35,6 +36,8 @@
const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path) override;
+ std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
+ const android::fs_mgr::CreateLogicalPartitionParams& params) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;
bool CreateLogicalAndSnapshotPartitions(
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
new file mode 100644
index 0000000..bf57a00
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 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.
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+
+#include <libsnapshot/cow_writer.h>
+
+namespace chromeos_update_engine {
+class FileDescriptor;
+} // namespace chromeos_update_engine
+
+namespace android {
+namespace snapshot {
+
+class ISnapshotWriter : public ICowWriter {
+ public:
+ using FileDescriptor = chromeos_update_engine::FileDescriptor;
+
+ explicit ISnapshotWriter(const CowOptions& options);
+
+ // Set the source device. This is used for AddCopy() operations, if the
+ // underlying writer needs the original bytes (for example if backed by
+ // dm-snapshot or if writing directly to an unsnapshotted region).
+ void SetSourceDevice(android::base::unique_fd&& source_fd);
+
+ virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;
+
+ protected:
+ android::base::unique_fd source_fd_;
+};
+
+// Write directly to a dm-snapshot device.
+class OnlineKernelSnapshotWriter : public ISnapshotWriter {
+ public:
+ OnlineKernelSnapshotWriter(const CowOptions& options);
+
+ // Set the device used for all writes.
+ void SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, uint64_t cow_size);
+
+ bool Flush() override;
+ uint64_t GetCowSize() override { return cow_size_; }
+ virtual std::unique_ptr<FileDescriptor> OpenReader() override;
+
+ protected:
+ bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
+ bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
+ bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+
+ private:
+ android::base::unique_fd snapshot_fd_;
+ uint64_t cow_size_ = 0;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
new file mode 100644
index 0000000..2f727d6
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
@@ -0,0 +1,113 @@
+// Copyright (C) 2020 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.
+
+#pragma once
+
+#include <linux/types.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <csignal>
+#include <cstring>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
+#include <libdm/dm.h>
+#include <libsnapshot/cow_reader.h>
+#include <libsnapshot/cow_writer.h>
+#include <libsnapshot/snapuserd_kernel.h>
+
+namespace android {
+namespace snapshot {
+
+using android::base::unique_fd;
+
+class BufferSink : public IByteSink {
+ public:
+ void Initialize(size_t size);
+ void* GetBufPtr() { return buffer_.get(); }
+ void Clear() { memset(GetBufPtr(), 0, buffer_size_); }
+ void* GetPayloadBuffer(size_t size);
+ void* GetBuffer(size_t requested, size_t* actual) override;
+ void UpdateBufferOffset(size_t size) { buffer_offset_ += size; }
+ struct dm_user_header* GetHeaderPtr();
+ bool ReturnData(void*, size_t) override { return true; }
+ void ResetBufferOffset() { buffer_offset_ = 0; }
+
+ private:
+ std::unique_ptr<uint8_t[]> buffer_;
+ loff_t buffer_offset_;
+ size_t buffer_size_;
+};
+
+class Snapuserd final {
+ public:
+ Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device,
+ const std::string& in_control_device)
+ : cow_device_(in_cow_device),
+ backing_store_device_(in_backing_store_device),
+ control_device_(in_control_device),
+ metadata_read_done_(false) {}
+
+ bool Init();
+ int Run();
+ int ReadDmUserHeader();
+ int WriteDmUserPayload(size_t size);
+ int ConstructKernelCowHeader();
+ int ReadMetadata();
+ int ZerofillDiskExceptions(size_t read_size);
+ int ReadDiskExceptions(chunk_t chunk, size_t size);
+ int ReadData(chunk_t chunk, size_t size);
+
+ std::string GetControlDevicePath() { return control_device_; }
+
+ private:
+ int ProcessReplaceOp(const CowOperation* cow_op);
+ int ProcessCopyOp(const CowOperation* cow_op);
+ int ProcessZeroOp();
+
+ std::string cow_device_;
+ std::string backing_store_device_;
+ std::string control_device_;
+
+ unique_fd cow_fd_;
+ unique_fd backing_store_fd_;
+ unique_fd ctrl_fd_;
+
+ uint32_t exceptions_per_area_;
+
+ std::unique_ptr<ICowOpIter> cowop_iter_;
+ std::unique_ptr<CowReader> reader_;
+
+ // Vector of disk exception which is a
+ // mapping of old-chunk to new-chunk
+ std::vector<std::unique_ptr<uint8_t[]>> vec_;
+
+ // Index - Chunk ID
+ // Value - cow operation
+ std::vector<const CowOperation*> chunk_vec_;
+
+ bool metadata_read_done_;
+ BufferSink bufsink_;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
new file mode 100644
index 0000000..ab2149e
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 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.
+
+#pragma once
+
+#include <cstring>
+#include <iostream>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace android {
+namespace snapshot {
+
+static constexpr uint32_t PACKET_SIZE = 512;
+static constexpr uint32_t MAX_CONNECT_RETRY_COUNT = 10;
+
+class SnapuserdClient {
+ private:
+ int sockfd_ = 0;
+
+ int Sendmsg(const char* msg, size_t size);
+ std::string Receivemsg();
+ int StartSnapuserdaemon(std::string socketname);
+ bool ConnectToServerSocket(std::string socketname);
+ bool ConnectToServer();
+
+ void DisconnectFromServer() { close(sockfd_); }
+
+ std::string GetSocketNameFirstStage() {
+ static std::string snapd_one("snapdone");
+ return snapd_one;
+ }
+
+ std::string GetSocketNameSecondStage() {
+ static std::string snapd_two("snapdtwo");
+ return snapd_two;
+ }
+
+ public:
+ int StartSnapuserd();
+ int StopSnapuserd(bool firstStageDaemon);
+ int RestartSnapuserd(std::vector<std::vector<std::string>>& vec);
+ int InitializeSnapuserd(std::string cow_device, std::string backing_device,
+ std::string control_device);
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_daemon.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_daemon.h
new file mode 100644
index 0000000..94542d7
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_daemon.h
@@ -0,0 +1,54 @@
+// Copyright (C) 2020 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.
+
+#pragma once
+
+#include <poll.h>
+
+#include <libsnapshot/snapuserd_server.h>
+
+namespace android {
+namespace snapshot {
+
+class Daemon {
+ // The Daemon class is a singleton to avoid
+ // instantiating more than once
+ public:
+ static Daemon& Instance() {
+ static Daemon instance;
+ return instance;
+ }
+
+ int StartServer(std::string socketname);
+ bool IsRunning();
+ void Run();
+
+ private:
+ bool is_running_;
+ std::unique_ptr<struct pollfd> poll_fd_;
+ // Signal mask used with ppoll()
+ sigset_t signal_mask_;
+
+ Daemon();
+ Daemon(Daemon const&) = delete;
+ void operator=(Daemon const&) = delete;
+
+ SnapuserdServer server_;
+ void MaskAllSignalsExceptIntAndTerm();
+ void MaskAllSignals();
+ static void SignalHandler(int signal);
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
new file mode 100644
index 0000000..1037c12
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2020 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.
+
+#pragma once
+
+namespace android {
+namespace snapshot {
+
+// Kernel COW header fields
+static constexpr uint32_t SNAP_MAGIC = 0x70416e53;
+
+static constexpr uint32_t SNAPSHOT_DISK_VERSION = 1;
+
+static constexpr uint32_t NUM_SNAPSHOT_HDR_CHUNKS = 1;
+
+static constexpr uint32_t SNAPSHOT_VALID = 1;
+
+/*
+ * The basic unit of block I/O is a sector. It is used in a number of contexts
+ * in Linux (blk, bio, genhd). The size of one sector is 512 = 2**9
+ * bytes. Variables of type sector_t represent an offset or size that is a
+ * multiple of 512 bytes. Hence these two constants.
+ */
+static constexpr uint32_t SECTOR_SHIFT = 9;
+
+typedef __u64 sector_t;
+typedef sector_t chunk_t;
+
+static constexpr uint32_t CHUNK_SIZE = 8;
+static constexpr uint32_t CHUNK_SHIFT = (__builtin_ffs(CHUNK_SIZE) - 1);
+
+static constexpr uint32_t BLOCK_SIZE = 4096;
+static constexpr uint32_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SIZE) - 1);
+
+// This structure represents the kernel COW header.
+// All the below fields should be in Little Endian format.
+struct disk_header {
+ uint32_t magic;
+
+ /*
+ * Is this snapshot valid. There is no way of recovering
+ * an invalid snapshot.
+ */
+ uint32_t valid;
+
+ /*
+ * Simple, incrementing version. no backward
+ * compatibility.
+ */
+ uint32_t version;
+
+ /* In sectors */
+ uint32_t chunk_size;
+} __packed;
+
+// A disk exception is a mapping of old_chunk to new_chunk
+// old_chunk is the chunk ID of a dm-snapshot device.
+// new_chunk is the chunk ID of the COW device.
+struct disk_exception {
+ uint64_t old_chunk;
+ uint64_t new_chunk;
+} __packed;
+
+// Control structures to communicate with dm-user
+// It comprises of header and a payload
+struct dm_user_header {
+ __u64 seq;
+ __u64 type;
+ __u64 flags;
+ __u64 sector;
+ __u64 len;
+} __attribute__((packed));
+
+struct dm_user_payload {
+ __u8 buf[];
+};
+
+// Message comprising both header and payload
+struct dm_user_message {
+ struct dm_user_header header;
+ struct dm_user_payload payload;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
new file mode 100644
index 0000000..a1ebd3a
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
@@ -0,0 +1,105 @@
+// Copyright (C) 2020 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.
+
+#pragma once
+
+#include <cstdio>
+#include <cstring>
+#include <functional>
+#include <future>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace snapshot {
+
+static constexpr uint32_t MAX_PACKET_SIZE = 512;
+
+enum class DaemonOperations {
+ START,
+ QUERY,
+ TERMINATING,
+ STOP,
+ INVALID,
+};
+
+class Client {
+ private:
+ std::unique_ptr<std::thread> threadHandler_;
+
+ public:
+ void SetThreadHandler(std::function<void(void)> func) {
+ threadHandler_ = std::make_unique<std::thread>(func);
+ }
+
+ std::unique_ptr<std::thread>& GetThreadHandler() { return threadHandler_; }
+};
+
+class Stoppable {
+ std::promise<void> exitSignal_;
+ std::future<void> futureObj_;
+
+ public:
+ Stoppable() : futureObj_(exitSignal_.get_future()) {}
+
+ virtual ~Stoppable() {}
+
+ virtual void ThreadStart(std::string cow_device, std::string backing_device,
+ std::string control_device) = 0;
+
+ bool StopRequested() {
+ // checks if value in future object is available
+ if (futureObj_.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout)
+ return false;
+ return true;
+ }
+ // Request the thread to stop by setting value in promise object
+ void StopThreads() { exitSignal_.set_value(); }
+};
+
+class SnapuserdServer : public Stoppable {
+ private:
+ android::base::unique_fd sockfd_;
+ bool terminating_;
+ std::vector<std::unique_ptr<Client>> clients_vec_;
+
+ void ThreadStart(std::string cow_device, std::string backing_device,
+ std::string control_device) override;
+ void ShutdownThreads();
+ DaemonOperations Resolveop(std::string& input);
+ std::string GetDaemonStatus();
+ void Parsemsg(std::string const& msg, const char delim, std::vector<std::string>& out);
+
+ void SetTerminating() { terminating_ = true; }
+
+ bool IsTerminating() { return terminating_; }
+
+ public:
+ SnapuserdServer() { terminating_ = false; }
+
+ int Start(std::string socketname);
+ int AcceptClient();
+ int Receivemsg(int fd);
+ int Sendmsg(int fd, char* msg, size_t len);
+ std::string Recvmsg(int fd, int* ret);
+ android::base::borrowed_fd GetSocketFd() { return sockfd_; }
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 8e369b0..197aeaa 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -144,6 +144,7 @@
// Expect space of |path| is multiple of 4K.
bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
std::string* hash = nullptr);
+bool WriteRandomData(ICowWriter* writer, std::string* hash = nullptr);
std::optional<std::string> GetHash(const std::string& path);
diff --git a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
index 0b40fd6..f761077 100644
--- a/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
+++ b/fs_mgr/libsnapshot/make_cow_from_ab_ota.cpp
@@ -204,7 +204,7 @@
}
}
- if (!writer_->Finalize()) {
+ if (!writer_->Flush()) {
LOG(ERROR) << "Unable to finalize COW for " << partition_name;
return false;
}
@@ -252,7 +252,7 @@
class PuffInputStream final : public puffin::StreamInterface {
public:
- PuffInputStream(uint8_t* buffer, size_t length) : buffer_(buffer), length_(length) {}
+ PuffInputStream(uint8_t* buffer, size_t length) : buffer_(buffer), length_(length), pos_(0) {}
bool GetSize(uint64_t* size) const override {
*size = length_;
@@ -472,7 +472,7 @@
class ExtentIter final {
public:
ExtentIter(const ContainerType& container)
- : iter_(container.cbegin()), end_(container.cend()) {}
+ : iter_(container.cbegin()), end_(container.cend()), dst_index_(0) {}
bool GetNext(uint64_t* block) {
while (iter_ != end_) {
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index b49f99e..8112b5f 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -15,6 +15,7 @@
#include <libsnapshot/snapshot.h>
#include <dirent.h>
+#include <fcntl.h>
#include <math.h>
#include <sys/file.h>
#include <sys/types.h>
@@ -27,6 +28,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/ext4_utils.h>
@@ -42,6 +44,7 @@
#include "device_info.h"
#include "partition_cow_creator.h"
#include "snapshot_metadata_updater.h"
+#include "snapshot_reader.h"
#include "utility.h"
namespace android {
@@ -68,6 +71,7 @@
using android::hardware::boot::V1_1::MergeStatus;
using chromeos_update_engine::DeltaArchiveManifest;
using chromeos_update_engine::Extent;
+using chromeos_update_engine::FileDescriptor;
using chromeos_update_engine::InstallOperation;
template <typename T>
using RepeatedPtrField = google::protobuf::RepeatedPtrField<T>;
@@ -103,6 +107,10 @@
metadata_dir_ = device_->GetMetadataDir();
}
+static inline bool IsCompressionEnabled() {
+ return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
+}
+
static std::string GetCowName(const std::string& snapshot_name) {
return snapshot_name + "-cow";
}
@@ -1563,8 +1571,8 @@
.partition_opener = &opener,
.timeout_ms = timeout_ms,
};
- std::string ignore_path;
- if (!MapPartitionWithSnapshot(lock.get(), std::move(params), &ignore_path)) {
+ if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount,
+ nullptr)) {
return false;
}
}
@@ -1592,11 +1600,10 @@
bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
CreateLogicalPartitionParams params,
- std::string* path) {
+ SnapshotContext context, SnapshotPaths* paths) {
auto begin = std::chrono::steady_clock::now();
CHECK(lock);
- path->clear();
if (params.GetPartitionName() != params.GetDeviceName()) {
LOG(ERROR) << "Mapping snapshot with a different name is unsupported: partition_name = "
@@ -1677,8 +1684,11 @@
}
created_devices.EmplaceBack<AutoUnmapDevice>(&dm, params.GetDeviceName());
+ if (paths) {
+ paths->target_device = base_path;
+ }
+
if (!live_snapshot_status.has_value()) {
- *path = base_path;
created_devices.Release();
return true;
}
@@ -1705,21 +1715,33 @@
LOG(ERROR) << "Could not determine major/minor for: " << cow_name;
return false;
}
+ if (paths) {
+ paths->cow_device = cow_device;
+ }
remaining_time = GetRemainingTime(params.timeout_ms, begin);
if (remaining_time.count() < 0) return false;
+ if (context == SnapshotContext::Update && IsCompressionEnabled()) {
+ // Stop here, we can't run dm-user yet, the COW isn't built.
+ return true;
+ }
+
+ std::string path;
if (!MapSnapshot(lock, params.GetPartitionName(), base_device, cow_device, remaining_time,
- path)) {
+ &path)) {
LOG(ERROR) << "Could not map snapshot for partition: " << params.GetPartitionName();
return false;
}
// No need to add params.GetPartitionName() to created_devices since it is immediately released.
+ if (paths) {
+ paths->snapshot_device = path;
+ }
+
created_devices.Release();
- LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << *path;
-
+ LOG(INFO) << "Mapped " << params.GetPartitionName() << " as snapshot device at " << path;
return true;
}
@@ -2420,6 +2442,11 @@
bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
std::string* snapshot_path) {
+ if (IsCompressionEnabled()) {
+ LOG(ERROR) << "MapUpdateSnapshot cannot be used in compression mode.";
+ return false;
+ }
+
auto lock = LockShared();
if (!lock) return false;
if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
@@ -2427,7 +2454,85 @@
<< params.GetPartitionName();
return false;
}
- return MapPartitionWithSnapshot(lock.get(), params, snapshot_path);
+
+ SnapshotPaths paths;
+ if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
+ return false;
+ }
+
+ if (!paths.snapshot_device.empty()) {
+ *snapshot_path = paths.snapshot_device;
+ } else {
+ *snapshot_path = paths.target_device;
+ }
+ DCHECK(!snapshot_path->empty());
+ return true;
+}
+
+std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
+ const android::fs_mgr::CreateLogicalPartitionParams& params) {
+ // First unmap any existing mapping.
+ auto lock = LockShared();
+ if (!lock) return nullptr;
+ if (!UnmapPartitionWithSnapshot(lock.get(), params.GetPartitionName())) {
+ LOG(ERROR) << "Cannot unmap existing snapshot before re-mapping it: "
+ << params.GetPartitionName();
+ return nullptr;
+ }
+
+ SnapshotPaths paths;
+ if (!MapPartitionWithSnapshot(lock.get(), params, SnapshotContext::Update, &paths)) {
+ return nullptr;
+ }
+
+ SnapshotStatus status;
+ if (!paths.cow_device.empty()) {
+ if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
+ return nullptr;
+ }
+ } else {
+ // Currently, partition_cow_creator always creates snapshots. The
+ // reason is that if partition X shrinks while partition Y grows, we
+ // cannot bindly write to the newly freed extents in X. This would
+ // make the old slot unusable. So, the entire size of the target
+ // partition is currently considered snapshottable.
+ LOG(ERROR) << "No snapshot available for partition " << params.GetPartitionName();
+ return nullptr;
+ }
+
+ if (IsCompressionEnabled()) {
+ return OpenCompressedSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
+ }
+ return OpenKernelSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
+}
+
+std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
+ LockedFile*, const std::string&, const SnapshotStatus&, const SnapshotPaths&) {
+ LOG(ERROR) << "OpenSnapshotWriter not yet implemented for compression";
+ return nullptr;
+}
+
+std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
+ LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
+ const SnapshotStatus& status, const SnapshotPaths& paths) {
+ CHECK(lock);
+
+ CowOptions cow_options;
+ cow_options.max_blocks = {status.device_size() / cow_options.block_size};
+
+ auto writer = std::make_unique<OnlineKernelSnapshotWriter>(cow_options);
+
+ std::string path = paths.snapshot_device.empty() ? paths.target_device : paths.snapshot_device;
+ unique_fd fd(open(path.c_str(), O_RDWR | O_CLOEXEC));
+ if (fd < 0) {
+ PLOG(ERROR) << "open failed: " << path;
+ return nullptr;
+ }
+
+ uint64_t cow_size = status.cow_partition_size() + status.cow_file_size();
+ writer->SetSnapshotDevice(std::move(fd), cow_size);
+
+ return writer;
}
bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) {
diff --git a/fs_mgr/libsnapshot/snapshot_reader.cpp b/fs_mgr/libsnapshot/snapshot_reader.cpp
new file mode 100644
index 0000000..0d47468
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_reader.cpp
@@ -0,0 +1,77 @@
+//
+// Copyright (C) 2020 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 <ext4_utils/ext4_utils.h>
+
+#include "snapshot_reader.h"
+
+namespace android {
+namespace snapshot {
+
+// Not supported.
+bool ReadOnlyFileDescriptor::Open(const char*, int, mode_t) {
+ errno = EINVAL;
+ return false;
+}
+
+bool ReadOnlyFileDescriptor::Open(const char*, int) {
+ errno = EINVAL;
+ return false;
+}
+
+ssize_t ReadOnlyFileDescriptor::Write(const void*, size_t) {
+ errno = EINVAL;
+ return false;
+}
+
+bool ReadOnlyFileDescriptor::BlkIoctl(int, uint64_t, uint64_t, int*) {
+ errno = EINVAL;
+ return false;
+}
+
+ReadFdFileDescriptor::ReadFdFileDescriptor(android::base::unique_fd&& fd) : fd_(std::move(fd)) {}
+
+ssize_t ReadFdFileDescriptor::Read(void* buf, size_t count) {
+ return read(fd_.get(), buf, count);
+}
+
+off64_t ReadFdFileDescriptor::Seek(off64_t offset, int whence) {
+ return lseek(fd_.get(), offset, whence);
+}
+
+uint64_t ReadFdFileDescriptor::BlockDevSize() {
+ return get_block_device_size(fd_.get());
+}
+
+bool ReadFdFileDescriptor::Close() {
+ fd_ = {};
+ return true;
+}
+
+bool ReadFdFileDescriptor::IsSettingErrno() {
+ return true;
+}
+
+bool ReadFdFileDescriptor::IsOpen() {
+ return fd_ >= 0;
+}
+
+bool ReadFdFileDescriptor::Flush() {
+ return true;
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_reader.h b/fs_mgr/libsnapshot/snapshot_reader.h
new file mode 100644
index 0000000..1f2ffe2
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_reader.h
@@ -0,0 +1,50 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#pragma once
+
+#include <android-base/file.h>
+#include <payload_consumer/file_descriptor.h>
+
+namespace android {
+namespace snapshot {
+
+class ReadOnlyFileDescriptor : public chromeos_update_engine::FileDescriptor {
+ public:
+ bool Open(const char* path, int flags, mode_t mode) override;
+ bool Open(const char* path, int flags) override;
+ ssize_t Write(const void* buf, size_t count) override;
+ bool BlkIoctl(int request, uint64_t start, uint64_t length, int* result) override;
+};
+
+class ReadFdFileDescriptor : public ReadOnlyFileDescriptor {
+ public:
+ explicit ReadFdFileDescriptor(android::base::unique_fd&& fd);
+
+ ssize_t Read(void* buf, size_t count) override;
+ off64_t Seek(off64_t offset, int whence) override;
+ uint64_t BlockDevSize() override;
+ bool Close() override;
+ bool IsSettingErrno() override;
+ bool IsOpen() override;
+ bool Flush() override;
+
+ private:
+ android::base::unique_fd fd_;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp
index 9b6f758..41f5da4 100644
--- a/fs_mgr/libsnapshot/snapshot_stub.cpp
+++ b/fs_mgr/libsnapshot/snapshot_stub.cpp
@@ -20,6 +20,7 @@
using android::fs_mgr::CreateLogicalPartitionParams;
using chromeos_update_engine::DeltaArchiveManifest;
+using chromeos_update_engine::FileDescriptor;
namespace android::snapshot {
@@ -129,4 +130,10 @@
return &snapshot_merge_stats;
}
+std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
+ const CreateLogicalPartitionParams&) {
+ LOG(ERROR) << __FUNCTION__ << " should never be called.";
+ return nullptr;
+}
+
} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 6ff935b..77226ad 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -80,6 +80,7 @@
std::string fake_super;
void MountMetadata();
+bool IsCompressionEnabled();
class SnapshotTest : public ::testing::Test {
public:
@@ -892,42 +893,78 @@
return AssertionSuccess();
}
- AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path = nullptr) {
- std::string real_path;
- if (!sm->MapUpdateSnapshot(
- CreateLogicalPartitionParams{
- .block_device = fake_super,
- .metadata_slot = 1,
- .partition_name = name,
- .timeout_ms = 10s,
- .partition_opener = opener_.get(),
- },
- &real_path)) {
- return AssertionFailure() << "Unable to map snapshot " << name;
+ AssertionResult MapUpdateSnapshot(const std::string& name,
+ std::unique_ptr<ICowWriter>* writer) {
+ CreateLogicalPartitionParams params{
+ .block_device = fake_super,
+ .metadata_slot = 1,
+ .partition_name = name,
+ .timeout_ms = 10s,
+ .partition_opener = opener_.get(),
+ };
+
+ auto result = sm->OpenSnapshotWriter(params);
+ if (!result) {
+ return AssertionFailure() << "Cannot open snapshot for writing: " << name;
}
- if (path) {
- *path = real_path;
+
+ if (writer) {
+ *writer = std::move(result);
}
- return AssertionSuccess() << "Mapped snapshot " << name << " to " << real_path;
+ return AssertionSuccess();
}
- AssertionResult WriteSnapshotAndHash(const std::string& name,
- std::optional<size_t> size = std::nullopt) {
- std::string path;
- auto res = MapUpdateSnapshot(name, &path);
- if (!res) {
- return res;
+ AssertionResult MapUpdateSnapshot(const std::string& name, std::string* path) {
+ CreateLogicalPartitionParams params{
+ .block_device = fake_super,
+ .metadata_slot = 1,
+ .partition_name = name,
+ .timeout_ms = 10s,
+ .partition_opener = opener_.get(),
+ };
+
+ auto result = sm->MapUpdateSnapshot(params, path);
+ if (!result) {
+ return AssertionFailure() << "Cannot open snapshot for writing: " << name;
+ }
+ return AssertionSuccess();
+ }
+
+ AssertionResult MapUpdateSnapshot(const std::string& name) {
+ if (IsCompressionEnabled()) {
+ std::unique_ptr<ICowWriter> writer;
+ return MapUpdateSnapshot(name, &writer);
+ } else {
+ std::string path;
+ return MapUpdateSnapshot(name, &path);
+ }
+ }
+
+ AssertionResult WriteSnapshotAndHash(const std::string& name) {
+ if (IsCompressionEnabled()) {
+ std::unique_ptr<ICowWriter> writer;
+ auto res = MapUpdateSnapshot(name, &writer);
+ if (!res) {
+ return res;
+ }
+ if (!WriteRandomData(writer.get(), &hashes_[name])) {
+ return AssertionFailure() << "Unable to write random data to snapshot " << name;
+ }
+ } else {
+ std::string path;
+ auto res = MapUpdateSnapshot(name, &path);
+ if (!res) {
+ return res;
+ }
+ if (!WriteRandomData(path, std::nullopt, &hashes_[name])) {
+ return AssertionFailure() << "Unable to write random data to snapshot " << name;
+ }
}
- std::string size_string = size ? (std::to_string(*size) + " bytes") : "";
+ // Make sure updates to one device are seen by all devices.
+ sync();
- if (!WriteRandomData(path, size, &hashes_[name])) {
- return AssertionFailure() << "Unable to write " << size_string << " to " << path
- << " for partition " << name;
- }
-
- return AssertionSuccess() << "Written " << size_string << " to " << path
- << " for snapshot partition " << name
+ return AssertionSuccess() << "Written random data to snapshot " << name
<< ", hash: " << hashes_[name];
}
@@ -1003,7 +1040,7 @@
// Write some data to target partitions.
for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) {
- ASSERT_TRUE(WriteSnapshotAndHash(name, partition_size));
+ ASSERT_TRUE(WriteSnapshotAndHash(name));
}
// Assert that source partitions aren't affected.
@@ -1406,6 +1443,10 @@
MetadataMountedTest().TearDown();
}
+bool IsCompressionEnabled() {
+ return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
+}
+
TEST_F(MetadataMountedTest, Android) {
auto device = sm->EnsureMetadataMounted();
EXPECT_NE(nullptr, device);
@@ -1623,7 +1664,7 @@
// Map and write some data to target partition.
ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b", partition_size));
+ ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
// Finish update.
ASSERT_TRUE(sm->FinishedSnapshotWrites(false));
@@ -1655,7 +1696,7 @@
// Map and write some data to target partitions.
ASSERT_TRUE(MapUpdateSnapshots({"vnd_b", "prd_b"}));
- ASSERT_TRUE(WriteSnapshotAndHash("sys_b", actual_write_size));
+ ASSERT_TRUE(WriteSnapshotAndHash("sys_b"));
std::vector<android::dm::DeviceMapper::TargetInfo> table;
ASSERT_TRUE(DeviceMapper::Instance().GetTableStatus("sys_b", &table));
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
new file mode 100644
index 0000000..584f15e
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -0,0 +1,97 @@
+//
+// Copyright (C) 2020 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 <libsnapshot/snapshot_writer.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <payload_consumer/file_descriptor.h>
+#include "snapshot_reader.h"
+
+namespace android {
+namespace snapshot {
+
+using android::base::unique_fd;
+using chromeos_update_engine::FileDescriptor;
+
+ISnapshotWriter::ISnapshotWriter(const CowOptions& options) : ICowWriter(options) {}
+
+void ISnapshotWriter::SetSourceDevice(android::base::unique_fd&& source_fd) {
+ source_fd_ = std::move(source_fd);
+}
+
+OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
+ : ISnapshotWriter(options) {}
+
+void OnlineKernelSnapshotWriter::SetSnapshotDevice(android::base::unique_fd&& snapshot_fd,
+ uint64_t cow_size) {
+ snapshot_fd_ = std::move(snapshot_fd);
+ cow_size_ = cow_size;
+}
+
+bool OnlineKernelSnapshotWriter::Flush() {
+ if (fsync(snapshot_fd_.get()) < 0) {
+ PLOG(ERROR) << "fsync";
+ return false;
+ }
+ return true;
+}
+
+bool OnlineKernelSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
+ size_t size) {
+ uint64_t offset = new_block_start * options_.block_size;
+ if (lseek(snapshot_fd_.get(), offset, SEEK_SET) < 0) {
+ PLOG(ERROR) << "EmitRawBlocks lseek to offset " << offset;
+ return false;
+ }
+ if (!android::base::WriteFully(snapshot_fd_, data, size)) {
+ PLOG(ERROR) << "EmitRawBlocks write";
+ return false;
+ }
+ return true;
+}
+
+bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
+ std::string zeroes(options_.block_size, 0);
+ for (uint64_t i = 0; i < num_blocks; i++) {
+ if (!EmitRawBlocks(new_block_start + i, zeroes.data(), zeroes.size())) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+ std::string buffer(options_.block_size, 0);
+ uint64_t offset = old_block * options_.block_size;
+ if (!android::base::ReadFullyAtOffset(source_fd_, buffer.data(), buffer.size(), offset)) {
+ PLOG(ERROR) << "EmitCopy read";
+ return false;
+ }
+ return EmitRawBlocks(new_block, buffer.data(), buffer.size());
+}
+
+std::unique_ptr<FileDescriptor> OnlineKernelSnapshotWriter::OpenReader() {
+ unique_fd fd(dup(snapshot_fd_.get()));
+ if (fd < 0) {
+ PLOG(ERROR) << "dup2 failed in OpenReader";
+ return nullptr;
+ }
+ return std::make_unique<ReadFdFileDescriptor>(std::move(fd));
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index a6ff4fd..62ef1b0 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -14,113 +14,617 @@
* limitations under the License.
*/
-#include <linux/types.h>
+#include <csignal>
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <libdm/dm.h>
+#include <libsnapshot/snapuserd.h>
+#include <libsnapshot/snapuserd_daemon.h>
+#include <libsnapshot/snapuserd_server.h>
+namespace android {
+namespace snapshot {
+
+using namespace android;
+using namespace android::dm;
using android::base::unique_fd;
#define DM_USER_MAP_READ 0
#define DM_USER_MAP_WRITE 1
-struct dm_user_message {
- __u64 seq;
- __u64 type;
- __u64 flags;
- __u64 sector;
- __u64 len;
- __u8 buf[];
-};
+static constexpr size_t PAYLOAD_SIZE = (1UL << 16);
-using namespace android::dm;
+static_assert(PAYLOAD_SIZE >= BLOCK_SIZE);
-static int daemon_main(const std::string& device) {
- unique_fd block_fd(open(device.c_str(), O_RDWR));
- if (block_fd < 0) {
- PLOG(ERROR) << "Unable to open " << device;
- return 1;
+void BufferSink::Initialize(size_t size) {
+ buffer_size_ = size;
+ buffer_offset_ = 0;
+ buffer_ = std::make_unique<uint8_t[]>(size);
+}
+
+void* BufferSink::GetPayloadBuffer(size_t size) {
+ if ((buffer_size_ - buffer_offset_) < size) return nullptr;
+
+ char* buffer = reinterpret_cast<char*>(GetBufPtr());
+ struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
+ return (char*)msg->payload.buf + buffer_offset_;
+}
+
+void* BufferSink::GetBuffer(size_t requested, size_t* actual) {
+ void* buf = GetPayloadBuffer(requested);
+ if (!buf) {
+ *actual = 0;
+ return nullptr;
+ }
+ *actual = requested;
+ return buf;
+}
+
+struct dm_user_header* BufferSink::GetHeaderPtr() {
+ CHECK(sizeof(struct dm_user_header) <= buffer_size_);
+ char* buf = reinterpret_cast<char*>(GetBufPtr());
+ struct dm_user_header* header = (struct dm_user_header*)(&(buf[0]));
+ return header;
+}
+
+// Construct kernel COW header in memory
+// This header will be in sector 0. The IO
+// request will always be 4k. After constructing
+// the header, zero out the remaining block.
+int Snapuserd::ConstructKernelCowHeader() {
+ void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
+ CHECK(buffer != nullptr);
+
+ memset(buffer, 0, BLOCK_SIZE);
+
+ struct disk_header* dh = reinterpret_cast<struct disk_header*>(buffer);
+
+ dh->magic = SNAP_MAGIC;
+ dh->valid = SNAPSHOT_VALID;
+ dh->version = SNAPSHOT_DISK_VERSION;
+ dh->chunk_size = CHUNK_SIZE;
+
+ return BLOCK_SIZE;
+}
+
+// Start the replace operation. This will read the
+// internal COW format and if the block is compressed,
+// it will be de-compressed.
+int Snapuserd::ProcessReplaceOp(const CowOperation* cow_op) {
+ if (!reader_->ReadData(*cow_op, &bufsink_)) {
+ LOG(ERROR) << "ReadData failed for chunk: " << cow_op->new_block;
+ return -EIO;
}
- unique_fd ctrl_fd(open("/dev/dm-user", O_RDWR));
- if (ctrl_fd < 0) {
- PLOG(ERROR) << "Unable to open /dev/dm-user";
- return 1;
+ return BLOCK_SIZE;
+}
+
+// Start the copy operation. This will read the backing
+// block device which is represented by cow_op->source.
+int Snapuserd::ProcessCopyOp(const CowOperation* cow_op) {
+ void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
+ CHECK(buffer != nullptr);
+
+ // Issue a single 4K IO. However, this can be optimized
+ // if the successive blocks are contiguous.
+ if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SIZE,
+ cow_op->source * BLOCK_SIZE)) {
+ LOG(ERROR) << "Copy-op failed. Read from backing store at: " << cow_op->source;
+ return -1;
}
- size_t buf_size = 1UL << 16;
- auto buf = std::make_unique<char>(buf_size);
+ return BLOCK_SIZE;
+}
- /* Just keeps pumping messages between userspace and the kernel. We won't
- * actually be doing anything, but the sequence numbers line up so it'll at
- * least make forward progress. */
- while (true) {
- struct dm_user_message* msg = (struct dm_user_message*)buf.get();
+int Snapuserd::ProcessZeroOp() {
+ // Zero out the entire block
+ void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SIZE);
+ CHECK(buffer != nullptr);
- memset(buf.get(), 0, buf_size);
+ memset(buffer, 0, BLOCK_SIZE);
+ return BLOCK_SIZE;
+}
- ssize_t readed = read(ctrl_fd.get(), buf.get(), buf_size);
- if (readed < 0) {
- PLOG(ERROR) << "Control read failed, trying with more space";
- buf_size *= 2;
- buf = std::make_unique<char>(buf_size);
- continue;
- }
+/*
+ * Read the data of size bytes from a given chunk.
+ *
+ * Kernel can potentially merge the blocks if the
+ * successive chunks are contiguous. For chunk size of 8,
+ * there can be 256 disk exceptions; and if
+ * all 256 disk exceptions are contiguous, kernel can merge
+ * them into a single IO.
+ *
+ * Since each chunk in the disk exception
+ * mapping represents a 4k block, kernel can potentially
+ * issue 256*4k = 1M IO in one shot.
+ *
+ * Even though kernel assumes that the blocks are
+ * contiguous, we need to split the 1M IO into 4k chunks
+ * as each operation represents 4k and it can either be:
+ *
+ * 1: Replace operation
+ * 2: Copy operation
+ * 3: Zero operation
+ *
+ */
+int Snapuserd::ReadData(chunk_t chunk, size_t size) {
+ int ret = 0;
- LOG(DEBUG) << android::base::StringPrintf("read() from dm-user returned %d bytes:",
- (int)readed);
- LOG(DEBUG) << android::base::StringPrintf(" msg->seq: 0x%016llx", msg->seq);
- LOG(DEBUG) << android::base::StringPrintf(" msg->type: 0x%016llx", msg->type);
- LOG(DEBUG) << android::base::StringPrintf(" msg->flags: 0x%016llx", msg->flags);
- LOG(DEBUG) << android::base::StringPrintf(" msg->sector: 0x%016llx", msg->sector);
- LOG(DEBUG) << android::base::StringPrintf(" msg->len: 0x%016llx", msg->len);
+ size_t read_size = size;
- switch (msg->type) {
- case DM_USER_MAP_READ: {
- LOG(DEBUG) << android::base::StringPrintf(
- "Responding to read of sector %lld with %lld bytes data", msg->sector,
- msg->len);
+ chunk_t chunk_key = chunk;
+ uint32_t stride;
+ lldiv_t divresult;
- if ((sizeof(*msg) + msg->len) > buf_size) {
- auto old_buf = std::move(buf);
- buf_size = sizeof(*msg) + msg->len;
- buf = std::make_unique<char>(buf_size);
- memcpy(buf.get(), old_buf.get(), sizeof(*msg));
- msg = (struct dm_user_message*)buf.get();
- }
+ // Size should always be aligned
+ CHECK((read_size & (BLOCK_SIZE - 1)) == 0);
- if (lseek(block_fd.get(), msg->sector * 512, SEEK_SET) < 0) {
- PLOG(ERROR) << "lseek failed: " << device;
- return 7;
- }
- if (!android::base::ReadFully(block_fd.get(), msg->buf, msg->len)) {
- PLOG(ERROR) << "read failed: " << device;
- return 7;
- }
+ while (read_size > 0) {
+ const CowOperation* cow_op = chunk_vec_[chunk_key];
+ CHECK(cow_op != nullptr);
+ int result;
- if (!android::base::WriteFully(ctrl_fd.get(), buf.get(), sizeof(*msg) + msg->len)) {
- PLOG(ERROR) << "write control failed";
- return 3;
- }
+ switch (cow_op->type) {
+ case kCowReplaceOp: {
+ result = ProcessReplaceOp(cow_op);
break;
}
- case DM_USER_MAP_WRITE:
- abort();
+ case kCowZeroOp: {
+ result = ProcessZeroOp();
break;
+ }
+
+ case kCowCopyOp: {
+ result = ProcessCopyOp(cow_op);
+ break;
+ }
+
+ default: {
+ LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
+ ret = -EIO;
+ goto done;
+ }
}
- LOG(DEBUG) << "read() finished, next message";
+ if (result < 0) {
+ ret = result;
+ goto done;
+ }
+
+ // Update the buffer offset
+ bufsink_.UpdateBufferOffset(BLOCK_SIZE);
+
+ read_size -= BLOCK_SIZE;
+ ret += BLOCK_SIZE;
+
+ // Start iterating the chunk incrementally; Since while
+ // constructing the metadata, we know that the chunk IDs
+ // are contiguous
+ chunk_key += 1;
+
+ // This is similar to the way when chunk IDs were assigned
+ // in ReadMetadata().
+ //
+ // Skip if the chunk id represents a metadata chunk.
+ stride = exceptions_per_area_ + 1;
+ divresult = lldiv(chunk_key, stride);
+ if (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS) {
+ // Crossing exception boundary. Kernel will never
+ // issue IO which is spanning between a data chunk
+ // and a metadata chunk. This should be perfectly aligned.
+ //
+ // Since the input read_size is 4k aligned, we will
+ // always end up reading all 256 data chunks in one area.
+ // Thus, every multiple of 4K IO represents 256 data chunks
+ CHECK(read_size == 0);
+ break;
+ }
+ }
+
+done:
+
+ // Reset the buffer offset
+ bufsink_.ResetBufferOffset();
+ return ret;
+}
+
+/*
+ * dm-snap does prefetch reads while reading disk-exceptions.
+ * By default, prefetch value is set to 12; this means that
+ * dm-snap will issue 12 areas wherein each area is a 4k page
+ * of disk-exceptions.
+ *
+ * If during prefetch, if the chunk-id seen is beyond the
+ * actual number of metadata page, fill the buffer with zero.
+ * When dm-snap starts parsing the buffer, it will stop
+ * reading metadata page once the buffer content is zero.
+ */
+int Snapuserd::ZerofillDiskExceptions(size_t read_size) {
+ size_t size = exceptions_per_area_ * sizeof(struct disk_exception);
+
+ if (read_size > size) return -EINVAL;
+
+ void* buffer = bufsink_.GetPayloadBuffer(size);
+ CHECK(buffer != nullptr);
+
+ memset(buffer, 0, size);
+ return size;
+}
+
+/*
+ * A disk exception is a simple mapping of old_chunk to new_chunk.
+ * When dm-snapshot device is created, kernel requests these mapping.
+ *
+ * Each disk exception is of size 16 bytes. Thus a single 4k page can
+ * have:
+ *
+ * exceptions_per_area_ = 4096/16 = 256. This entire 4k page
+ * is considered a metadata page and it is represented by chunk ID.
+ *
+ * Convert the chunk ID to index into the vector which gives us
+ * the metadata page.
+ */
+int Snapuserd::ReadDiskExceptions(chunk_t chunk, size_t read_size) {
+ uint32_t stride = exceptions_per_area_ + 1;
+ size_t size;
+
+ // ChunkID to vector index
+ lldiv_t divresult = lldiv(chunk, stride);
+
+ if (divresult.quot < vec_.size()) {
+ size = exceptions_per_area_ * sizeof(struct disk_exception);
+
+ if (read_size > size) return -EINVAL;
+
+ void* buffer = bufsink_.GetPayloadBuffer(size);
+ CHECK(buffer != nullptr);
+
+ memcpy(buffer, vec_[divresult.quot].get(), size);
+ } else {
+ size = ZerofillDiskExceptions(read_size);
+ }
+
+ return size;
+}
+
+/*
+ * Read the metadata from COW device and
+ * construct the metadata as required by the kernel.
+ *
+ * Please see design on kernel COW format
+ *
+ * 1: Read the metadata from internal COW device
+ * 2: There are 3 COW operations:
+ * a: Replace op
+ * b: Copy op
+ * c: Zero op
+ * 3: For each of the 3 operations, op->new_block
+ * represents the block number in the base device
+ * for which one of the 3 operations have to be applied.
+ * This represents the old_chunk in the kernel COW format
+ * 4: We need to assign new_chunk for a corresponding old_chunk
+ * 5: The algorithm is similar to how kernel assigns chunk number
+ * while creating exceptions.
+ * 6: Use a monotonically increasing chunk number to assign the
+ * new_chunk
+ * 7: Each chunk-id represents either a: Metadata page or b: Data page
+ * 8: Chunk-id representing a data page is stored in a vector. Index is the
+ * chunk-id and value is the pointer to the CowOperation
+ * 9: Chunk-id representing a metadata page is converted into a vector
+ * index. We store this in vector as kernel requests metadata during
+ * two stage:
+ * a: When initial dm-snapshot device is created, kernel requests
+ * all the metadata and stores it in its internal data-structures.
+ * b: During merge, kernel once again requests the same metadata
+ * once-again.
+ * In both these cases, a quick lookup based on chunk-id is done.
+ * 10: When chunk number is incremented, we need to make sure that
+ * if the chunk is representing a metadata page and skip.
+ * 11: Each 4k page will contain 256 disk exceptions. We call this
+ * exceptions_per_area_
+ * 12: Kernel will stop issuing metadata IO request when new-chunk ID is 0.
+ */
+int Snapuserd::ReadMetadata() {
+ reader_ = std::make_unique<CowReader>();
+ CowHeader header;
+
+ if (!reader_->Parse(cow_fd_)) {
+ LOG(ERROR) << "Failed to parse";
+ return 1;
+ }
+
+ if (!reader_->GetHeader(&header)) {
+ LOG(ERROR) << "Failed to get header";
+ return 1;
+ }
+
+ CHECK(header.block_size == BLOCK_SIZE);
+
+ LOG(DEBUG) << "Num-ops: " << std::hex << header.num_ops;
+ LOG(DEBUG) << "ops-offset: " << std::hex << header.ops_offset;
+ LOG(DEBUG) << "ops-size: " << std::hex << header.ops_size;
+
+ cowop_iter_ = reader_->GetOpIter();
+
+ if (cowop_iter_ == nullptr) {
+ LOG(ERROR) << "Failed to get cowop_iter";
+ return 1;
+ }
+
+ exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception);
+
+ // Start from chunk number 2. Chunk 0 represents header and chunk 1
+ // represents first metadata page.
+ chunk_t next_free = NUM_SNAPSHOT_HDR_CHUNKS + 1;
+ chunk_vec_.push_back(nullptr);
+ chunk_vec_.push_back(nullptr);
+
+ loff_t offset = 0;
+ std::unique_ptr<uint8_t[]> de_ptr =
+ std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception));
+
+ // This memset is important. Kernel will stop issuing IO when new-chunk ID
+ // is 0. When Area is not filled completely will all 256 exceptions,
+ // this memset will ensure that metadata read is completed.
+ memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
+ size_t num_ops = 0;
+
+ while (!cowop_iter_->Done()) {
+ const CowOperation* cow_op = &cowop_iter_->Get();
+ struct disk_exception* de =
+ reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
+
+ if (!(cow_op->type == kCowReplaceOp || cow_op->type == kCowZeroOp ||
+ cow_op->type == kCowCopyOp)) {
+ LOG(ERROR) << "Unknown operation-type found: " << cow_op->type;
+ return 1;
+ }
+
+ // Construct the disk-exception
+ de->old_chunk = cow_op->new_block;
+ de->new_chunk = next_free;
+
+ LOG(DEBUG) << "Old-chunk: " << de->old_chunk << "New-chunk: " << de->new_chunk;
+
+ // Store operation pointer. Note, new-chunk ID is the index
+ chunk_vec_.push_back(cow_op);
+ CHECK(next_free == (chunk_vec_.size() - 1));
+
+ offset += sizeof(struct disk_exception);
+
+ cowop_iter_->Next();
+
+ // Find the next free chunk-id to be assigned. Check if the next free
+ // chunk-id represents a metadata page. If so, skip it.
+ next_free += 1;
+ uint32_t stride = exceptions_per_area_ + 1;
+ lldiv_t divresult = lldiv(next_free, stride);
+ num_ops += 1;
+
+ if (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS) {
+ CHECK(num_ops == exceptions_per_area_);
+ // Store it in vector at the right index. This maps the chunk-id to
+ // vector index.
+ vec_.push_back(std::move(de_ptr));
+ offset = 0;
+ num_ops = 0;
+
+ chunk_t metadata_chunk = (next_free - exceptions_per_area_ - NUM_SNAPSHOT_HDR_CHUNKS);
+
+ LOG(DEBUG) << "Area: " << vec_.size() - 1;
+ LOG(DEBUG) << "Metadata-chunk: " << metadata_chunk;
+ LOG(DEBUG) << "Sector number of Metadata-chunk: " << (metadata_chunk << CHUNK_SHIFT);
+
+ // Create buffer for next area
+ de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ *
+ sizeof(struct disk_exception));
+ memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
+
+ // Since this is a metadata, store at this index
+ chunk_vec_.push_back(nullptr);
+
+ // Find the next free chunk-id
+ next_free += 1;
+ if (cowop_iter_->Done()) {
+ vec_.push_back(std::move(de_ptr));
+ }
+ }
+ }
+
+ // Partially filled area
+ if (num_ops) {
+ LOG(DEBUG) << "Partially filled area num_ops: " << num_ops;
+ vec_.push_back(std::move(de_ptr));
}
return 0;
}
+void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
+ unsigned int, const char* message) {
+ if (severity == android::base::ERROR) {
+ fprintf(stderr, "%s\n", message);
+ } else {
+ fprintf(stdout, "%s\n", message);
+ }
+}
+
+// Read Header from dm-user misc device. This gives
+// us the sector number for which IO is issued by dm-snapshot device
+int Snapuserd::ReadDmUserHeader() {
+ int ret;
+
+ ret = read(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header));
+ if (ret < 0) {
+ PLOG(ERROR) << "Control-read failed with: " << ret;
+ return ret;
+ }
+
+ return sizeof(struct dm_user_header);
+}
+
+// Send the payload/data back to dm-user misc device.
+int Snapuserd::WriteDmUserPayload(size_t size) {
+ if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
+ sizeof(struct dm_user_header) + size)) {
+ PLOG(ERROR) << "Write to dm-user failed";
+ return -1;
+ }
+
+ return sizeof(struct dm_user_header) + size;
+}
+
+bool Snapuserd::Init() {
+ backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
+ if (backing_store_fd_ < 0) {
+ LOG(ERROR) << "Open Failed: " << backing_store_device_;
+ return false;
+ }
+
+ cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
+ if (cow_fd_ < 0) {
+ LOG(ERROR) << "Open Failed: " << cow_device_;
+ return false;
+ }
+
+ std::string control_path = GetControlDevicePath();
+
+ LOG(DEBUG) << "Opening control device " << control_path;
+
+ ctrl_fd_.reset(open(control_path.c_str(), O_RDWR));
+ if (ctrl_fd_ < 0) {
+ LOG(ERROR) << "Unable to open " << control_path;
+ return false;
+ }
+
+ // Allocate the buffer which is used to communicate between
+ // daemon and dm-user. The buffer comprises of header and a fixed payload.
+ // If the dm-user requests a big IO, the IO will be broken into chunks
+ // of PAYLOAD_SIZE.
+ size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_SIZE;
+ bufsink_.Initialize(buf_size);
+
+ return true;
+}
+
+int Snapuserd::Run() {
+ int ret = 0;
+
+ struct dm_user_header* header = bufsink_.GetHeaderPtr();
+
+ bufsink_.Clear();
+
+ ret = ReadDmUserHeader();
+ if (ret < 0) return ret;
+
+ LOG(DEBUG) << "dm-user returned " << ret << " bytes";
+
+ LOG(DEBUG) << "msg->seq: " << std::hex << header->seq;
+ LOG(DEBUG) << "msg->type: " << std::hex << header->type;
+ LOG(DEBUG) << "msg->flags: " << std::hex << header->flags;
+ LOG(DEBUG) << "msg->sector: " << std::hex << header->sector;
+ LOG(DEBUG) << "msg->len: " << std::hex << header->len;
+
+ switch (header->type) {
+ case DM_USER_MAP_READ: {
+ size_t remaining_size = header->len;
+ loff_t offset = 0;
+ ret = 0;
+ do {
+ size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
+
+ // Request to sector 0 is always for kernel
+ // representation of COW header. This IO should be only
+ // once during dm-snapshot device creation. We should
+ // never see multiple IO requests. Additionally this IO
+ // will always be a single 4k.
+ if (header->sector == 0) {
+ // Read the metadata from internal COW device
+ // and build the in-memory data structures
+ // for all the operations in the internal COW.
+ if (!metadata_read_done_ && ReadMetadata()) {
+ LOG(ERROR) << "Metadata read failed";
+ return 1;
+ }
+ metadata_read_done_ = true;
+
+ CHECK(read_size == BLOCK_SIZE);
+ ret = ConstructKernelCowHeader();
+ if (ret < 0) return ret;
+ } else {
+ // Convert the sector number to a chunk ID.
+ //
+ // Check if the chunk ID represents a metadata
+ // page. If the chunk ID is not found in the
+ // vector, then it points to a metadata page.
+ chunk_t chunk = (header->sector >> CHUNK_SHIFT);
+
+ if (chunk >= chunk_vec_.size()) {
+ ret = ZerofillDiskExceptions(read_size);
+ if (ret < 0) {
+ LOG(ERROR) << "ZerofillDiskExceptions failed";
+ return ret;
+ }
+ } else if (chunk_vec_[chunk] == nullptr) {
+ ret = ReadDiskExceptions(chunk, read_size);
+ if (ret < 0) {
+ LOG(ERROR) << "ReadDiskExceptions failed";
+ return ret;
+ }
+ } else {
+ chunk_t num_chunks_read = (offset >> BLOCK_SHIFT);
+ ret = ReadData(chunk + num_chunks_read, read_size);
+ if (ret < 0) {
+ LOG(ERROR) << "ReadData failed";
+ // TODO: Bug 168259959: All the error paths from this function
+ // should send error code to dm-user thereby IO
+ // terminates with an error from dm-user. Returning
+ // here without sending error code will block the
+ // IO.
+ return ret;
+ }
+ }
+ }
+
+ ssize_t written = WriteDmUserPayload(ret);
+ if (written < 0) return written;
+
+ remaining_size -= ret;
+ offset += ret;
+ if (remaining_size) {
+ LOG(DEBUG) << "Write done ret: " << ret
+ << " remaining size: " << remaining_size;
+ }
+ } while (remaining_size);
+
+ break;
+ }
+
+ case DM_USER_MAP_WRITE: {
+ // TODO: Bug: 168311203: After merge operation is completed, kernel issues write
+ // to flush all the exception mappings where the merge is
+ // completed. If dm-user routes the WRITE IO, we need to clear
+ // in-memory data structures representing those exception
+ // mappings.
+ abort();
+ break;
+ }
+ }
+
+ LOG(DEBUG) << "read() finished, next message";
+
+ return 0;
+}
+
+} // namespace snapshot
+} // namespace android
+
int main([[maybe_unused]] int argc, char** argv) {
android::base::InitLogging(argv, &android::base::KernelLogger);
- daemon_main(argv[1]);
+
+ android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
+
+ daemon.StartServer(argv[1]);
+ daemon.Run();
+
return 0;
}
diff --git a/fs_mgr/libsnapshot/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd_client.cpp
new file mode 100644
index 0000000..78dbada
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd_client.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2020 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 <arpa/inet.h>
+#include <cutils/sockets.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <chrono>
+
+#include <android-base/logging.h>
+#include <libsnapshot/snapuserd_client.h>
+
+namespace android {
+namespace snapshot {
+
+bool SnapuserdClient::ConnectToServerSocket(std::string socketname) {
+ sockfd_ = 0;
+
+ sockfd_ =
+ socket_local_client(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+ if (sockfd_ < 0) {
+ LOG(ERROR) << "Failed to connect to " << socketname;
+ return false;
+ }
+
+ std::string msg = "query";
+
+ int sendRet = Sendmsg(msg.c_str(), msg.size());
+ if (sendRet < 0) {
+ LOG(ERROR) << "Failed to send query message to snapuserd daemon with socket " << socketname;
+ DisconnectFromServer();
+ return false;
+ }
+
+ std::string str = Receivemsg();
+
+ if (str.find("fail") != std::string::npos) {
+ LOG(ERROR) << "Failed to receive message from snapuserd daemon with socket " << socketname;
+ DisconnectFromServer();
+ return false;
+ }
+
+ // If the daemon is passive then fallback to secondary active daemon. Daemon
+ // is passive during transition phase. Please see RestartSnapuserd()
+ if (str.find("passive") != std::string::npos) {
+ LOG(DEBUG) << "Snapuserd is passive with socket " << socketname;
+ DisconnectFromServer();
+ return false;
+ }
+
+ CHECK(str.find("active") != std::string::npos);
+
+ return true;
+}
+
+bool SnapuserdClient::ConnectToServer() {
+ if (ConnectToServerSocket(GetSocketNameFirstStage())) return true;
+
+ if (ConnectToServerSocket(GetSocketNameSecondStage())) return true;
+
+ return false;
+}
+
+int SnapuserdClient::Sendmsg(const char* msg, size_t size) {
+ int numBytesSent = TEMP_FAILURE_RETRY(send(sockfd_, msg, size, 0));
+ if (numBytesSent < 0) {
+ LOG(ERROR) << "Send failed " << strerror(errno);
+ return -1;
+ }
+
+ if ((uint)numBytesSent < size) {
+ LOG(ERROR) << "Partial data sent " << strerror(errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+std::string SnapuserdClient::Receivemsg() {
+ int ret;
+ struct timeval tv;
+ fd_set set;
+ char msg[PACKET_SIZE];
+ std::string msgStr("fail");
+
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ FD_ZERO(&set);
+ FD_SET(sockfd_, &set);
+ ret = select(sockfd_ + 1, &set, NULL, NULL, &tv);
+ if (ret == -1) { // select failed
+ LOG(ERROR) << "Snapuserd:client: Select call failed";
+ } else if (ret == 0) { // timeout
+ LOG(ERROR) << "Snapuserd:client: Select call timeout";
+ } else {
+ ret = TEMP_FAILURE_RETRY(recv(sockfd_, msg, PACKET_SIZE, 0));
+ if (ret < 0) {
+ PLOG(ERROR) << "Snapuserd:client: recv failed";
+ } else if (ret == 0) {
+ LOG(DEBUG) << "Snapuserd:client disconnected";
+ } else {
+ msgStr.clear();
+ msgStr = msg;
+ }
+ }
+ return msgStr;
+}
+
+int SnapuserdClient::StopSnapuserd(bool firstStageDaemon) {
+ if (firstStageDaemon) {
+ sockfd_ = socket_local_client(GetSocketNameFirstStage().c_str(),
+ ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+ if (sockfd_ < 0) {
+ LOG(ERROR) << "Failed to connect to " << GetSocketNameFirstStage();
+ return -1;
+ }
+ } else {
+ if (!ConnectToServer()) {
+ LOG(ERROR) << "Failed to connect to socket " << GetSocketNameSecondStage();
+ return -1;
+ }
+ }
+
+ std::string msg = "stop";
+
+ int sendRet = Sendmsg(msg.c_str(), msg.size());
+ if (sendRet < 0) {
+ LOG(ERROR) << "Failed to send stop message to snapuserd daemon";
+ return -1;
+ }
+
+ DisconnectFromServer();
+
+ return 0;
+}
+
+int SnapuserdClient::StartSnapuserdaemon(std::string socketname) {
+ int retry_count = 0;
+
+ if (fork() == 0) {
+ const char* argv[] = {"/system/bin/snapuserd", socketname.c_str(), nullptr};
+ if (execv(argv[0], const_cast<char**>(argv))) {
+ LOG(ERROR) << "Failed to exec snapuserd daemon";
+ return -1;
+ }
+ }
+
+ // snapuserd is a daemon and will never exit; parent can't wait here
+ // to get the return code. Since Snapuserd starts the socket server,
+ // give it some time to fully launch.
+ //
+ // Try to connect to server to verify snapuserd server is started
+ while (retry_count < MAX_CONNECT_RETRY_COUNT) {
+ if (!ConnectToServer()) {
+ retry_count++;
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ } else {
+ close(sockfd_);
+ return 0;
+ }
+ }
+
+ LOG(ERROR) << "Failed to start snapuserd daemon";
+ return -1;
+}
+
+int SnapuserdClient::StartSnapuserd() {
+ if (StartSnapuserdaemon(GetSocketNameFirstStage()) < 0) return -1;
+
+ return 0;
+}
+
+int SnapuserdClient::InitializeSnapuserd(std::string cow_device, std::string backing_device,
+ std::string control_device) {
+ int ret = 0;
+
+ if (!ConnectToServer()) {
+ LOG(ERROR) << "Failed to connect to server ";
+ return -1;
+ }
+
+ std::string msg = "start," + cow_device + "," + backing_device + "," + control_device;
+
+ ret = Sendmsg(msg.c_str(), msg.size());
+ if (ret < 0) {
+ LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
+ return -1;
+ }
+
+ std::string str = Receivemsg();
+
+ if (str.find("fail") != std::string::npos) {
+ LOG(ERROR) << "Failed to receive ack for " << msg << " from snapuserd daemon";
+ return -1;
+ }
+
+ DisconnectFromServer();
+
+ LOG(DEBUG) << "Snapuserd daemon initialized with " << msg;
+ return 0;
+}
+
+/*
+ * Transition from first stage snapuserd daemon to second stage daemon involves
+ * series of steps viz:
+ *
+ * 1: Create new dm-user devices - This is done by libsnapshot
+ *
+ * 2: Spawn the new snapuserd daemon - This is the second stage daemon which
+ * will start the server but the dm-user misc devices is not binded yet.
+ *
+ * 3: Vector to this function contains pair of cow_device and source device.
+ * Ex: {{system_cow,system_a}, {product_cow, product_a}, {vendor_cow,
+ * vendor_a}}. This vector will be populated by the libsnapshot.
+ *
+ * 4: Initialize the Second stage daemon passing the information from the
+ * vector. This will bind the daemon with dm-user misc device and will be ready
+ * to serve the IO. Up until this point, first stage daemon is still active.
+ * However, client library will mark the first stage daemon as passive and hence
+ * all the control message from hereon will be sent to active second stage
+ * daemon.
+ *
+ * 5: Create new dm-snapshot table. This is done by libsnapshot. When new table
+ * is created, kernel will issue metadata read once again which will be served
+ * by second stage daemon. However, any active IO will still be served by first
+ * stage daemon.
+ *
+ * 6: Swap the snapshot table atomically - This is done by libsnapshot. Once
+ * the swapping is done, all the IO will be served by second stage daemon.
+ *
+ * 7: Stop the first stage daemon. After this point second stage daemon is
+ * completely active to serve the IO and merging process.
+ *
+ */
+int SnapuserdClient::RestartSnapuserd(std::vector<std::vector<std::string>>& vec) {
+ // Connect to first-stage daemon and send a terminate-request control
+ // message. This will not terminate the daemon but will mark the daemon as
+ // passive.
+ if (!ConnectToServer()) {
+ LOG(ERROR) << "Failed to connect to server ";
+ return -1;
+ }
+
+ std::string msg = "terminate-request";
+
+ int sendRet = Sendmsg(msg.c_str(), msg.size());
+ if (sendRet < 0) {
+ LOG(ERROR) << "Failed to send message " << msg << " to snapuserd daemon";
+ return -1;
+ }
+
+ std::string str = Receivemsg();
+
+ if (str.find("fail") != std::string::npos) {
+ LOG(ERROR) << "Failed to receive ack for " << msg << " from snapuserd daemon";
+ return -1;
+ }
+
+ CHECK(str.find("success") != std::string::npos);
+
+ DisconnectFromServer();
+
+ // Start the new daemon
+ if (StartSnapuserdaemon(GetSocketNameSecondStage()) < 0) {
+ LOG(ERROR) << "Failed to start new daemon at socket " << GetSocketNameSecondStage();
+ return -1;
+ }
+
+ LOG(DEBUG) << "Second stage Snapuserd daemon created successfully at socket "
+ << GetSocketNameSecondStage();
+
+ // Vector contains all the device information to be passed to the new
+ // daemon. Note that the caller can choose to initialize separately
+ // by calling InitializeSnapuserd() API as well. In that case, vector
+ // should be empty
+ for (int i = 0; i < vec.size(); i++) {
+ std::string& cow_device = vec[i][0];
+ std::string& base_device = vec[i][1];
+ std::string& control_device = vec[i][2];
+
+ InitializeSnapuserd(cow_device, base_device, control_device);
+ LOG(DEBUG) << "Daemon initialized with " << cow_device << ", " << base_device << " and "
+ << control_device;
+ }
+
+ return 0;
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
new file mode 100644
index 0000000..8e76618
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd_daemon.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2020 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/logging.h>
+#include <libsnapshot/snapuserd_daemon.h>
+
+namespace android {
+namespace snapshot {
+
+int Daemon::StartServer(std::string socketname) {
+ int ret;
+
+ ret = server_.Start(socketname);
+ if (ret < 0) {
+ LOG(ERROR) << "Snapuserd daemon failed to start...";
+ exit(EXIT_FAILURE);
+ }
+
+ return ret;
+}
+
+void Daemon::MaskAllSignalsExceptIntAndTerm() {
+ sigset_t signal_mask;
+ sigfillset(&signal_mask);
+ sigdelset(&signal_mask, SIGINT);
+ sigdelset(&signal_mask, SIGTERM);
+ sigdelset(&signal_mask, SIGPIPE);
+ if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
+ PLOG(ERROR) << "Failed to set sigprocmask";
+ }
+}
+
+void Daemon::MaskAllSignals() {
+ sigset_t signal_mask;
+ sigfillset(&signal_mask);
+ if (sigprocmask(SIG_SETMASK, &signal_mask, NULL) != 0) {
+ PLOG(ERROR) << "Couldn't mask all signals";
+ }
+}
+
+Daemon::Daemon() {
+ is_running_ = true;
+}
+
+bool Daemon::IsRunning() {
+ return is_running_;
+}
+
+void Daemon::Run() {
+ poll_fd_ = std::make_unique<struct pollfd>();
+ poll_fd_->fd = server_.GetSocketFd().get();
+ poll_fd_->events = POLLIN;
+
+ sigfillset(&signal_mask_);
+ sigdelset(&signal_mask_, SIGINT);
+ sigdelset(&signal_mask_, SIGTERM);
+
+ // Masking signals here ensure that after this point, we won't handle INT/TERM
+ // until after we call into ppoll()
+ MaskAllSignals();
+ signal(SIGINT, Daemon::SignalHandler);
+ signal(SIGTERM, Daemon::SignalHandler);
+ signal(SIGPIPE, Daemon::SignalHandler);
+
+ LOG(DEBUG) << "Snapuserd-server: ready to accept connections";
+
+ while (IsRunning()) {
+ int ret = ppoll(poll_fd_.get(), 1, nullptr, &signal_mask_);
+ MaskAllSignalsExceptIntAndTerm();
+
+ if (ret == -1) {
+ PLOG(ERROR) << "Snapuserd:ppoll error";
+ break;
+ }
+
+ if (poll_fd_->revents == POLLIN) {
+ if (server_.AcceptClient() == static_cast<int>(DaemonOperations::STOP)) {
+ Daemon::Instance().is_running_ = false;
+ }
+ }
+
+ // Mask all signals to ensure that is_running_ can't become false between
+ // checking it in the while condition and calling into ppoll()
+ MaskAllSignals();
+ }
+}
+
+void Daemon::SignalHandler(int signal) {
+ LOG(DEBUG) << "Snapuserd received signal: " << signal;
+ switch (signal) {
+ case SIGINT:
+ case SIGTERM: {
+ Daemon::Instance().is_running_ = false;
+ break;
+ }
+ case SIGPIPE: {
+ LOG(ERROR) << "Received SIGPIPE signal";
+ break;
+ }
+ default:
+ LOG(ERROR) << "Received unknown signal " << signal;
+ break;
+ }
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
new file mode 100644
index 0000000..53101aa
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2020 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 <arpa/inet.h>
+#include <cutils/sockets.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <libsnapshot/snapuserd.h>
+#include <libsnapshot/snapuserd_server.h>
+
+namespace android {
+namespace snapshot {
+
+DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
+ if (input == "start") return DaemonOperations::START;
+ if (input == "stop") return DaemonOperations::STOP;
+ if (input == "terminate-request") return DaemonOperations::TERMINATING;
+ if (input == "query") return DaemonOperations::QUERY;
+
+ return DaemonOperations::INVALID;
+}
+
+std::string SnapuserdServer::GetDaemonStatus() {
+ std::string msg = "";
+
+ if (IsTerminating())
+ msg = "passive";
+ else
+ msg = "active";
+
+ return msg;
+}
+
+void SnapuserdServer::Parsemsg(std::string const& msg, const char delim,
+ std::vector<std::string>& out) {
+ std::stringstream ss(msg);
+ std::string s;
+
+ while (std::getline(ss, s, delim)) {
+ out.push_back(s);
+ }
+}
+
+// new thread
+void SnapuserdServer::ThreadStart(std::string cow_device, std::string backing_device,
+ std::string control_device) {
+ Snapuserd snapd(cow_device, backing_device, control_device);
+ if (!snapd.Init()) {
+ PLOG(ERROR) << "Snapuserd: Init failed";
+ return;
+ }
+
+ while (StopRequested() == false) {
+ int ret = snapd.Run();
+
+ if (ret < 0) {
+ LOG(ERROR) << "Snapuserd: Thread terminating as control device is de-registered";
+ break;
+ }
+ }
+}
+
+void SnapuserdServer::ShutdownThreads() {
+ StopThreads();
+
+ for (auto& client : clients_vec_) {
+ auto& th = client->GetThreadHandler();
+
+ if (th->joinable()) th->join();
+ }
+}
+
+int SnapuserdServer::Sendmsg(int fd, char* msg, size_t size) {
+ int ret = TEMP_FAILURE_RETRY(send(fd, (char*)msg, size, 0));
+ if (ret < 0) {
+ PLOG(ERROR) << "Snapuserd:server: send() failed";
+ return -1;
+ }
+
+ if (ret < size) {
+ PLOG(ERROR) << "Partial data sent";
+ return -1;
+ }
+
+ return 0;
+}
+
+std::string SnapuserdServer::Recvmsg(int fd, int* ret) {
+ struct timeval tv;
+ fd_set set;
+ char msg[MAX_PACKET_SIZE];
+
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ *ret = select(fd + 1, &set, NULL, NULL, &tv);
+ if (*ret == -1) { // select failed
+ return {};
+ } else if (*ret == 0) { // timeout
+ return {};
+ } else {
+ *ret = TEMP_FAILURE_RETRY(recv(fd, msg, MAX_PACKET_SIZE, 0));
+ if (*ret < 0) {
+ PLOG(ERROR) << "Snapuserd:server: recv failed";
+ return {};
+ } else if (*ret == 0) {
+ LOG(DEBUG) << "Snapuserd client disconnected";
+ return {};
+ } else {
+ std::string str(msg);
+ return str;
+ }
+ }
+}
+
+int SnapuserdServer::Receivemsg(int fd) {
+ char msg[MAX_PACKET_SIZE];
+ std::unique_ptr<Client> newClient;
+ int ret = 0;
+
+ while (1) {
+ memset(msg, '\0', MAX_PACKET_SIZE);
+ std::string str = Recvmsg(fd, &ret);
+
+ if (ret <= 0) {
+ LOG(DEBUG) << "recv failed with ret: " << ret;
+ return 0;
+ }
+
+ const char delim = ',';
+
+ std::vector<std::string> out;
+ Parsemsg(str, delim, out);
+ DaemonOperations op = Resolveop(out[0]);
+ memset(msg, '\0', MAX_PACKET_SIZE);
+
+ switch (op) {
+ case DaemonOperations::START: {
+ // Message format:
+ // start,<cow_device_path>,<source_device_path>,<control_device>
+ //
+ // Start the new thread which binds to dm-user misc device
+ newClient = std::make_unique<Client>();
+ newClient->SetThreadHandler(
+ std::bind(&SnapuserdServer::ThreadStart, this, out[1], out[2], out[3]));
+ clients_vec_.push_back(std::move(newClient));
+ sprintf(msg, "success");
+ Sendmsg(fd, msg, MAX_PACKET_SIZE);
+ return 0;
+ }
+ case DaemonOperations::STOP: {
+ // Message format: stop
+ //
+ // Stop all the threads gracefully and then shutdown the
+ // main thread
+ ShutdownThreads();
+ return static_cast<int>(DaemonOperations::STOP);
+ }
+ case DaemonOperations::TERMINATING: {
+ // Message format: terminate-request
+ //
+ // This is invoked during transition. First stage
+ // daemon will receive this request. First stage daemon
+ // will be considered as a passive daemon from hereon.
+ SetTerminating();
+ sprintf(msg, "success");
+ Sendmsg(fd, msg, MAX_PACKET_SIZE);
+ return 0;
+ }
+ case DaemonOperations::QUERY: {
+ // Message format: query
+ //
+ // As part of transition, Second stage daemon will be
+ // created before terminating the first stage daemon. Hence,
+ // for a brief period client may have to distiguish between
+ // first stage daemon and second stage daemon.
+ //
+ // Second stage daemon is marked as active and hence will
+ // be ready to receive control message.
+ std::string dstr = GetDaemonStatus();
+ memcpy(msg, dstr.c_str(), dstr.size());
+ Sendmsg(fd, msg, MAX_PACKET_SIZE);
+ if (dstr == "active")
+ break;
+ else
+ return 0;
+ }
+ default: {
+ sprintf(msg, "fail");
+ Sendmsg(fd, msg, MAX_PACKET_SIZE);
+ return 0;
+ }
+ }
+ }
+}
+
+int SnapuserdServer::Start(std::string socketname) {
+ sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM));
+ if (sockfd_ < 0) {
+ PLOG(ERROR) << "Failed to create server socket " << socketname;
+ return -1;
+ }
+
+ LOG(DEBUG) << "Snapuserd server successfully started with socket name " << socketname;
+ return 0;
+}
+
+int SnapuserdServer::AcceptClient() {
+ int fd = accept(sockfd_.get(), NULL, NULL);
+ if (fd < 0) {
+ PLOG(ERROR) << "Socket accept failed: " << strerror(errno);
+ return -1;
+ }
+
+ return Receivemsg(fd);
+}
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/test_helpers.cpp b/fs_mgr/libsnapshot/test_helpers.cpp
index b07bf91..6104c82 100644
--- a/fs_mgr/libsnapshot/test_helpers.cpp
+++ b/fs_mgr/libsnapshot/test_helpers.cpp
@@ -127,6 +127,48 @@
return true;
}
+bool WriteRandomData(ICowWriter* writer, std::string* hash) {
+ unique_fd rand(open("/dev/urandom", O_RDONLY));
+ if (rand < 0) {
+ PLOG(ERROR) << "open /dev/urandom";
+ return false;
+ }
+
+ SHA256_CTX ctx;
+ if (hash) {
+ SHA256_Init(&ctx);
+ }
+
+ if (!writer->options().max_blocks) {
+ LOG(ERROR) << "CowWriter must specify maximum number of blocks";
+ return false;
+ }
+ uint64_t num_blocks = writer->options().max_blocks.value();
+
+ size_t block_size = writer->options().block_size;
+ std::string block(block_size, '\0');
+ for (uint64_t i = 0; i < num_blocks; i++) {
+ if (!ReadFully(rand, block.data(), block.size())) {
+ PLOG(ERROR) << "read /dev/urandom";
+ return false;
+ }
+ if (!writer->AddRawBlocks(i, block.data(), block.size())) {
+ LOG(ERROR) << "Failed to add raw block " << i;
+ return false;
+ }
+ if (hash) {
+ SHA256_Update(&ctx, block.data(), block.size());
+ }
+ }
+
+ if (hash) {
+ uint8_t out[32];
+ SHA256_Final(out, &ctx);
+ *hash = ToHexString(out, sizeof(out));
+ }
+ return true;
+}
+
std::optional<std::string> GetHash(const std::string& path) {
std::string content;
if (!android::base::ReadFileToString(path, &content, true)) {
diff --git a/fs_mgr/tests/Android.bp b/fs_mgr/tests/Android.bp
index f68ab87..9ed283a 100644
--- a/fs_mgr/tests/Android.bp
+++ b/fs_mgr/tests/Android.bp
@@ -17,7 +17,6 @@
test_suites: [
"cts",
"device-tests",
- "vts10",
],
compile_multilib: "both",
multilib: {
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index d56f7f2..e995888 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -740,7 +740,7 @@
grep -v \
-e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \
-e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \
- -e "^\(ramdumpfs\) " \
+ -e "^\(ramdumpfs\|binder\|/sys/kernel/debug\) " \
-e " functionfs " \
-e "^\(/data/media\|/dev/block/loop[0-9]*\) " \
-e "^rootfs / rootfs rw," \
@@ -755,7 +755,7 @@
uninteresting to the test" ]
skip_unrelated_mounts() {
grep -v "^overlay.* /\(apex\|bionic\|system\|vendor\)/[^ ]" |
- grep -v "[%] /\(apex\|bionic\|system\|vendor\)/[^ ][^ ]*$"
+ grep -v "[%] /\(data_mirror\|apex\|bionic\|system\|vendor\)/[^ ][^ ]*$"
}
##
@@ -1301,9 +1301,9 @@
fi
check_ne "${BASE_SYSTEM_DEVT}" "${BASE_VENDOR_DEVT}" --warning system/vendor devt
[ -n "${SYSTEM_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
- die "system devt ${SYSTEM_DEVT} is major 0"
+ echo "${YELLOW}[ WARNING ]${NORMAL} system devt ${SYSTEM_DEVT} major 0" >&2
[ -n "${VENDOR_DEVT%[0-9a-fA-F][0-9a-fA-F]}" ] ||
- die "vendor devt ${SYSTEM_DEVT} is major 0"
+ echo "${YELLOW}[ WARNING ]${NORMAL} vendor devt ${VENDOR_DEVT} major 0" >&2
# Download libc.so, append some gargage, push back, and check if the file
# is updated.
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 27c8aae..46f1c59 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -394,9 +394,9 @@
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source none0 swap defaults encryptable,forceencrypt,fileencryption,forcefdeorfbe,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_loopback_path,zram_loopback_size,zram_backing_dev_path
+source none0 swap defaults encryptable,forceencrypt,fileencryption,forcefdeorfbe,keydirectory,length,swapprio,zramsize,max_comp_streams,reservedsize,eraseblk,logicalblk,sysfs_path,zram_backingdev_size
-source none1 swap defaults encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_loopback_path=,zram_loopback_size=,zram_backing_dev_path=
+source none1 swap defaults encryptable=,forceencrypt=,fileencryption=,keydirectory=,length=,swapprio=,zramsize=,max_comp_streams=,avb=,reservedsize=,eraseblk=,logicalblk=,sysfs_path=,zram_backingdev_size=
source none2 swap defaults forcefdeorfbe=
@@ -426,9 +426,7 @@
EXPECT_EQ(0, entry->erase_blk_size);
EXPECT_EQ(0, entry->logical_blk_size);
EXPECT_EQ("", entry->sysfs_path);
- EXPECT_EQ("", entry->zram_loopback_path);
- EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
- EXPECT_EQ("", entry->zram_backing_dev_path);
+ EXPECT_EQ(0U, entry->zram_backingdev_size);
entry++;
EXPECT_EQ("none1", entry->mount_point);
@@ -453,9 +451,7 @@
EXPECT_EQ(0, entry->erase_blk_size);
EXPECT_EQ(0, entry->logical_blk_size);
EXPECT_EQ("", entry->sysfs_path);
- EXPECT_EQ("", entry->zram_loopback_path);
- EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
- EXPECT_EQ("", entry->zram_backing_dev_path);
+ EXPECT_EQ(0U, entry->zram_backingdev_size);
entry++;
// forcefdeorfbe has its own encryption_options defaults, so test it separately.
@@ -960,14 +956,10 @@
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
std::string fstab_contents = R"fs(
-source none0 swap defaults zram_loopback_path=/dev/path
-
-source none1 swap defaults zram_loopback_size=blah
-source none2 swap defaults zram_loopback_size=2
-source none3 swap defaults zram_loopback_size=1K
-source none4 swap defaults zram_loopback_size=2m
-
-source none5 swap defaults zram_backing_dev_path=/dev/path2
+source none1 swap defaults zram_backingdev_size=blah
+source none2 swap defaults zram_backingdev_size=2
+source none3 swap defaults zram_backingdev_size=1K
+source none4 swap defaults zram_backingdev_size=2m
)fs";
@@ -975,31 +967,25 @@
Fstab fstab;
EXPECT_TRUE(ReadFstabFromFile(tf.path, &fstab));
- ASSERT_EQ(6U, fstab.size());
+ ASSERT_EQ(4U, fstab.size());
auto entry = fstab.begin();
- EXPECT_EQ("none0", entry->mount_point);
- EXPECT_EQ("/dev/path", entry->zram_loopback_path);
- entry++;
EXPECT_EQ("none1", entry->mount_point);
- EXPECT_EQ(512U * 1024U * 1024U, entry->zram_loopback_size);
+ EXPECT_EQ(0U, entry->zram_backingdev_size);
entry++;
EXPECT_EQ("none2", entry->mount_point);
- EXPECT_EQ(2U, entry->zram_loopback_size);
+ EXPECT_EQ(2U, entry->zram_backingdev_size);
entry++;
EXPECT_EQ("none3", entry->mount_point);
- EXPECT_EQ(1024U, entry->zram_loopback_size);
+ EXPECT_EQ(1024U, entry->zram_backingdev_size);
entry++;
EXPECT_EQ("none4", entry->mount_point);
- EXPECT_EQ(2U * 1024U * 1024U, entry->zram_loopback_size);
+ EXPECT_EQ(2U * 1024U * 1024U, entry->zram_backingdev_size);
entry++;
-
- EXPECT_EQ("none5", entry->mount_point);
- EXPECT_EQ("/dev/path2", entry->zram_backing_dev_path);
}
TEST(fs_mgr, DefaultFstabContainsUserdata) {
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 7a3d9a9..62ca162 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -38,6 +38,7 @@
#include <vector>
using namespace std::literals::string_literals;
+using namespace std::chrono_literals;
using namespace android::dm;
using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
@@ -49,6 +50,7 @@
std::cerr << " delete <dm-name>" << std::endl;
std::cerr << " list <devices | targets> [-v]" << std::endl;
std::cerr << " getpath <dm-name>" << std::endl;
+ std::cerr << " getuuid <dm-name>" << std::endl;
std::cerr << " info <dm-name>" << std::endl;
std::cerr << " status <dm-name>" << std::endl;
std::cerr << " resume <dm-name>" << std::endl;
@@ -175,7 +177,12 @@
return std::make_unique<DmTargetSnapshot>(start_sector, num_sectors, base_device,
cow_device, mode, chunk_size);
} else if (target_type == "user") {
- return std::make_unique<DmTargetUser>(start_sector, num_sectors);
+ if (!HasArgs(1)) {
+ std::cerr << "Expected \"user\" <control_device_name>" << std::endl;
+ return nullptr;
+ }
+ std::string control_device = NextArg();
+ return std::make_unique<DmTargetUser>(start_sector, num_sectors, control_device);
} else {
std::cerr << "Unrecognized target type: " << target_type << std::endl;
return nullptr;
@@ -241,8 +248,9 @@
return ret;
}
+ std::string ignore_path;
DeviceMapper& dm = DeviceMapper::Instance();
- if (!dm.CreateDevice(name, table)) {
+ if (!dm.CreateDevice(name, table, &ignore_path, 5s)) {
std::cerr << "Failed to create device-mapper device with name: " << name << std::endl;
return -EIO;
}
@@ -391,6 +399,22 @@
return 0;
}
+static int GetUuidCmdHandler(int argc, char** argv) {
+ if (argc != 1) {
+ std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
+ return -EINVAL;
+ }
+
+ DeviceMapper& dm = DeviceMapper::Instance();
+ std::string uuid;
+ if (!dm.GetDmDeviceUuidByName(argv[0], &uuid)) {
+ std::cerr << "Could not query uuid of device \"" << argv[0] << "\"." << std::endl;
+ return -EINVAL;
+ }
+ std::cout << uuid << std::endl;
+ return 0;
+}
+
static int InfoCmdHandler(int argc, char** argv) {
if (argc != 1) {
std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
@@ -504,6 +528,7 @@
{"list", DmListCmdHandler},
{"help", HelpCmdHandler},
{"getpath", GetPathCmdHandler},
+ {"getuuid", GetUuidCmdHandler},
{"info", InfoCmdHandler},
{"table", TableCmdHandler},
{"status", StatusCmdHandler},
diff --git a/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl b/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl
index 57adaba..4646efc 100644
--- a/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl
+++ b/gatekeeperd/binder/android/service/gatekeeper/IGateKeeperService.aidl
@@ -30,7 +30,7 @@
interface IGateKeeperService {
/**
* Enrolls a password, returning the handle to the enrollment to be stored locally.
- * @param uid The Android user ID associated to this enrollment
+ * @param userId The Android user ID associated to this enrollment
* @param currentPasswordHandle The previously enrolled handle, or null if none
* @param currentPassword The previously enrolled plaintext password, or null if none.
* If provided, must verify against the currentPasswordHandle.
@@ -38,22 +38,22 @@
* upon success.
* @return an EnrollResponse or null on failure
*/
- GateKeeperResponse enroll(int uid, in @nullable byte[] currentPasswordHandle,
+ GateKeeperResponse enroll(int userId, in @nullable byte[] currentPasswordHandle,
in @nullable byte[] currentPassword, in byte[] desiredPassword);
/**
* Verifies an enrolled handle against a provided, plaintext blob.
- * @param uid The Android user ID associated to this enrollment
+ * @param userId The Android user ID associated to this enrollment
* @param enrolledPasswordHandle The handle against which the provided password will be
* verified.
* @param The plaintext blob to verify against enrolledPassword.
* @return a VerifyResponse, or null on failure.
*/
- GateKeeperResponse verify(int uid, in byte[] enrolledPasswordHandle, in byte[] providedPassword);
+ GateKeeperResponse verify(int userId, in byte[] enrolledPasswordHandle, in byte[] providedPassword);
/**
* Verifies an enrolled handle against a provided, plaintext blob.
- * @param uid The Android user ID associated to this enrollment
+ * @param userId The Android user ID associated to this enrollment
* @param challenge a challenge to authenticate agaisnt the device credential. If successful
* authentication occurs, this value will be written to the returned
* authentication attestation.
@@ -62,22 +62,22 @@
* @param The plaintext blob to verify against enrolledPassword.
* @return a VerifyResponse with an attestation, or null on failure.
*/
- GateKeeperResponse verifyChallenge(int uid, long challenge, in byte[] enrolledPasswordHandle,
+ GateKeeperResponse verifyChallenge(int userId, long challenge, in byte[] enrolledPasswordHandle,
in byte[] providedPassword);
/**
* Retrieves the secure identifier for the user with the provided Android ID,
* or 0 if none is found.
- * @param uid the Android user id
+ * @param userId the Android user id
*/
- long getSecureUserId(int uid);
+ long getSecureUserId(int userId);
/**
* Clears secure user id associated with the provided Android ID.
* Must be called when password is set to NONE.
- * @param uid the Android user id.
+ * @param userId the Android user id.
*/
- void clearSecureUserId(int uid);
+ void clearSecureUserId(int userId);
/**
* Notifies gatekeeper that device setup has been completed and any potentially still existing
diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp
index c81a80e..b982dbc 100644
--- a/gatekeeperd/gatekeeperd.cpp
+++ b/gatekeeperd/gatekeeperd.cpp
@@ -76,9 +76,9 @@
virtual ~GateKeeperProxy() {
}
- void store_sid(uint32_t uid, uint64_t sid) {
+ void store_sid(uint32_t userId, uint64_t sid) {
char filename[21];
- snprintf(filename, sizeof(filename), "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", userId);
int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
if (fd < 0) {
ALOGE("could not open file: %s: %s", filename, strerror(errno));
@@ -117,18 +117,18 @@
return false;
}
- void maybe_store_sid(uint32_t uid, uint64_t sid) {
+ void maybe_store_sid(uint32_t userId, uint64_t sid) {
char filename[21];
- snprintf(filename, sizeof(filename), "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", userId);
if (access(filename, F_OK) == -1) {
- store_sid(uid, sid);
+ store_sid(userId, sid);
}
}
- uint64_t read_sid(uint32_t uid) {
+ uint64_t read_sid(uint32_t userId) {
char filename[21];
uint64_t sid;
- snprintf(filename, sizeof(filename), "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", userId);
int fd = open(filename, O_RDONLY);
if (fd < 0) return 0;
read(fd, &sid, sizeof(sid));
@@ -136,30 +136,30 @@
return sid;
}
- void clear_sid(uint32_t uid) {
+ void clear_sid(uint32_t userId) {
char filename[21];
- snprintf(filename, sizeof(filename), "%u", uid);
+ snprintf(filename, sizeof(filename), "%u", userId);
if (remove(filename) < 0) {
ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno));
- store_sid(uid, 0);
+ store_sid(userId, 0);
}
}
- // This should only be called on uids being passed to the GateKeeper HAL. It ensures that
+ // This should only be called on userIds being passed to the GateKeeper HAL. It ensures that
// secure storage shared across a GSI image and a host image will not overlap.
- uint32_t adjust_uid(uint32_t uid) {
+ uint32_t adjust_userId(uint32_t userId) {
static constexpr uint32_t kGsiOffset = 1000000;
- CHECK(uid < kGsiOffset);
+ CHECK(userId < kGsiOffset);
CHECK(hw_device != nullptr);
if (is_running_gsi) {
- return uid + kGsiOffset;
+ return userId + kGsiOffset;
}
- return uid;
+ return userId;
}
#define GK_ERROR *gkResponse = GKResponse::error(), Status::ok()
- Status enroll(int32_t uid, const std::optional<std::vector<uint8_t>>& currentPasswordHandle,
+ Status enroll(int32_t userId, const std::optional<std::vector<uint8_t>>& currentPasswordHandle,
const std::optional<std::vector<uint8_t>>& currentPassword,
const std::vector<uint8_t>& desiredPassword, GKResponse* gkResponse) override {
IPCThreadState* ipc = IPCThreadState::self();
@@ -198,9 +198,10 @@
android::hardware::hidl_vec<uint8_t> newPwd;
newPwd.setToExternal(const_cast<uint8_t*>(desiredPassword.data()), desiredPassword.size());
- uint32_t hw_uid = adjust_uid(uid);
+ uint32_t hw_userId = adjust_userId(userId);
Return<void> hwRes = hw_device->enroll(
- hw_uid, curPwdHandle, curPwd, newPwd, [&gkResponse](const GatekeeperResponse& rsp) {
+ hw_userId, curPwdHandle, curPwd, newPwd,
+ [&gkResponse](const GatekeeperResponse& rsp) {
if (rsp.code >= GatekeeperStatusCode::STATUS_OK) {
*gkResponse = GKResponse::ok({rsp.data.begin(), rsp.data.end()});
} else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT &&
@@ -225,12 +226,12 @@
const gatekeeper::password_handle_t* handle =
reinterpret_cast<const gatekeeper::password_handle_t*>(
gkResponse->payload().data());
- store_sid(uid, handle->user_id);
+ store_sid(userId, handle->user_id);
GKResponse verifyResponse;
// immediately verify this password so we don't ask the user to enter it again
// if they just created it.
- auto status = verify(uid, gkResponse->payload(), desiredPassword, &verifyResponse);
+ auto status = verify(userId, gkResponse->payload(), desiredPassword, &verifyResponse);
if (!status.isOk() || verifyResponse.response_code() != GKResponseCode::OK) {
LOG(ERROR) << "Failed to verify password after enrolling";
}
@@ -239,13 +240,13 @@
return Status::ok();
}
- Status verify(int32_t uid, const ::std::vector<uint8_t>& enrolledPasswordHandle,
+ Status verify(int32_t userId, const ::std::vector<uint8_t>& enrolledPasswordHandle,
const ::std::vector<uint8_t>& providedPassword, GKResponse* gkResponse) override {
- return verifyChallenge(uid, 0 /* challenge */, enrolledPasswordHandle, providedPassword,
+ return verifyChallenge(userId, 0 /* challenge */, enrolledPasswordHandle, providedPassword,
gkResponse);
}
- Status verifyChallenge(int32_t uid, int64_t challenge,
+ Status verifyChallenge(int32_t userId, int64_t challenge,
const std::vector<uint8_t>& enrolledPasswordHandle,
const std::vector<uint8_t>& providedPassword,
GKResponse* gkResponse) override {
@@ -269,7 +270,7 @@
reinterpret_cast<const gatekeeper::password_handle_t*>(
enrolledPasswordHandle.data());
- uint32_t hw_uid = adjust_uid(uid);
+ uint32_t hw_userId = adjust_userId(userId);
android::hardware::hidl_vec<uint8_t> curPwdHandle;
curPwdHandle.setToExternal(const_cast<uint8_t*>(enrolledPasswordHandle.data()),
enrolledPasswordHandle.size());
@@ -278,7 +279,7 @@
providedPassword.size());
Return<void> hwRes = hw_device->verify(
- hw_uid, challenge, curPwdHandle, enteredPwd,
+ hw_userId, challenge, curPwdHandle, enteredPwd,
[&gkResponse](const GatekeeperResponse& rsp) {
if (rsp.code >= GatekeeperStatusCode::STATUS_OK) {
*gkResponse = GKResponse::ok(
@@ -315,18 +316,18 @@
}
}
- maybe_store_sid(uid, handle->user_id);
+ maybe_store_sid(userId, handle->user_id);
}
return Status::ok();
}
- Status getSecureUserId(int32_t uid, int64_t* sid) override {
- *sid = read_sid(uid);
+ Status getSecureUserId(int32_t userId, int64_t* sid) override {
+ *sid = read_sid(userId);
return Status::ok();
}
- Status clearSecureUserId(int32_t uid) override {
+ Status clearSecureUserId(int32_t userId) override {
IPCThreadState* ipc = IPCThreadState::self();
const int calling_pid = ipc->getCallingPid();
const int calling_uid = ipc->getCallingUid();
@@ -334,11 +335,11 @@
ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid);
return Status::ok();
}
- clear_sid(uid);
+ clear_sid(userId);
if (hw_device) {
- uint32_t hw_uid = adjust_uid(uid);
- hw_device->deleteUser(hw_uid, [] (const GatekeeperResponse &){});
+ uint32_t hw_userId = adjust_userId(userId);
+ hw_device->deleteUser(hw_userId, [](const GatekeeperResponse&) {});
}
return Status::ok();
}
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 599f500..fd810cb 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -79,7 +79,7 @@
// HIDL enum values are zero initialized, so they need to be initialized
// properly.
- health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNKNOWN;
+ health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNSUPPORTED;
health_info_2_1->batteryChargeTimeToFullNowSeconds =
(int64_t)Constants::BATTERY_CHARGE_TIME_TO_FULL_NOW_SECONDS_UNSUPPORTED;
auto* props = &health_info_2_1->legacy.legacy;
diff --git a/healthd/android.hardware.health@2.0-service.rc b/healthd/android.hardware.health@2.0-service.rc
index 6960c5d..762771e 100644
--- a/healthd/android.hardware.health@2.0-service.rc
+++ b/healthd/android.hardware.health@2.0-service.rc
@@ -2,5 +2,5 @@
class hal
user system
group system
- capabilities WAKE_ALARM
+ capabilities WAKE_ALARM BLOCK_SUSPEND
file /dev/kmsg w
diff --git a/healthd/api/charger_sysprop-current.txt b/healthd/api/charger_sysprop-current.txt
index 678c847..e69de29 100644
--- a/healthd/api/charger_sysprop-current.txt
+++ b/healthd/api/charger_sysprop-current.txt
@@ -1,29 +0,0 @@
-props {
- module: "android.sysprop.ChargerProperties"
- prop {
- api_name: "disable_init_blank"
- scope: Internal
- prop_name: "ro.charger.disable_init_blank"
- }
- prop {
- api_name: "draw_split_offset"
- type: Long
- scope: Internal
- prop_name: "ro.charger.draw_split_offset"
- }
- prop {
- api_name: "draw_split_screen"
- scope: Internal
- prop_name: "ro.charger.draw_split_screen"
- }
- prop {
- api_name: "enable_suspend"
- scope: Internal
- prop_name: "ro.charger.enable_suspend"
- }
- prop {
- api_name: "no_ui"
- scope: Internal
- prop_name: "ro.charger.no_ui"
- }
-}
diff --git a/include/android/log.h b/include/android/log.h
deleted file mode 120000
index 736c448..0000000
--- a/include/android/log.h
+++ /dev/null
@@ -1 +0,0 @@
-../../liblog/include/android/log.h
\ No newline at end of file
diff --git a/include/log b/include/log
deleted file mode 120000
index 714065f..0000000
--- a/include/log
+++ /dev/null
@@ -1 +0,0 @@
-../liblog/include/log
\ No newline at end of file
diff --git a/include/private/android_filesystem_capability.h b/include/private/android_filesystem_capability.h
deleted file mode 120000
index f310b35..0000000
--- a/include/private/android_filesystem_capability.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libcutils/include/private/android_filesystem_capability.h
\ No newline at end of file
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
deleted file mode 120000
index f28a564..0000000
--- a/include/private/android_filesystem_config.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libcutils/include/private/android_filesystem_config.h
\ No newline at end of file
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
deleted file mode 120000
index f187a6d..0000000
--- a/include/private/android_logger.h
+++ /dev/null
@@ -1 +0,0 @@
-../../liblog/include/private/android_logger.h
\ No newline at end of file
diff --git a/include/private/canned_fs_config.h b/include/private/canned_fs_config.h
deleted file mode 120000
index 8f92b2d..0000000
--- a/include/private/canned_fs_config.h
+++ /dev/null
@@ -1 +0,0 @@
-../../libcutils/include/private/canned_fs_config.h
\ No newline at end of file
diff --git a/include/private/fs_config.h b/include/private/fs_config.h
deleted file mode 100644
index e9868a4..0000000
--- a/include/private/fs_config.h
+++ /dev/null
@@ -1,4 +0,0 @@
-// TODO(b/63135587) remove this file after the transitive dependency
-// from private/android_filesystem_config.h is resolved. All files that use
-// libcutils/include/private/fs_config.h should include the file directly, not
-// indirectly via private/android_filesystem_config.h.
diff --git a/include/sysutils b/include/sysutils
deleted file mode 120000
index 1c8e85b..0000000
--- a/include/sysutils
+++ /dev/null
@@ -1 +0,0 @@
-../libsysutils/include/sysutils/
\ No newline at end of file
diff --git a/init/Android.bp b/init/Android.bp
index 3f2cd07..19ba21b0 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -129,6 +129,7 @@
"libprotobuf-cpp-lite",
"libpropertyinfoserializer",
"libpropertyinfoparser",
+ "libsnapshot_cow",
"libsnapshot_init",
"libxml2",
"lib_apex_manifest_proto_lite",
@@ -273,7 +274,6 @@
test_suites: [
"cts",
"device-tests",
- "vts10",
],
}
diff --git a/init/Android.mk b/init/Android.mk
index da94daf..ac31ef1 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -80,6 +80,7 @@
$(TARGET_RAMDISK_OUT)/dev \
$(TARGET_RAMDISK_OUT)/mnt \
$(TARGET_RAMDISK_OUT)/proc \
+ $(TARGET_RAMDISK_OUT)/second_stage_resources \
$(TARGET_RAMDISK_OUT)/sys \
LOCAL_STATIC_LIBRARIES := \
@@ -112,6 +113,7 @@
libmodprobe \
libext2_uuid \
libprotobuf-cpp-lite \
+ libsnapshot_cow \
libsnapshot_init \
update_metadata-protos \
diff --git a/init/README.md b/init/README.md
index c3b64f6..6439393 100644
--- a/init/README.md
+++ b/init/README.md
@@ -31,14 +31,13 @@
extension. There are typically multiple of these in multiple
locations on the system, described below.
-/init.rc is the primary .rc file and is loaded by the init executable
-at the beginning of its execution. It is responsible for the initial
-set up of the system.
+`/system/etc/init/hw/init.rc` is the primary .rc file and is loaded by the init executable at the
+beginning of its execution. It is responsible for the initial set up of the system.
Init loads all of the files contained within the
-/{system,vendor,odm}/etc/init/ directories immediately after loading
-the primary /init.rc. This is explained in more details in the
-Imports section of this file.
+`/{system,system_ext,vendor,odm,product}/etc/init/` directories immediately after loading
+the primary `/system/etc/init/hw/init.rc`. This is explained in more details in the
+[Imports](#imports) section of this file.
Legacy devices without the first stage mount mechanism previously were
able to import init scripts during mount_all, however that is deprecated
@@ -689,29 +688,22 @@
There are only three times where the init executable imports .rc files:
- 1. When it imports /init.rc or the script indicated by the property
+ 1. When it imports `/system/etc/init/hw/init.rc` or the script indicated by the property
`ro.boot.init_rc` during initial boot.
- 2. When it imports /{system,vendor,odm}/etc/init/ for first stage mount
- devices immediately after importing /init.rc.
+ 2. When it imports `/{system,system_ext,vendor,odm,product}/etc/init/` immediately after
+ importing `/system/etc/init/hw/init.rc`.
3. (Deprecated) When it imports /{system,vendor,odm}/etc/init/ or .rc files
at specified paths during mount_all, not allowed for devices launching
after Q.
-The order that files are imported is a bit complex for legacy reasons
-and to keep backwards compatibility. It is not strictly guaranteed.
+The order that files are imported is a bit complex for legacy reasons. The below is guaranteed:
-The only correct way to guarantee that a command has been run before a
-different command is to either 1) place it in an Action with an
-earlier executed trigger, or 2) place it in an Action with the same
-trigger within the same file at an earlier line.
-
-Nonetheless, the de facto order for first stage mount devices is:
-1. /init.rc is parsed then recursively each of its imports are
+1. `/system/etc/init/hw/init.rc` is parsed then recursively each of its imports are
parsed.
-2. The contents of /system/etc/init/ are alphabetized and parsed
- sequentially, with imports happening recursively after each file is
- parsed.
-3. Step 2 is repeated for /vendor/etc/init then /odm/etc/init
+2. The contents of `/system/etc/init/` are alphabetized and parsed sequentially, with imports
+ happening recursively after each file is parsed.
+3. Step 2 is repeated for `/system_ext/etc/init`, `/vendor/etc/init`, `/odm/etc/init`,
+ `/product/etc/init`
The below pseudocode may explain this more clearly:
@@ -720,13 +712,17 @@
for (import : file.imports)
Import(import)
- Import(/init.rc)
- Directories = [/system/etc/init, /vendor/etc/init, /odm/etc/init]
+ Import(/system/etc/init/hw/init.rc)
+ Directories = [/system/etc/init, /system_ext/etc/init, /vendor/etc/init, /odm/etc/init, /product/etc/init]
for (directory : Directories)
files = <Alphabetical order of directory's contents>
for (file : files)
Import(file)
+Actions are executed in the order that they are parsed. For example the `post-fs-data` action(s)
+in `/system/etc/init/hw/init.rc` are always the first `post-fs-data` action(s) to be executed in
+order of how they appear in that file. Then the `post-fs-data` actions of the imports of
+`/system/etc/init/hw/init.rc` in the order that they're imported, etc.
Properties
----------
diff --git a/init/README.ueventd.md b/init/README.ueventd.md
index 053ebf8..4363f3c 100644
--- a/init/README.ueventd.md
+++ b/init/README.ueventd.md
@@ -86,6 +86,8 @@
for a file matching the uevent `FIRMWARE`. It then forks a process to serve this firmware to the
kernel.
+`/apex/*/etc/firmware` is also searched after a list of firmware directories.
+
The list of firmware directories is customized by a `firmware_directories` line in a ueventd.rc
file. This line takes the format of
diff --git a/init/builtins.cpp b/init/builtins.cpp
index f5de1ad..d00d1b1 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -662,18 +662,26 @@
}
}
- auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_all->mode);
+ auto mount_fstab_result = fs_mgr_mount_all(&fstab, mount_all->mode);
SetProperty(prop_name, std::to_string(t.duration().count()));
if (mount_all->import_rc) {
import_late(mount_all->rc_paths);
}
+ if (mount_fstab_result.userdata_mounted) {
+ // This call to fs_mgr_mount_all mounted userdata. Keep the result in
+ // order for userspace reboot to correctly remount userdata.
+ LOG(INFO) << "Userdata mounted using "
+ << (mount_all->fstab_path.empty() ? "(default fstab)" : mount_all->fstab_path)
+ << " result : " << mount_fstab_result.code;
+ initial_mount_fstab_return_code = mount_fstab_result.code;
+ }
+
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
- initial_mount_fstab_return_code = mount_fstab_return_code;
- auto queue_fs_result = queue_fs_event(mount_fstab_return_code, false);
+ auto queue_fs_result = queue_fs_event(mount_fstab_result.code, false);
if (!queue_fs_result.ok()) {
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
}
@@ -1173,6 +1181,10 @@
}
// TODO(b/135984674): check that fstab contains /data.
if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
+ std::string proc_mounts_output;
+ android::base::ReadFileToString("/proc/mounts", &proc_mounts_output, true);
+ android::base::WriteStringToFile(proc_mounts_output,
+ "/metadata/userspacereboot/mount_info.txt");
trigger_shutdown("reboot,mount_userdata_failed");
}
if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result.ok()) {
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index dff7b69..ba7e6bd 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -17,6 +17,7 @@
#include "firmware_handler.h"
#include <fcntl.h>
+#include <glob.h>
#include <pwd.h>
#include <signal.h>
#include <stdlib.h>
@@ -30,6 +31,7 @@
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/scopeguard.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -203,25 +205,28 @@
}
std::vector<std::string> attempted_paths_and_errors;
-
- int booting = IsBooting();
-try_loading_again:
- attempted_paths_and_errors.clear();
- for (const auto& firmware_directory : firmware_directories_) {
+ auto TryLoadFirmware = [&](const std::string& firmware_directory) {
std::string file = firmware_directory + firmware;
unique_fd fw_fd(open(file.c_str(), O_RDONLY | O_CLOEXEC));
if (fw_fd == -1) {
attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
", open failed: " + strerror(errno));
- continue;
+ return false;
}
struct stat sb;
if (fstat(fw_fd, &sb) == -1) {
attempted_paths_and_errors.emplace_back("firmware: attempted " + file +
", fstat failed: " + strerror(errno));
- continue;
+ return false;
}
LoadFirmware(firmware, root, fw_fd, sb.st_size, loading_fd, data_fd);
+ return true;
+ };
+
+ int booting = IsBooting();
+try_loading_again:
+ attempted_paths_and_errors.clear();
+ if (ForEachFirmwareDirectory(TryLoadFirmware)) {
return;
}
@@ -242,6 +247,33 @@
write(loading_fd, "-1", 2);
}
+bool FirmwareHandler::ForEachFirmwareDirectory(
+ std::function<bool(const std::string&)> handler) const {
+ for (const std::string& firmware_directory : firmware_directories_) {
+ if (std::invoke(handler, firmware_directory)) {
+ return true;
+ }
+ }
+
+ glob_t glob_result;
+ glob("/apex/*/etc/firmware/", GLOB_MARK, nullptr, &glob_result);
+ auto free_glob = android::base::make_scope_guard(std::bind(&globfree, &glob_result));
+ for (size_t i = 0; i < glob_result.gl_pathc; i++) {
+ char* apex_firmware_directory = glob_result.gl_pathv[i];
+ // Filter-out /apex/<name>@<ver> paths. The paths are bind-mounted to
+ // /apex/<name> paths, so unless we filter them out, we will look into the
+ // same apex twice.
+ if (strchr(apex_firmware_directory, '@')) {
+ continue;
+ }
+ if (std::invoke(handler, apex_firmware_directory)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void FirmwareHandler::HandleUevent(const Uevent& uevent) {
if (uevent.subsystem != "firmware" || uevent.action != "add") return;
diff --git a/init/firmware_handler.h b/init/firmware_handler.h
index b4138f1..8b758ae 100644
--- a/init/firmware_handler.h
+++ b/init/firmware_handler.h
@@ -18,6 +18,7 @@
#include <pwd.h>
+#include <functional>
#include <string>
#include <vector>
@@ -52,6 +53,7 @@
const Uevent& uevent) const;
std::string GetFirmwarePath(const Uevent& uevent) const;
void ProcessFirmwareEvent(const std::string& root, const std::string& firmware) const;
+ bool ForEachFirmwareDirectory(std::function<bool(const std::string&)> handler) const;
std::vector<std::string> firmware_directories_;
std::vector<ExternalFirmwareHandler> external_firmware_handlers_;
diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp
index 0215576..554f301 100644
--- a/init/first_stage_init.cpp
+++ b/init/first_stage_init.cpp
@@ -41,6 +41,7 @@
#include "first_stage_console.h"
#include "first_stage_mount.h"
#include "reboot_utils.h"
+#include "second_stage_resources.h"
#include "switch_root.h"
#include "util.h"
@@ -235,6 +236,11 @@
// /debug_ramdisk is used to preserve additional files from the debug ramdisk
CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
"mode=0755,uid=0,gid=0"));
+
+ // /second_stage_resources is used to preserve files from first to second
+ // stage init
+ CHECKCALL(mount("tmpfs", kSecondStageRes, "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
+ "mode=0755,uid=0,gid=0"))
#undef CHECKCALL
SetStdioToDevNull(argv);
@@ -276,6 +282,20 @@
StartConsole();
}
+ if (access(kBootImageRamdiskProp, F_OK) == 0) {
+ std::string dest = GetRamdiskPropForSecondStage();
+ std::string dir = android::base::Dirname(dest);
+ std::error_code ec;
+ if (!fs::create_directories(dir, ec)) {
+ LOG(FATAL) << "Can't mkdir " << dir << ": " << ec.message();
+ }
+ if (!fs::copy_file(kBootImageRamdiskProp, dest, ec)) {
+ LOG(FATAL) << "Can't copy " << kBootImageRamdiskProp << " to " << dest << ": "
+ << ec.message();
+ }
+ LOG(INFO) << "Copied ramdisk prop to " << dest;
+ }
+
if (ForceNormalBoot(cmdline)) {
mkdir("/first_stage_ramdisk", 0755);
// SwitchRoot() must be called with a mount point as the target, so we bind mount the
diff --git a/init/init.cpp b/init/init.cpp
index 7d00538..ea04494 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -71,6 +71,7 @@
#include "proto_utils.h"
#include "reboot.h"
#include "reboot_utils.h"
+#include "second_stage_resources.h"
#include "security.h"
#include "selabel.h"
#include "selinux.h"
@@ -668,6 +669,12 @@
}
}
+static void UmountSecondStageRes() {
+ if (umount(kSecondStageRes) != 0) {
+ PLOG(ERROR) << "Failed to umount " << kSecondStageRes;
+ }
+}
+
static void MountExtraFilesystems() {
#define CHECKCALL(x) \
if ((x) != 0) PLOG(FATAL) << #x " failed.";
@@ -776,6 +783,9 @@
PropertyInit();
+ // Umount second stage resources after property service has read the .prop files.
+ UmountSecondStageRes();
+
// Umount the debug ramdisk after property service has read the .prop files when it means to.
if (load_debug_prop) {
UmountDebugRamdisk();
diff --git a/init/mount_handler.cpp b/init/mount_handler.cpp
index 01abba8..46f8331 100644
--- a/init/mount_handler.cpp
+++ b/init/mount_handler.cpp
@@ -130,7 +130,11 @@
char* buf = nullptr;
size_t len = 0;
while (getline(&buf, &len, fp_.get()) != -1) {
- auto entry = ParseMount(std::string(buf));
+ auto buf_string = std::string(buf);
+ if (buf_string.find("/emulated") != std::string::npos) {
+ continue;
+ }
+ auto entry = ParseMount(buf_string);
auto match = untouched.find(entry);
if (match == untouched.end()) {
touched.emplace_back(std::move(entry));
diff --git a/init/property_service.cpp b/init/property_service.cpp
index a1e0969..e71c386 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -67,6 +67,7 @@
#include "persistent_properties.h"
#include "property_type.h"
#include "proto_utils.h"
+#include "second_stage_resources.h"
#include "selinux.h"
#include "subcontext.h"
#include "system/core/init/property_service.pb.h"
@@ -745,6 +746,15 @@
return true;
}
+static void LoadPropertiesFromSecondStageRes(std::map<std::string, std::string>* properties) {
+ std::string prop = GetRamdiskPropForSecondStage();
+ if (access(prop.c_str(), R_OK) != 0) {
+ CHECK(errno == ENOENT) << "Cannot access " << prop << ": " << strerror(errno);
+ return;
+ }
+ load_properties_from_file(prop.c_str(), nullptr, properties);
+}
+
// persist.sys.usb.config values can't be combined on build-time when property
// files are split into each partition.
// So we need to apply the same rule of build/make/tools/post_process_props.py
@@ -860,7 +870,7 @@
build_fingerprint += '/';
build_fingerprint += GetProperty("ro.product.device", UNKNOWN);
build_fingerprint += ':';
- build_fingerprint += GetProperty("ro.build.version.release", UNKNOWN);
+ build_fingerprint += GetProperty("ro.build.version.release_or_codename", UNKNOWN);
build_fingerprint += '/';
build_fingerprint += GetProperty("ro.build.id", UNKNOWN);
build_fingerprint += '/';
@@ -933,6 +943,7 @@
// Order matters here. The more the partition is specific to a product, the higher its
// precedence is.
+ LoadPropertiesFromSecondStageRes(&properties);
load_properties_from_file("/system/build.prop", nullptr, &properties);
load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);
// TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 19e83cc..49baf9e 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -690,9 +690,12 @@
// Reap subcontext pids.
ReapAnyOutstandingChildren();
- // 3. send volume shutdown to vold
+ // 3. send volume abort_fuse and volume shutdown to vold
Service* vold_service = ServiceList::GetInstance().FindService("vold");
if (vold_service != nullptr && vold_service->IsRunning()) {
+ // Manually abort FUSE connections, since the FUSE daemon is already dead
+ // at this point, and unmounting it might hang.
+ CallVdc("volume", "abort_fuse");
CallVdc("volume", "shutdown");
vold_service->Stop();
} else {
@@ -804,11 +807,19 @@
auto sigkill_timeout = GetMillisProperty("init.userspace_reboot.sigkill.timeoutmillis", 10s);
LOG(INFO) << "Timeout to terminate services: " << sigterm_timeout.count() << "ms "
<< "Timeout to kill services: " << sigkill_timeout.count() << "ms";
+ std::string services_file_name = "/metadata/userspacereboot/services.txt";
+ const int flags = O_RDWR | O_CREAT | O_SYNC | O_APPEND | O_CLOEXEC;
StopServicesAndLogViolations(stop_first, sigterm_timeout, true /* SIGTERM */);
if (int r = StopServicesAndLogViolations(stop_first, sigkill_timeout, false /* SIGKILL */);
r > 0) {
+ auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
+ android::base::WriteStringToFd("Post-data services still running: \n", fd);
+ for (const auto& s : stop_first) {
+ if (s->IsRunning()) {
+ android::base::WriteStringToFd(s->name() + "\n", fd);
+ }
+ }
sub_reason = "sigkill";
- // TODO(b/135984674): store information about offending services for debugging.
return Error() << r << " post-data services are still running";
}
if (auto result = KillZramBackingDevice(); !result.ok()) {
@@ -822,8 +833,14 @@
if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */),
sigkill_timeout, false /* SIGKILL */);
r > 0) {
+ auto fd = unique_fd(TEMP_FAILURE_RETRY(open(services_file_name.c_str(), flags, 0666)));
+ android::base::WriteStringToFd("Debugging services still running: \n", fd);
+ for (const auto& s : GetDebuggingServices(true)) {
+ if (s->IsRunning()) {
+ android::base::WriteStringToFd(s->name() + "\n", fd);
+ }
+ }
sub_reason = "sigkill_debug";
- // TODO(b/135984674): store information about offending services for debugging.
return Error() << r << " debugging services are still running";
}
{
diff --git a/init/second_stage_resources.h b/init/second_stage_resources.h
new file mode 100644
index 0000000..544d16f
--- /dev/null
+++ b/init/second_stage_resources.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android {
+namespace init {
+
+constexpr const char kSecondStageRes[] = "/second_stage_resources";
+constexpr const char kBootImageRamdiskProp[] = "/system/etc/ramdisk/build.prop";
+
+inline std::string GetRamdiskPropForSecondStage() {
+ return std::string(kSecondStageRes) + kBootImageRamdiskProp;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 9d4ea8c..dc2455e 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,6 +30,7 @@
#include "action.h"
#include "builtins.h"
+#include "mount_namespace.h"
#include "proto_utils.h"
#include "util.h"
@@ -217,7 +218,13 @@
PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
}
}
-
+#if defined(__ANDROID__)
+ // subcontext init runs in "default" mount namespace
+ // so that it can access /apex/*
+ if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) {
+ LOG(FATAL) << "Could not switch to \"default\" mount namespace: " << result.error();
+ }
+#endif
auto init_path = GetExecutablePath();
auto child_fd_string = std::to_string(child_fd);
const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
diff --git a/init/sysprop/api/com.android.sysprop.init-latest.txt b/init/sysprop/api/com.android.sysprop.init-latest.txt
index c835b95..01f4e9a 100644
--- a/init/sysprop/api/com.android.sysprop.init-latest.txt
+++ b/init/sysprop/api/com.android.sysprop.init-latest.txt
@@ -1,8 +1,13 @@
props {
module: "android.sysprop.InitProperties"
prop {
+ api_name: "is_userspace_reboot_supported"
+ prop_name: "init.userspace_reboot.is_supported"
+ integer_as_bool: true
+ }
+ prop {
api_name: "userspace_reboot_in_progress"
- scope: Public
+ access: ReadWrite
prop_name: "sys.init.userspace_reboot.in_progress"
integer_as_bool: true
}
diff --git a/libbacktrace b/libbacktrace
new file mode 120000
index 0000000..571194c
--- /dev/null
+++ b/libbacktrace
@@ -0,0 +1 @@
+../unwinding/libbacktrace
\ No newline at end of file
diff --git a/libbacktrace/.clang-format b/libbacktrace/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/libbacktrace/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
deleted file mode 100644
index c7969f2..0000000
--- a/libbacktrace/Android.bp
+++ /dev/null
@@ -1,233 +0,0 @@
-//
-// Copyright (C) 2014 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.
-//
-
-cc_defaults {
- name: "libbacktrace_common",
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- target: {
- darwin: {
- enabled: false,
- },
- },
-}
-
-libbacktrace_sources = [
- "Backtrace.cpp",
- "BacktraceCurrent.cpp",
- "BacktracePtrace.cpp",
- "ThreadEntry.cpp",
- "UnwindStack.cpp",
- "UnwindStackMap.cpp",
-]
-
-cc_library_headers {
- name: "libbacktrace_headers",
- vendor_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- export_include_dirs: ["include"],
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
- min_sdk_version: "apex_inherit",
-}
-
-cc_defaults {
- name: "libbacktrace_defaults",
- defaults: ["libbacktrace_common"],
-
- cflags: [
- "-Wexit-time-destructors",
- ],
-
- srcs: [
- "BacktraceMap.cpp",
- ],
-
- export_include_dirs: ["include"],
-
- target: {
- darwin: {
- enabled: true,
- shared_libs: [
- "libbase",
- ],
- },
- linux: {
- srcs: libbacktrace_sources,
-
- shared_libs: [
- "libbase",
- "liblog",
- ],
-
- static_libs: [
- "libprocinfo",
- ],
- },
- android: {
- static_libs: ["libasync_safe"],
- static: {
- whole_static_libs: ["libasync_safe"],
- },
- },
- },
-}
-
-cc_library {
- name: "libbacktrace",
- vendor_available: false,
- // TODO(b/153609531): remove when no longer needed.
- native_bridge_supported: true,
- recovery_available: true,
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
- vndk: {
- enabled: true,
- support_system_process: true,
- },
- host_supported: true,
- defaults: ["libbacktrace_defaults"],
-
- target: {
- linux: {
- shared_libs: [
- "libunwindstack",
- ],
- },
- vendor: {
- cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- },
- recovery: {
- cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- },
- native_bridge: {
- cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- },
- },
-}
-
-// Static library without DEX support to avoid dependencies on the ART APEX.
-cc_library_static {
- name: "libbacktrace_no_dex",
- visibility: [
- "//system/core/debuggerd",
- "//system/core/init",
- ],
- defaults: ["libbacktrace_defaults"],
- cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
- target: {
- linux: {
- static_libs: [
- "libunwindstack_no_dex",
- ],
- },
- },
-}
-
-cc_test_library {
- name: "libbacktrace_test",
- defaults: ["libbacktrace_common"],
- host_supported: true,
- strip: {
- none: true,
- },
- cflags: ["-O0"],
- srcs: ["backtrace_testlib.cpp"],
-
- shared_libs: [
- "libunwindstack",
- ],
- relative_install_path: "backtrace_test_libs",
-
- target: {
- linux_glibc: {
- // This forces the creation of eh_frame with unwind information
- // for host.
- cflags: [
- "-fcxx-exceptions"
- ],
- },
- },
-}
-
-//-------------------------------------------------------------------------
-// The backtrace_test executable.
-//-------------------------------------------------------------------------
-cc_test {
- name: "backtrace_test",
- isolated: true,
- defaults: ["libbacktrace_common"],
- host_supported: true,
- srcs: [
- "backtrace_test.cpp",
- ],
-
- cflags: [
- "-fno-builtin",
- "-O0",
- "-g",
- ],
-
- shared_libs: [
- "libbacktrace",
- "libbase",
- "liblog",
- "libunwindstack",
- ],
-
- group_static_libs: true,
-
- // So that the dlopen can find the libbacktrace_test.so.
- ldflags: [
- "-Wl,--rpath,${ORIGIN}/../backtrace_test_libs",
- ],
-
- test_suites: ["device-tests"],
- data: [
- "testdata/arm/*",
- "testdata/arm64/*",
- "testdata/x86/*",
- "testdata/x86_64/*",
- ],
- required: [
- "libbacktrace_test",
- ],
-}
-
-cc_benchmark {
- name: "backtrace_benchmarks",
- defaults: ["libbacktrace_common"],
-
- srcs: [
- "backtrace_benchmarks.cpp",
- "backtrace_read_benchmarks.cpp",
- ],
-
- shared_libs: [
- "libbacktrace",
- "libbase",
- "libunwindstack",
- ],
-}
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
deleted file mode 100644
index 3e050ab..0000000
--- a/libbacktrace/Backtrace.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2013 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 <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <ucontext.h>
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <android-base/threads.h>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceLog.h"
-#include "UnwindStack.h"
-
-using android::base::StringPrintf;
-
-extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
-
-//-------------------------------------------------------------------------
-// Backtrace functions.
-//-------------------------------------------------------------------------
-Backtrace::Backtrace(pid_t pid, pid_t tid, BacktraceMap* map)
- : pid_(pid), tid_(tid), map_(map), map_shared_(true) {
- if (map_ == nullptr) {
- map_ = BacktraceMap::Create(pid);
- map_shared_ = false;
- }
-}
-
-Backtrace::~Backtrace() {
- if (map_ && !map_shared_) {
- delete map_;
- map_ = nullptr;
- }
-}
-
-std::string Backtrace::GetFunctionName(uint64_t pc, uint64_t* offset, const backtrace_map_t* map) {
- backtrace_map_t map_value;
- if (map == nullptr) {
- FillInMap(pc, &map_value);
- map = &map_value;
- }
- // If no map is found, or this map is backed by a device, then return nothing.
- if (map->start == 0 || (map->flags & PROT_DEVICE_MAP)) {
- return "";
- }
- std::string name(GetFunctionNameRaw(pc, offset));
- char* demangled_name = __cxa_demangle(name.c_str(), nullptr, nullptr, nullptr);
- if (demangled_name != nullptr) {
- name = demangled_name;
- free(demangled_name);
- return name;
- }
- return name;
-}
-
-bool Backtrace::VerifyReadWordArgs(uint64_t ptr, word_t* out_value) {
- if (ptr & (sizeof(word_t)-1)) {
- BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr));
- *out_value = static_cast<word_t>(-1);
- return false;
- }
- return true;
-}
-
-std::string Backtrace::FormatFrameData(size_t frame_num) {
- if (frame_num >= frames_.size()) {
- return "";
- }
- return FormatFrameData(&frames_[frame_num]);
-}
-
-std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
- std::string map_name;
- if (BacktraceMap::IsValid(frame->map)) {
- map_name = frame->map.Name();
- if (!frame->map.name.empty()) {
- if (map_name[0] == '[' && map_name[map_name.size() - 1] == ']') {
- map_name.resize(map_name.size() - 1);
- map_name += StringPrintf(":%" PRIPTR "]", frame->map.start);
- }
- }
- } else {
- map_name = "<unknown>";
- }
-
- std::string line(StringPrintf("#%02zu pc %" PRIPTR " ", frame->num, frame->rel_pc));
- line += map_name;
- // Special handling for non-zero offset maps, we need to print that
- // information.
- if (frame->map.offset != 0) {
- line += " (offset " + StringPrintf("0x%" PRIx64, frame->map.offset) + ")";
- }
- if (!frame->func_name.empty()) {
- line += " (" + frame->func_name;
- if (frame->func_offset) {
- line += StringPrintf("+%" PRIu64, frame->func_offset);
- }
- line += ')';
- }
-
- return line;
-}
-
-void Backtrace::FillInMap(uint64_t pc, backtrace_map_t* map) {
- if (map_ != nullptr) {
- map_->FillIn(pc, map);
- }
-}
-
-Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
- if (pid == BACKTRACE_CURRENT_PROCESS) {
- pid = getpid();
- if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = android::base::GetThreadId();
- }
- } else if (tid == BACKTRACE_CURRENT_THREAD) {
- tid = pid;
- }
-
- if (pid == getpid()) {
- return new UnwindStackCurrent(pid, tid, map);
- } else {
- return new UnwindStackPtrace(pid, tid, map);
- }
-}
-
-std::string Backtrace::GetErrorString(BacktraceUnwindError error) {
- switch (error.error_code) {
- case BACKTRACE_UNWIND_NO_ERROR:
- return "No error";
- case BACKTRACE_UNWIND_ERROR_SETUP_FAILED:
- return "Setup failed";
- case BACKTRACE_UNWIND_ERROR_MAP_MISSING:
- return "No map found";
- case BACKTRACE_UNWIND_ERROR_INTERNAL:
- return "Internal libbacktrace error, please submit a bugreport";
- case BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST:
- return "Thread doesn't exist";
- case BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT:
- return "Thread has not responded to signal in time";
- case BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION:
- return "Attempt to use an unsupported feature";
- case BACKTRACE_UNWIND_ERROR_NO_CONTEXT:
- return "Attempt to do an offline unwind without a context";
- case BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT:
- return "Exceed MAX_BACKTRACE_FRAMES limit";
- case BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED:
- return android::base::StringPrintf("Failed to read memory at addr 0x%" PRIx64,
- error.error_info.addr);
- case BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED:
- return android::base::StringPrintf("Failed to read register %" PRIu64, error.error_info.regno);
- case BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED:
- return "Failed to find a function in debug sections";
- case BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED:
- return "Failed to execute dwarf instructions in debug sections";
- case BACKTRACE_UNWIND_ERROR_UNWIND_INFO:
- return "Failed to unwind due to invalid unwind information";
- case BACKTRACE_UNWIND_ERROR_REPEATED_FRAME:
- return "Failed to unwind due to same sp/pc repeating";
- case BACKTRACE_UNWIND_ERROR_INVALID_ELF:
- return "Failed to unwind due to invalid elf";
- }
-}
diff --git a/libbacktrace/BacktraceAsyncSafeLog.h b/libbacktrace/BacktraceAsyncSafeLog.h
deleted file mode 100644
index 14f51be..0000000
--- a/libbacktrace/BacktraceAsyncSafeLog.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2014 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 _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
-#define _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
-
-#if defined(__ANDROID__)
-
-#include <async_safe/log.h>
-
-// Logging macros for use in signal handler, only available on target.
-#define BACK_ASYNC_SAFE_LOGW(format, ...) \
- async_safe_format_log(ANDROID_LOG_WARN, "libbacktrace", "%s: " format, __PRETTY_FUNCTION__, \
- ##__VA_ARGS__)
-
-#define BACK_ASYNC_SAFE_LOGE(format, ...) \
- async_safe_format_log(ANDROID_LOG_ERROR, "libbacktrace", "%s: " format, __PRETTY_FUNCTION__, \
- ##__VA_ARGS__)
-
-#else
-
-#define BACK_ASYNC_SAFE_LOGW(format, ...)
-
-#define BACK_ASYNC_SAFE_LOGE(format, ...)
-
-#endif
-
-#endif // _LIBBACKTRACE_BACKTRACE_ASYNC_SAFE_LOG_H
diff --git a/libbacktrace/BacktraceCurrent.cpp b/libbacktrace/BacktraceCurrent.cpp
deleted file mode 100644
index 038b59e..0000000
--- a/libbacktrace/BacktraceCurrent.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE 1
-#include <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <stdlib.h>
-
-#include <string>
-
-#include <android-base/threads.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceAsyncSafeLog.h"
-#include "BacktraceCurrent.h"
-#include "ThreadEntry.h"
-
-bool BacktraceCurrent::ReadWord(uint64_t ptr, word_t* out_value) {
- if (!VerifyReadWordArgs(ptr, out_value)) {
- return false;
- }
-
- backtrace_map_t map;
- FillInMap(ptr, &map);
- if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) {
- *out_value = *reinterpret_cast<word_t*>(ptr);
- return true;
- } else {
- BACK_ASYNC_SAFE_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
- *out_value = static_cast<word_t>(-1);
- return false;
- }
-}
-
-size_t BacktraceCurrent::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
- backtrace_map_t map;
- FillInMap(addr, &map);
- if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
- return 0;
- }
- bytes = MIN(map.end - addr, bytes);
- memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes);
- return bytes;
-}
-
-bool BacktraceCurrent::Unwind(size_t num_ignore_frames, void* ucontext) {
- if (GetMap() == nullptr) {
- // Without a map object, we can't do anything.
- error_.error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
- return false;
- }
-
- error_.error_code = BACKTRACE_UNWIND_NO_ERROR;
- if (ucontext) {
- return UnwindFromContext(num_ignore_frames, ucontext);
- }
-
- if (Tid() != static_cast<pid_t>(android::base::GetThreadId())) {
- return UnwindThread(num_ignore_frames);
- }
-
- return UnwindFromContext(num_ignore_frames, nullptr);
-}
-
-bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) {
- if (BacktraceMap::IsValid(frame.map)) {
- const std::string library = basename(frame.map.name.c_str());
- if (library == "libunwind.so" || library == "libbacktrace.so") {
- return true;
- }
- }
- return false;
-}
-
-static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-// Since errno is stored per thread, changing it in the signal handler
-// modifies the value on the thread in which the signal handler executes.
-// If a signal occurs between a call and an errno check, it's possible
-// to get the errno set here. Always save and restore it just in case
-// code would modify it.
-class ErrnoRestorer {
- public:
- ErrnoRestorer() : saved_errno_(errno) {}
- ~ErrnoRestorer() {
- errno = saved_errno_;
- }
-
- private:
- int saved_errno_;
-};
-
-static void SignalLogOnly(int, siginfo_t*, void*) {
- ErrnoRestorer restore;
-
- BACK_ASYNC_SAFE_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(),
- static_cast<int>(android::base::GetThreadId()), THREAD_SIGNAL);
-}
-
-static void SignalHandler(int, siginfo_t*, void* sigcontext) {
- ErrnoRestorer restore;
-
- ThreadEntry* entry = ThreadEntry::Get(getpid(), android::base::GetThreadId(), false);
- if (!entry) {
- BACK_ASYNC_SAFE_LOGE("pid %d, tid %d entry not found", getpid(),
- static_cast<int>(android::base::GetThreadId()));
- return;
- }
-
- entry->CopyUcontextFromSigcontext(sigcontext);
-
- // Indicate the ucontext is now valid.
- entry->Wake();
-
- // Pause the thread until the unwind is complete. This avoids having
- // the thread run ahead causing problems.
- // The number indicates that we are waiting for the second Wake() call
- // overall which is made by the thread requesting an unwind.
- if (entry->Wait(2)) {
- // Do not remove the entry here because that can result in a deadlock
- // if the code cannot properly send a signal to the thread under test.
- entry->Wake();
- } else {
- // At this point, it is possible that entry has been freed, so just exit.
- BACK_ASYNC_SAFE_LOGE("Timed out waiting for unwind thread to indicate it completed.");
- }
-}
-
-bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) {
- // Prevent multiple threads trying to set the trigger action on different
- // threads at the same time.
- pthread_mutex_lock(&g_sigaction_mutex);
-
- ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
- entry->Lock();
-
- struct sigaction act, oldact;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = SignalHandler;
- act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
- sigemptyset(&act.sa_mask);
- if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
- BACK_ASYNC_SAFE_LOGE("sigaction failed: %s", strerror(errno));
- ThreadEntry::Remove(entry);
- pthread_mutex_unlock(&g_sigaction_mutex);
- error_.error_code = BACKTRACE_UNWIND_ERROR_INTERNAL;
- return false;
- }
-
- if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
- // Do not emit an error message, this might be expected. Set the
- // error and let the caller decide.
- if (errno == ESRCH) {
- error_.error_code = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
- } else {
- error_.error_code = BACKTRACE_UNWIND_ERROR_INTERNAL;
- }
-
- sigaction(THREAD_SIGNAL, &oldact, nullptr);
- ThreadEntry::Remove(entry);
- pthread_mutex_unlock(&g_sigaction_mutex);
- return false;
- }
-
- // Wait for the thread to get the ucontext. The number indicates
- // that we are waiting for the first Wake() call made by the thread.
- bool wait_completed = entry->Wait(1);
-
- if (!wait_completed && oldact.sa_sigaction == nullptr) {
- // If the wait failed, it could be that the signal could not be delivered
- // within the timeout. Add a signal handler that's simply going to log
- // something so that we don't crash if the signal eventually gets
- // delivered. Only do this if there isn't already an action set up.
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = SignalLogOnly;
- act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
- sigemptyset(&act.sa_mask);
- sigaction(THREAD_SIGNAL, &act, nullptr);
- } else {
- sigaction(THREAD_SIGNAL, &oldact, nullptr);
- }
- // After the thread has received the signal, allow other unwinders to
- // continue.
- pthread_mutex_unlock(&g_sigaction_mutex);
-
- bool unwind_done = false;
- if (wait_completed) {
- unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext());
-
- // Tell the signal handler to exit and release the entry.
- entry->Wake();
-
- // Wait for the thread to indicate it is done with the ThreadEntry.
- if (!entry->Wait(3)) {
- // Send a warning, but do not mark as a failure to unwind.
- BACK_ASYNC_SAFE_LOGW("Timed out waiting for signal handler to indicate it finished.");
- }
- } else {
- // Check to see if the thread has disappeared.
- if (tgkill(Pid(), Tid(), 0) == -1 && errno == ESRCH) {
- error_.error_code = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
- } else {
- error_.error_code = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT;
- BACK_ASYNC_SAFE_LOGE("Timed out waiting for signal handler to get ucontext data.");
- }
- }
-
- ThreadEntry::Remove(entry);
-
- return unwind_done;
-}
diff --git a/libbacktrace/BacktraceCurrent.h b/libbacktrace/BacktraceCurrent.h
deleted file mode 100644
index 48c14ea..0000000
--- a/libbacktrace/BacktraceCurrent.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_CURRENT_H
-#define _LIBBACKTRACE_BACKTRACE_CURRENT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <backtrace/Backtrace.h>
-
-// The signal used to cause a thread to dump the stack.
-#if defined(__GLIBC__)
-// In order to run the backtrace_tests on the host, we can't use
-// the internal real time signals used by GLIBC. To avoid this,
-// use SIGRTMIN for the signal to dump the stack.
-#define THREAD_SIGNAL SIGRTMIN
-#else
-#define THREAD_SIGNAL (__SIGRTMIN+1)
-#endif
-
-class BacktraceMap;
-
-class BacktraceCurrent : public Backtrace {
- public:
- BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
- virtual ~BacktraceCurrent() {}
-
- size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
-
- bool ReadWord(uint64_t ptr, word_t* out_value) override;
-
- bool Unwind(size_t num_ignore_frames, void* ucontext) override;
-
- protected:
- bool DiscardFrame(const backtrace_frame_data_t& frame);
-
- private:
- bool UnwindThread(size_t num_ignore_frames);
-
- virtual bool UnwindFromContext(size_t num_ignore_frames, void* ucontext) = 0;
-};
-
-#endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H
diff --git a/libbacktrace/BacktraceLog.h b/libbacktrace/BacktraceLog.h
deleted file mode 100644
index 5c39f1c..0000000
--- a/libbacktrace/BacktraceLog.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2014 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 _LIBBACKTRACE_BACKTRACE_LOG_H
-#define _LIBBACKTRACE_BACKTRACE_LOG_H
-
-#define LOG_TAG "libbacktrace"
-
-#include <log/log.h>
-
-// Macro to log the function name along with the warning message.
-#define BACK_LOGW(format, ...) \
- ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
-
-#define BACK_LOGE(format, ...) \
- ALOGE("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
-
-#endif // _LIBBACKTRACE_BACKTRACE_LOG_H
diff --git a/libbacktrace/BacktraceMap.cpp b/libbacktrace/BacktraceMap.cpp
deleted file mode 100644
index 781819a..0000000
--- a/libbacktrace/BacktraceMap.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "backtrace-map"
-
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include <android-base/stringprintf.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-#include <backtrace/backtrace_constants.h>
-#if defined(__linux__)
-#include <procinfo/process_map.h>
-#endif
-
-using android::base::StringPrintf;
-
-std::string backtrace_map_t::Name() const {
- if (!name.empty()) return name;
- if (start == 0 && end == 0) return "";
- return StringPrintf("<anonymous:%" PRIPTR ">", start);
-}
-
-BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
- if (pid_ < 0) {
- pid_ = getpid();
- }
-}
-
-BacktraceMap::~BacktraceMap() {}
-
-void BacktraceMap::FillIn(uint64_t addr, backtrace_map_t* map) {
- ScopedBacktraceMapIteratorLock lock(this);
- for (auto it = begin(); it != end(); ++it) {
- const backtrace_map_t* entry = *it;
- if (addr >= entry->start && addr < entry->end) {
- *map = *entry;
- return;
- }
- }
- *map = {};
-}
-
-#if defined(__APPLE__)
-static bool ParseLine(const char* line, backtrace_map_t* map) {
- uint64_t start;
- uint64_t end;
- char permissions[5];
- int name_pos;
-
- // Mac OS vmmap(1) output:
- // __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW
- // /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
- // 012345678901234567890123456789012345678901234567890123456789
- // 0 1 2 3 4 5
- if (sscanf(line, "%*21c %" SCNx64 "-%" SCNx64 " [%*13c] %3c/%*3c SM=%*3c %n", &start, &end,
- permissions, &name_pos) != 3) {
- return false;
- }
-
- map->start = start;
- map->end = end;
- map->flags = PROT_NONE;
- if (permissions[0] == 'r') {
- map->flags |= PROT_READ;
- }
- if (permissions[1] == 'w') {
- map->flags |= PROT_WRITE;
- }
- if (permissions[2] == 'x') {
- map->flags |= PROT_EXEC;
- }
-
- map->name = line + name_pos;
- if (!map->name.empty() && map->name[map->name.length() - 1] == '\n') {
- map->name.erase(map->name.length() - 1);
- }
-
- ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s", reinterpret_cast<void*>(map->start),
- reinterpret_cast<void*>(map->end), map->flags, map->name.c_str());
- return true;
-}
-#endif // defined(__APPLE__)
-
-bool BacktraceMap::Build() {
-#if defined(__APPLE__)
- char
- cmd[sizeof(pid_t) * 3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
- char line[1024];
- // cmd is guaranteed to always be big enough to hold this string.
- snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
- FILE* fp = popen(cmd, "r");
- if (fp == nullptr) {
- return false;
- }
-
- while (fgets(line, sizeof(line), fp)) {
- backtrace_map_t map;
- if (ParseLine(line, &map)) {
- maps_.push_back(map);
- }
- }
- pclose(fp);
- return true;
-#else
- return android::procinfo::ReadProcessMaps(
- pid_, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t, ino_t, const char* name) {
- maps_.resize(maps_.size() + 1);
- backtrace_map_t& map = maps_.back();
- map.start = start;
- map.end = end;
- map.flags = flags;
- map.name = name;
- });
-#endif
-}
-
-#if defined(__APPLE__)
-// Corkscrew and libunwind don't compile on the mac, so create a generic
-// map object.
-BacktraceMap* BacktraceMap::Create(pid_t pid, bool /*uncached*/) {
- BacktraceMap* map = new BacktraceMap(pid);
- if (!map->Build()) {
- delete map;
- return nullptr;
- }
- return map;
-}
-#endif
diff --git a/libbacktrace/BacktracePtrace.cpp b/libbacktrace/BacktracePtrace.cpp
deleted file mode 100644
index 9da457d..0000000
--- a/libbacktrace/BacktracePtrace.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2013 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 <errno.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include "BacktraceLog.h"
-#include "BacktracePtrace.h"
-
-#if !defined(__APPLE__)
-static bool PtraceRead(pid_t tid, uint64_t addr, word_t* out_value) {
- // ptrace() returns -1 and sets errno when the operation fails.
- // To disambiguate -1 from a valid result, we clear errno beforehand.
- errno = 0;
- *out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr);
- if (*out_value == static_cast<word_t>(-1) && errno) {
- return false;
- }
- return true;
-}
-#endif
-
-bool BacktracePtrace::ReadWord(uint64_t ptr, word_t* out_value) {
-#if defined(__APPLE__)
- BACK_LOGW("MacOS does not support reading from another pid.");
- return false;
-#else
- if (!VerifyReadWordArgs(ptr, out_value)) {
- return false;
- }
-
- backtrace_map_t map;
- FillInMap(ptr, &map);
- if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
- return false;
- }
-
- return PtraceRead(Tid(), ptr, out_value);
-#endif
-}
-
-size_t BacktracePtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
-#if defined(__APPLE__)
- BACK_LOGW("MacOS does not support reading from another pid.");
- return 0;
-#else
- backtrace_map_t map;
- FillInMap(addr, &map);
- if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
- return 0;
- }
-
- bytes = MIN(map.end - addr, bytes);
- size_t bytes_read = 0;
- word_t data_word;
- size_t align_bytes = addr & (sizeof(word_t) - 1);
- if (align_bytes != 0) {
- if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
- return 0;
- }
- size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
- memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
- addr += copy_bytes;
- buffer += copy_bytes;
- bytes -= copy_bytes;
- bytes_read += copy_bytes;
- }
-
- size_t num_words = bytes / sizeof(word_t);
- for (size_t i = 0; i < num_words; i++) {
- if (!PtraceRead(Tid(), addr, &data_word)) {
- return bytes_read;
- }
- memcpy(buffer, &data_word, sizeof(word_t));
- buffer += sizeof(word_t);
- addr += sizeof(word_t);
- bytes_read += sizeof(word_t);
- }
-
- size_t left_over = bytes & (sizeof(word_t) - 1);
- if (left_over) {
- if (!PtraceRead(Tid(), addr, &data_word)) {
- return bytes_read;
- }
- memcpy(buffer, &data_word, left_over);
- bytes_read += left_over;
- }
- return bytes_read;
-#endif
-}
diff --git a/libbacktrace/BacktracePtrace.h b/libbacktrace/BacktracePtrace.h
deleted file mode 100644
index 1ae3adf..0000000
--- a/libbacktrace/BacktracePtrace.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_PTRACE_H
-#define _LIBBACKTRACE_BACKTRACE_PTRACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <backtrace/Backtrace.h>
-
-class BacktraceMap;
-
-class BacktracePtrace : public Backtrace {
- public:
- BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
- virtual ~BacktracePtrace() {}
-
- size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
-
- bool ReadWord(uint64_t ptr, word_t* out_value) override;
-};
-
-#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H
diff --git a/libbacktrace/BacktraceTest.h b/libbacktrace/BacktraceTest.h
deleted file mode 100644
index c38af04..0000000
--- a/libbacktrace/BacktraceTest.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_BACKTRACE_TEST_H
-#define _LIBBACKTRACE_BACKTRACE_TEST_H
-
-#include <dlfcn.h>
-
-#include <gtest/gtest.h>
-
-class BacktraceTest : public ::testing::Test {
- protected:
- static void SetUpTestCase() {
- dl_handle_ = dlopen("libbacktrace_test.so", RTLD_NOW | RTLD_LOCAL);
-
- test_level_one_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
- dlsym(dl_handle_, "test_level_one"));
-
- test_level_two_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
- dlsym(dl_handle_, "test_level_two"));
-
- test_level_three_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
- dlsym(dl_handle_, "test_level_three"));
-
- test_level_four_ = reinterpret_cast<int (*)(int, int, int, int, void (*)(void*), void*)>(
- dlsym(dl_handle_, "test_level_four"));
-
- test_recursive_call_ = reinterpret_cast<int (*)(int, void (*)(void*), void*)>(
- dlsym(dl_handle_, "test_recursive_call"));
-
- test_get_context_and_wait_ = reinterpret_cast<void (*)(void*, volatile int*)>(
- dlsym(dl_handle_, "test_get_context_and_wait"));
-
- test_signal_action_ =
- reinterpret_cast<void (*)(int, siginfo_t*, void*)>(dlsym(dl_handle_, "test_signal_action"));
-
- test_signal_handler_ =
- reinterpret_cast<void (*)(int)>(dlsym(dl_handle_, "test_signal_handler"));
- }
-
- void SetUp() override {
- ASSERT_TRUE(dl_handle_ != nullptr);
- ASSERT_TRUE(test_level_one_ != nullptr);
- ASSERT_TRUE(test_level_two_ != nullptr);
- ASSERT_TRUE(test_level_three_ != nullptr);
- ASSERT_TRUE(test_level_four_ != nullptr);
- ASSERT_TRUE(test_recursive_call_ != nullptr);
- ASSERT_TRUE(test_get_context_and_wait_ != nullptr);
- ASSERT_TRUE(test_signal_action_ != nullptr);
- ASSERT_TRUE(test_signal_handler_ != nullptr);
- }
-
- public:
- static void* dl_handle_;
- static int (*test_level_one_)(int, int, int, int, void (*)(void*), void*);
- static int (*test_level_two_)(int, int, int, int, void (*)(void*), void*);
- static int (*test_level_three_)(int, int, int, int, void (*)(void*), void*);
- static int (*test_level_four_)(int, int, int, int, void (*)(void*), void*);
- static int (*test_recursive_call_)(int, void (*)(void*), void*);
- static void (*test_get_context_and_wait_)(void*, volatile int*);
- static void (*test_signal_action_)(int, siginfo_t*, void*);
- static void (*test_signal_handler_)(int);
-};
-
-#endif // _LIBBACKTRACE_BACKTRACE_TEST_H
diff --git a/libbacktrace/OWNERS b/libbacktrace/OWNERS
deleted file mode 100644
index bfeedca..0000000
--- a/libbacktrace/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-cferris@google.com
-jmgao@google.com
diff --git a/libbacktrace/ThreadEntry.cpp b/libbacktrace/ThreadEntry.cpp
deleted file mode 100644
index 9bd59e4..0000000
--- a/libbacktrace/ThreadEntry.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2015 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 <pthread.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-#include <time.h>
-#include <ucontext.h>
-
-#include "BacktraceAsyncSafeLog.h"
-#include "ThreadEntry.h"
-
-// Initialize static member variables.
-ThreadEntry* ThreadEntry::list_ = nullptr;
-pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
-
-// Assumes that ThreadEntry::list_mutex_ has already been locked before
-// creating a ThreadEntry object.
-ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
- : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER),
- wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0),
- next_(ThreadEntry::list_), prev_(nullptr) {
- pthread_condattr_t attr;
- pthread_condattr_init(&attr);
- pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
- pthread_cond_init(&wait_cond_, &attr);
-
- // Add ourselves to the list.
- if (ThreadEntry::list_) {
- ThreadEntry::list_->prev_ = this;
- }
- ThreadEntry::list_ = this;
-}
-
-ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
- pthread_mutex_lock(&ThreadEntry::list_mutex_);
- ThreadEntry* entry = list_;
- while (entry != nullptr) {
- if (entry->Match(pid, tid)) {
- break;
- }
- entry = entry->next_;
- }
-
- if (!entry) {
- if (create) {
- entry = new ThreadEntry(pid, tid);
- }
- } else {
- entry->ref_count_++;
- }
- pthread_mutex_unlock(&ThreadEntry::list_mutex_);
-
- return entry;
-}
-
-void ThreadEntry::Remove(ThreadEntry* entry) {
- entry->Unlock();
-
- pthread_mutex_lock(&ThreadEntry::list_mutex_);
- if (--entry->ref_count_ == 0) {
- delete entry;
- }
- pthread_mutex_unlock(&ThreadEntry::list_mutex_);
-}
-
-// Assumes that ThreadEntry::list_mutex_ has already been locked before
-// deleting a ThreadEntry object.
-ThreadEntry::~ThreadEntry() {
- if (list_ == this) {
- list_ = next_;
- } else {
- if (next_) {
- next_->prev_ = prev_;
- }
- prev_->next_ = next_;
- }
-
- next_ = nullptr;
- prev_ = nullptr;
-
- pthread_cond_destroy(&wait_cond_);
-}
-
-bool ThreadEntry::Wait(int value) {
- timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- ts.tv_sec += 5;
-
- bool wait_completed = true;
- pthread_mutex_lock(&wait_mutex_);
- while (wait_value_ != value) {
- int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
- if (ret != 0) {
- BACK_ASYNC_SAFE_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
- wait_completed = false;
- break;
- }
- }
- pthread_mutex_unlock(&wait_mutex_);
-
- return wait_completed;
-}
-
-void ThreadEntry::Wake() {
- pthread_mutex_lock(&wait_mutex_);
- wait_value_++;
- pthread_mutex_unlock(&wait_mutex_);
-
- pthread_cond_signal(&wait_cond_);
-}
-
-void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
- ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
- // The only thing the unwinder cares about is the mcontext data.
- memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
-}
diff --git a/libbacktrace/ThreadEntry.h b/libbacktrace/ThreadEntry.h
deleted file mode 100644
index caa5497..0000000
--- a/libbacktrace/ThreadEntry.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2013 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 _LIBBACKTRACE_THREAD_ENTRY_H
-#define _LIBBACKTRACE_THREAD_ENTRY_H
-
-#include <pthread.h>
-#include <sys/types.h>
-#include <ucontext.h>
-
-class ThreadEntry {
- public:
- static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
-
- static void Remove(ThreadEntry* entry);
-
- void Wake();
-
- bool Wait(int);
-
- void CopyUcontextFromSigcontext(void*);
-
- inline void Lock() {
- pthread_mutex_lock(&mutex_);
-
- // Always reset the wait value since this could be the first or nth
- // time this entry is locked.
- wait_value_ = 0;
- }
-
- inline void Unlock() {
- pthread_mutex_unlock(&mutex_);
- }
-
- inline ucontext_t* GetUcontext() { return &ucontext_; }
-
- private:
- ThreadEntry(pid_t pid, pid_t tid);
- ~ThreadEntry();
-
- bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid_ && chk_tid == tid_); }
-
- pid_t pid_;
- pid_t tid_;
- int ref_count_;
- pthread_mutex_t mutex_;
- pthread_mutex_t wait_mutex_;
- pthread_cond_t wait_cond_;
- int wait_value_;
- ThreadEntry* next_;
- ThreadEntry* prev_;
- ucontext_t ucontext_;
-
- static ThreadEntry* list_;
- static pthread_mutex_t list_mutex_;
-};
-
-#endif // _LIBBACKTRACE_THREAD_ENTRY_H
diff --git a/libbacktrace/UnwindMap.cpp b/libbacktrace/UnwindMap.cpp
deleted file mode 100644
index 798c769..0000000
--- a/libbacktrace/UnwindMap.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2014 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 <pthread.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <backtrace/BacktraceMap.h>
-
-#include <libunwind.h>
-
-#include "BacktraceLog.h"
-#include "UnwindMap.h"
-
-//-------------------------------------------------------------------------
-// libunwind has a single shared address space for the current process
-// aka local. If multiple maps are created for the current pid, then
-// only update the local address space once, and keep a reference count
-// of maps using the same map cursor.
-//-------------------------------------------------------------------------
-UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) {
- unw_map_cursor_clear(&map_cursor_);
-}
-
-UnwindMapRemote::UnwindMapRemote(pid_t pid) : UnwindMap(pid) {
-}
-
-UnwindMapRemote::~UnwindMapRemote() {
- unw_map_cursor_destroy(&map_cursor_);
- unw_map_cursor_clear(&map_cursor_);
-}
-
-bool UnwindMapRemote::GenerateMap() {
- // Use the map_cursor information to construct the BacktraceMap data
- // rather than reparsing /proc/self/maps.
- unw_map_cursor_reset(&map_cursor_);
-
- unw_map_t unw_map;
- while (unw_map_cursor_get_next(&map_cursor_, &unw_map)) {
- backtrace_map_t map;
-
- map.start = unw_map.start;
- map.end = unw_map.end;
- map.offset = unw_map.offset;
- map.load_bias = unw_map.load_base;
- map.flags = unw_map.flags;
- map.name = unw_map.path;
-
- // The maps are in descending order, but we want them in ascending order.
- maps_.push_front(map);
- }
-
- return true;
-}
-
-bool UnwindMapRemote::Build() {
- return (unw_map_cursor_create(&map_cursor_, pid_) == 0) && GenerateMap();
-}
-
-UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
- pthread_rwlock_init(&map_lock_, nullptr);
-}
-
-UnwindMapLocal::~UnwindMapLocal() {
- if (map_created_) {
- unw_map_local_destroy();
- unw_map_cursor_clear(&map_cursor_);
- }
-}
-
-bool UnwindMapLocal::GenerateMap() {
- // Lock so that multiple threads cannot modify the maps data at the
- // same time.
- pthread_rwlock_wrlock(&map_lock_);
-
- // It's possible for the map to be regenerated while this loop is occurring.
- // If that happens, get the map again, but only try at most three times
- // before giving up.
- bool generated = false;
- for (int i = 0; i < 3; i++) {
- maps_.clear();
-
- // Save the map data retrieved so we can tell if it changes.
- unw_map_local_cursor_get(&map_cursor_);
-
- unw_map_t unw_map;
- int ret;
- while ((ret = unw_map_local_cursor_get_next(&map_cursor_, &unw_map)) > 0) {
- backtrace_map_t map;
-
- map.start = unw_map.start;
- map.end = unw_map.end;
- map.offset = unw_map.offset;
- map.load_bias = unw_map.load_base;
- map.flags = unw_map.flags;
- map.name = unw_map.path;
-
- free(unw_map.path);
-
- // The maps are in descending order, but we want them in ascending order.
- maps_.push_front(map);
- }
- // Check to see if the map changed while getting the data.
- if (ret != -UNW_EINVAL) {
- generated = true;
- break;
- }
- }
-
- pthread_rwlock_unlock(&map_lock_);
-
- if (!generated) {
- BACK_LOGW("Unable to generate the map.");
- }
- return generated;
-}
-
-bool UnwindMapLocal::Build() {
- return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
-}
-
-void UnwindMapLocal::FillIn(uint64_t addr, backtrace_map_t* map) {
- BacktraceMap::FillIn(addr, map);
- if (!IsValid(*map)) {
- // Check to see if the underlying map changed and regenerate the map
- // if it did.
- if (unw_map_local_cursor_valid(&map_cursor_) < 0) {
- if (GenerateMap()) {
- BacktraceMap::FillIn(addr, map);
- }
- }
- }
-}
diff --git a/libbacktrace/UnwindMap.h b/libbacktrace/UnwindMap.h
deleted file mode 100644
index 15544e8..0000000
--- a/libbacktrace/UnwindMap.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2014 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 _LIBBACKTRACE_UNWIND_MAP_H
-#define _LIBBACKTRACE_UNWIND_MAP_H
-
-#include <pthread.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <backtrace/BacktraceMap.h>
-
-// The unw_map_cursor_t structure is different depending on whether it is
-// the local or remote version. In order to get the correct version, include
-// libunwind.h first then this header.
-
-class UnwindMap : public BacktraceMap {
- public:
- explicit UnwindMap(pid_t pid);
-
- unw_map_cursor_t* GetMapCursor() { return &map_cursor_; }
-
- protected:
- unw_map_cursor_t map_cursor_;
-};
-
-class UnwindMapRemote : public UnwindMap {
- public:
- explicit UnwindMapRemote(pid_t pid);
- virtual ~UnwindMapRemote();
-
- bool Build() override;
-
- private:
- bool GenerateMap();
-};
-
-class UnwindMapLocal : public UnwindMap {
- public:
- UnwindMapLocal();
- virtual ~UnwindMapLocal();
-
- bool Build() override;
-
- void FillIn(uint64_t addr, backtrace_map_t* map) override;
-
- void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
- void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
-
- private:
- bool GenerateMap();
-
- bool map_created_;
-
- pthread_rwlock_t map_lock_;
-};
-
-#endif // _LIBBACKTRACE_UNWIND_MAP_H
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
deleted file mode 100644
index 624711f..0000000
--- a/libbacktrace/UnwindStack.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE 1
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include <backtrace/Backtrace.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#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"
-#include "UnwindStack.h"
-#include "UnwindStackMap.h"
-
-extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
-
-bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
- std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
- std::vector<std::string>* skip_names, BacktraceUnwindError* error) {
- UnwindStackMap* stack_map = reinterpret_cast<UnwindStackMap*>(back_map);
- auto process_memory = stack_map->process_memory();
- unwindstack::Unwinder unwinder(MAX_BACKTRACE_FRAMES + num_ignore_frames, stack_map->stack_maps(),
- 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()) {
- case unwindstack::ERROR_NONE:
- error->error_code = BACKTRACE_UNWIND_NO_ERROR;
- break;
-
- case unwindstack::ERROR_MEMORY_INVALID:
- error->error_code = BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED;
- error->error_info.addr = unwinder.LastErrorAddress();
- break;
-
- case unwindstack::ERROR_UNWIND_INFO:
- error->error_code = BACKTRACE_UNWIND_ERROR_UNWIND_INFO;
- break;
-
- case unwindstack::ERROR_UNSUPPORTED:
- error->error_code = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
- break;
-
- case unwindstack::ERROR_INVALID_MAP:
- error->error_code = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
- break;
-
- case unwindstack::ERROR_MAX_FRAMES_EXCEEDED:
- error->error_code = BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT;
- break;
-
- case unwindstack::ERROR_REPEATED_FRAME:
- error->error_code = BACKTRACE_UNWIND_ERROR_REPEATED_FRAME;
- break;
-
- case unwindstack::ERROR_INVALID_ELF:
- error->error_code = BACKTRACE_UNWIND_ERROR_INVALID_ELF;
- break;
- }
- }
-
- if (num_ignore_frames >= unwinder.NumFrames()) {
- frames->resize(0);
- return true;
- }
-
- auto unwinder_frames = unwinder.frames();
- frames->resize(unwinder.NumFrames() - num_ignore_frames);
- size_t cur_frame = 0;
- for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) {
- auto frame = &unwinder_frames[i];
-
- backtrace_frame_data_t* back_frame = &frames->at(cur_frame);
-
- back_frame->num = cur_frame++;
-
- back_frame->rel_pc = frame->rel_pc;
- back_frame->pc = frame->pc;
- back_frame->sp = frame->sp;
-
- char* demangled_name = __cxa_demangle(frame->function_name.c_str(), nullptr, nullptr, nullptr);
- if (demangled_name != nullptr) {
- back_frame->func_name = demangled_name;
- free(demangled_name);
- } else {
- back_frame->func_name = frame->function_name;
- }
- back_frame->func_offset = frame->function_offset;
-
- back_frame->map.name = frame->map_name;
- back_frame->map.start = frame->map_start;
- back_frame->map.end = frame->map_end;
- back_frame->map.offset = frame->map_elf_start_offset;
- back_frame->map.load_bias = frame->map_load_bias;
- back_frame->map.flags = frame->map_flags;
- }
-
- return true;
-}
-
-UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map)
- : BacktraceCurrent(pid, tid, map) {}
-
-std::string UnwindStackCurrent::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) {
- return GetMap()->GetFunctionName(pc, offset);
-}
-
-bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, void* ucontext) {
- std::unique_ptr<unwindstack::Regs> regs;
- if (ucontext == nullptr) {
- regs.reset(unwindstack::Regs::CreateFromLocal());
- // Fill in the registers from this function. Do it here to avoid
- // one extra function call appearing in the unwind.
- unwindstack::RegsGetLocal(regs.get());
- } else {
- regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
- }
-
- std::vector<std::string> skip_names{"libunwindstack.so", "libbacktrace.so"};
- if (!skip_frames_) {
- skip_names.clear();
- }
- return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, &skip_names, &error_);
-}
-
-UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
- : BacktracePtrace(pid, tid, map), memory_(unwindstack::Memory::CreateProcessMemory(pid)) {}
-
-std::string UnwindStackPtrace::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) {
- return GetMap()->GetFunctionName(pc, offset);
-}
-
-bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, void* context) {
- std::unique_ptr<unwindstack::Regs> regs;
- if (context == nullptr) {
- regs.reset(unwindstack::Regs::RemoteGet(Tid()));
- } else {
- regs.reset(unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), context));
- }
-
- return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_);
-}
-
-size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) {
- return memory_->Read(addr, buffer, bytes);
-}
diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h
deleted file mode 100644
index 47f6757..0000000
--- a/libbacktrace/UnwindStack.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2017 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 _LIBBACKTRACE_UNWIND_STACK_H
-#define _LIBBACKTRACE_UNWIND_STACK_H
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-
-#include <backtrace/BacktraceMap.h>
-#include <unwindstack/Memory.h>
-
-#include "BacktraceCurrent.h"
-#include "BacktracePtrace.h"
-
-class UnwindStackCurrent : public BacktraceCurrent {
- public:
- UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map);
- virtual ~UnwindStackCurrent() = default;
-
- std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
-
- bool UnwindFromContext(size_t num_ignore_frames, void* ucontext) override;
-};
-
-class UnwindStackPtrace : public BacktracePtrace {
- public:
- UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
- virtual ~UnwindStackPtrace() = default;
-
- bool Unwind(size_t num_ignore_frames, void* context) override;
-
- std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override;
-
- size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override;
-
- private:
- std::shared_ptr<unwindstack::Memory> memory_;
-};
-
-#endif // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
deleted file mode 100644
index aa0b17c..0000000
--- a/libbacktrace/UnwindStackMap.cpp
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2017 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 <stdlib.h>
-#include <sys/types.h>
-
-#include <string>
-#include <vector>
-
-#include <backtrace/BacktraceMap.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Regs.h>
-
-#include "UnwindStackMap.h"
-
-//-------------------------------------------------------------------------
-UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {}
-
-bool UnwindStackMap::Build() {
- if (pid_ == 0) {
- pid_ = getpid();
- stack_maps_.reset(new unwindstack::LocalMaps);
- } else {
- stack_maps_.reset(new unwindstack::RemoteMaps(pid_));
- }
-
- // 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;
- }
-
- // Iterate through the maps and fill in the backtrace_map_t structure.
- for (const auto& map_info : *stack_maps_) {
- backtrace_map_t map;
- map.start = map_info->start;
- map.end = map_info->end;
- map.offset = map_info->offset;
- // Set to -1 so that it is demand loaded.
- map.load_bias = static_cast<uint64_t>(-1);
- map.flags = map_info->flags;
- map.name = map_info->name;
-
- maps_.push_back(map);
- }
-
- return true;
-}
-
-void UnwindStackMap::FillIn(uint64_t addr, backtrace_map_t* map) {
- BacktraceMap::FillIn(addr, map);
- if (map->load_bias != static_cast<uint64_t>(-1)) {
- return;
- }
-
- // Fill in the load_bias.
- unwindstack::MapInfo* map_info = stack_maps_->Find(addr);
- if (map_info == nullptr) {
- return;
- }
- map->load_bias = map_info->GetLoadBias(process_memory_);
-}
-
-uint64_t UnwindStackMap::GetLoadBias(size_t index) {
- if (index >= stack_maps_->Total()) {
- return 0;
- }
-
- unwindstack::MapInfo* map_info = stack_maps_->Get(index);
- if (map_info == nullptr) {
- return 0;
- }
- return map_info->GetLoadBias(process_memory_);
-}
-
-std::string UnwindStackMap::GetFunctionName(uint64_t pc, uint64_t* offset) {
- *offset = 0;
- unwindstack::Maps* maps = stack_maps();
-
- // Get the map for this
- unwindstack::MapInfo* map_info = maps->Find(pc);
- if (map_info == nullptr || map_info->flags & PROT_DEVICE_MAP) {
- return "";
- }
-
- if (arch_ == unwindstack::ARCH_UNKNOWN) {
- if (pid_ == getpid()) {
- arch_ = unwindstack::Regs::CurrentArch();
- } else {
- // Create a remote regs, to figure out the architecture.
- std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::RemoteGet(pid_));
- arch_ = regs->Arch();
- }
- }
-
- unwindstack::Elf* elf = map_info->GetElf(process_memory(), arch_);
-
- std::string name;
- uint64_t func_offset;
- if (!elf->GetFunctionName(elf->GetRelPc(pc, map_info), &name, &func_offset)) {
- return "";
- }
- *offset = func_offset;
- return name;
-}
-
-std::shared_ptr<unwindstack::Memory> UnwindStackMap::GetProcessMemory() {
- return process_memory_;
-}
-
-//-------------------------------------------------------------------------
-// BacktraceMap create function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
- BacktraceMap* map;
-
- if (uncached) {
- // Force use of the base class to parse the maps when this call is made.
- map = new BacktraceMap(pid);
- } else if (pid == getpid()) {
- map = new UnwindStackMap(0);
- } else {
- map = new UnwindStackMap(pid);
- }
- if (!map->Build()) {
- delete map;
- return nullptr;
- }
- return map;
-}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
deleted file mode 100644
index f0e7d8b..0000000
--- a/libbacktrace/UnwindStackMap.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2017 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 _LIBBACKTRACE_UNWINDSTACK_MAP_H
-#define _LIBBACKTRACE_UNWINDSTACK_MAP_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-#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>
-#include <unwindstack/Memory.h>
-
-// Forward declarations.
-class UnwindDexFile;
-
-class UnwindStackMap : public BacktraceMap {
- public:
- explicit UnwindStackMap(pid_t pid);
- ~UnwindStackMap() = default;
-
- bool Build() override;
-
- void FillIn(uint64_t addr, backtrace_map_t* map) override;
-
- virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset) override;
- virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() override final;
-
- unwindstack::Maps* stack_maps() { return stack_maps_.get(); }
-
- 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:
- uint64_t GetLoadBias(size_t index) override;
-
- 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;
-};
-
-#endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H
diff --git a/libbacktrace/backtrace_benchmarks.cpp b/libbacktrace/backtrace_benchmarks.cpp
deleted file mode 100644
index a93a25e..0000000
--- a/libbacktrace/backtrace_benchmarks.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (C) 2017 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 <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/threads.h>
-
-#include <benchmark/benchmark.h>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-#include <unwindstack/Memory.h>
-
-constexpr size_t kNumMaps = 2000;
-
-static bool CountMaps(pid_t pid, size_t* num_maps) {
- // Minimize the calls that might allocate memory. If too much memory
- // gets allocated, then this routine will add extra maps and the next
- // call will fail to get the same number of maps as before.
- int fd =
- open((std::string("/proc/") + std::to_string(pid) + "/maps").c_str(), O_RDONLY | O_CLOEXEC);
- if (fd == -1) {
- fprintf(stderr, "Cannot open map file for pid %d: %s\n", pid, strerror(errno));
- return false;
- }
- *num_maps = 0;
- while (true) {
- char buffer[2048];
- ssize_t bytes = read(fd, buffer, sizeof(buffer));
- if (bytes <= 0) {
- break;
- }
- // Count the '\n'.
- for (size_t i = 0; i < static_cast<size_t>(bytes); i++) {
- if (buffer[i] == '\n') {
- ++*num_maps;
- }
- }
- }
-
- close(fd);
- return true;
-}
-
-static void CreateMap(benchmark::State& state, BacktraceMap* (*map_func)(pid_t, bool)) {
- // Create a remote process so that the map data is exactly the same.
- // Also, so that we can create a set number of maps.
- pid_t pid;
- if ((pid = fork()) == 0) {
- size_t num_maps;
- if (!CountMaps(getpid(), &num_maps)) {
- exit(1);
- }
- // Create uniquely named maps.
- std::vector<void*> maps;
- for (size_t i = num_maps; i < kNumMaps; i++) {
- int flags = PROT_READ | PROT_WRITE;
- // Alternate page type to make sure a map entry is added for each call.
- if ((i % 2) == 0) {
- flags |= PROT_EXEC;
- }
- void* memory = mmap(nullptr, PAGE_SIZE, flags, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (memory == MAP_FAILED) {
- fprintf(stderr, "Failed to create map: %s\n", strerror(errno));
- exit(1);
- }
- memset(memory, 0x1, PAGE_SIZE);
-#if defined(PR_SET_VMA)
- if (prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, memory, PAGE_SIZE, "test_map") == -1) {
- fprintf(stderr, "Failed: %s\n", strerror(errno));
- }
-#endif
- maps.push_back(memory);
- }
-
- if (!CountMaps(getpid(), &num_maps)) {
- exit(1);
- }
-
- if (num_maps < kNumMaps) {
- fprintf(stderr, "Maps set incorrectly: %zu found, %zu expected at least.\n", num_maps,
- kNumMaps);
- std::string str;
- android::base::ReadFileToString("/proc/self/maps", &str);
- fprintf(stderr, "%s\n", str.c_str());
- exit(1);
- }
-
- // Wait for an hour at most.
- sleep(3600);
- exit(1);
- } else if (pid < 0) {
- fprintf(stderr, "Fork failed: %s\n", strerror(errno));
- return;
- }
-
- size_t num_maps = 0;
- for (size_t i = 0; i < 2000; i++) {
- if (CountMaps(pid, &num_maps) && num_maps >= kNumMaps) {
- break;
- }
- usleep(1000);
- }
- if (num_maps < kNumMaps) {
- fprintf(stderr, "Timed out waiting for the number of maps available: %zu\n", num_maps);
- return;
- }
-
- while (state.KeepRunning()) {
- BacktraceMap* map = map_func(pid, false);
- if (map == nullptr) {
- fprintf(stderr, "Failed to create map\n");
- return;
- }
- delete map;
- }
-
- kill(pid, SIGKILL);
- waitpid(pid, nullptr, 0);
-}
-
-static void BM_create_map(benchmark::State& state) {
- CreateMap(state, BacktraceMap::Create);
-}
-BENCHMARK(BM_create_map);
-
-using BacktraceCreateFn = decltype(Backtrace::Create);
-
-static void CreateBacktrace(benchmark::State& state, BacktraceMap* map, BacktraceCreateFn fn) {
- while (state.KeepRunning()) {
- std::unique_ptr<Backtrace> backtrace(fn(getpid(), android::base::GetThreadId(), map));
- backtrace->Unwind(0);
- }
-}
-
-static void BM_create_backtrace(benchmark::State& state) {
- std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(getpid()));
- CreateBacktrace(state, backtrace_map.get(), Backtrace::Create);
-}
-BENCHMARK(BM_create_backtrace);
-
-BENCHMARK_MAIN();
diff --git a/libbacktrace/backtrace_read_benchmarks.cpp b/libbacktrace/backtrace_read_benchmarks.cpp
deleted file mode 100644
index 6a688b0..0000000
--- a/libbacktrace/backtrace_read_benchmarks.cpp
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2017 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 <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <memory>
-#include <vector>
-
-#include <benchmark/benchmark.h>
-
-#include <backtrace/Backtrace.h>
-
-#define AT_COMMON_SIZES Arg(1)->Arg(4)->Arg(8)->Arg(16)->Arg(100)->Arg(200)->Arg(500)->Arg(1024)
-
-static void Attach(pid_t pid) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
- perror("Failed to attach");
- abort();
- }
-
- siginfo_t si;
- // Wait for up to 5 seconds.
- for (size_t i = 0; i < 5000; i++) {
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- return;
- }
- usleep(1000);
- }
- printf("Remote process failed to stop in five seconds.\n");
- abort();
-}
-
-class ScopedPidReaper {
- public:
- ScopedPidReaper(pid_t pid) : pid_(pid) {}
- ~ScopedPidReaper() {
- kill(pid_, SIGKILL);
- waitpid(pid_, nullptr, 0);
- }
-
- private:
- pid_t pid_;
-};
-
-static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
- struct iovec dst_iov = {
- .iov_base = dst, .iov_len = len,
- };
-
- struct iovec src_iov = {
- .iov_base = reinterpret_cast<void*>(remote_src), .iov_len = len,
- };
-
- ssize_t rc = process_vm_readv(pid, &dst_iov, 1, &src_iov, 1, 0);
- return rc == -1 ? 0 : rc;
-}
-
-static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
- // ptrace() returns -1 and sets errno when the operation fails.
- // To disambiguate -1 from a valid result, we clear errno beforehand.
- errno = 0;
- *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
- if (*value == -1 && errno) {
- return false;
- }
- return true;
-}
-
-static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
- size_t bytes_read = 0;
- long data;
- for (size_t i = 0; i < bytes / sizeof(long); i++) {
- if (!PtraceReadLong(pid, addr, &data)) {
- return bytes_read;
- }
- memcpy(dst, &data, sizeof(long));
- dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
- addr += sizeof(long);
- bytes_read += sizeof(long);
- }
-
- size_t left_over = bytes & (sizeof(long) - 1);
- if (left_over) {
- if (!PtraceReadLong(pid, addr, &data)) {
- return bytes_read;
- }
- memcpy(dst, &data, left_over);
- bytes_read += left_over;
- }
- return bytes_read;
-}
-
-static void CreateRemoteProcess(size_t size, void** map, pid_t* pid) {
- *map = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (*map == MAP_FAILED) {
- perror("Can't allocate memory");
- abort();
- }
- memset(*map, 0xaa, size);
-
- if ((*pid = fork()) == 0) {
- for (volatile int i = 0;; i++)
- ;
- exit(1);
- }
- if (*pid < 0) {
- perror("Failed to fork");
- abort();
- }
- Attach(*pid);
- // Don't need this map in the current process any more.
- munmap(*map, size);
-}
-
-static void BM_read_with_ptrace(benchmark::State& state) {
- void* map;
- pid_t pid;
- CreateRemoteProcess(state.range(0), &map, &pid);
- ScopedPidReaper reap(pid);
-
- std::vector<uint8_t> read_buffer(state.range(0));
- uint64_t addr = reinterpret_cast<uint64_t>(map);
- while (state.KeepRunning()) {
- if (PtraceRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
- printf("Unexpected bad read.\n");
- abort();
- }
- }
- ptrace(PTRACE_DETACH, pid, 0, 0);
-}
-BENCHMARK(BM_read_with_ptrace)->AT_COMMON_SIZES;
-
-static void BM_read_with_process_vm_read(benchmark::State& state) {
- void* map;
- pid_t pid;
- CreateRemoteProcess(state.range(0), &map, &pid);
- ScopedPidReaper reap(pid);
-
- std::vector<uint8_t> read_buffer(state.range(0));
- uint64_t addr = reinterpret_cast<uint64_t>(map);
- while (state.KeepRunning()) {
- if (ProcessVmRead(pid, addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
- printf("Unexpected bad read.\n");
- abort();
- }
- }
- ptrace(PTRACE_DETACH, pid, 0, 0);
-}
-BENCHMARK(BM_read_with_process_vm_read)->AT_COMMON_SIZES;
-
-static void BM_read_with_backtrace_object(benchmark::State& state) {
- void* map;
- pid_t pid;
- CreateRemoteProcess(state.range(0), &map, &pid);
- ScopedPidReaper reap(pid);
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
- if (backtrace.get() == nullptr) {
- printf("Failed to create backtrace.\n");
- abort();
- }
-
- uint64_t addr = reinterpret_cast<uint64_t>(map);
- std::vector<uint8_t> read_buffer(state.range(0));
- while (state.KeepRunning()) {
- if (backtrace->Read(addr, read_buffer.data(), read_buffer.size()) != read_buffer.size()) {
- printf("Unexpected bad read.\n");
- abort();
- }
- }
- ptrace(PTRACE_DETACH, pid, 0, 0);
-}
-BENCHMARK(BM_read_with_backtrace_object)->AT_COMMON_SIZES;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
deleted file mode 100644
index cc32b6d..0000000
--- a/libbacktrace/backtrace_test.cpp
+++ /dev/null
@@ -1,1893 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE 1
-#include <dirent.h>
-#include <dlfcn.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <malloc.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <time.h>
-#include <ucontext.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <list>
-#include <memory>
-#include <ostream>
-#include <string>
-#include <vector>
-
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
-#include <android-base/threads.h>
-#include <android-base/unique_fd.h>
-#include <cutils/atomic.h>
-
-#include <gtest/gtest.h>
-
-// For the THREAD_SIGNAL definition.
-#include "BacktraceCurrent.h"
-#include "BacktraceTest.h"
-#include "backtrace_testlib.h"
-
-// Number of microseconds per milliseconds.
-#define US_PER_MSEC 1000
-
-// Number of nanoseconds in a second.
-#define NS_PER_SEC 1000000000ULL
-
-// Number of simultaneous dumping operations to perform.
-#define NUM_THREADS 40
-
-// Number of simultaneous threads running in our forked process.
-#define NUM_PTRACE_THREADS 5
-
-// The list of shared libaries that make up the backtrace library.
-static std::vector<std::string> kBacktraceLibs{"libunwindstack.so", "libbacktrace.so"};
-
-struct thread_t {
- pid_t tid;
- int32_t state;
- pthread_t threadId;
- void* data;
-};
-
-struct dump_thread_t {
- thread_t thread;
- BacktraceMap* map;
- Backtrace* backtrace;
- int32_t* now;
- int32_t done;
-};
-
-typedef Backtrace* (*create_func_t)(pid_t, pid_t, BacktraceMap*);
-typedef BacktraceMap* (*map_create_func_t)(pid_t, bool);
-
-static void VerifyLevelDump(Backtrace* backtrace, create_func_t create_func = nullptr,
- map_create_func_t map_func = nullptr);
-static void VerifyMaxDump(Backtrace* backtrace, create_func_t create_func = nullptr,
- map_create_func_t map_func = nullptr);
-
-void* BacktraceTest::dl_handle_;
-int (*BacktraceTest::test_level_one_)(int, int, int, int, void (*)(void*), void*);
-int (*BacktraceTest::test_level_two_)(int, int, int, int, void (*)(void*), void*);
-int (*BacktraceTest::test_level_three_)(int, int, int, int, void (*)(void*), void*);
-int (*BacktraceTest::test_level_four_)(int, int, int, int, void (*)(void*), void*);
-int (*BacktraceTest::test_recursive_call_)(int, void (*)(void*), void*);
-void (*BacktraceTest::test_get_context_and_wait_)(void*, volatile int*);
-void (*BacktraceTest::test_signal_action_)(int, siginfo_t*, void*);
-void (*BacktraceTest::test_signal_handler_)(int);
-
-extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
- static const char* initial_args[] = {"--slow_threshold_ms=8000", "--deadline_threshold_ms=15000"};
- *args = initial_args;
- *num_args = 2;
- return true;
-}
-
-static uint64_t NanoTime() {
- struct timespec t = { 0, 0 };
- clock_gettime(CLOCK_MONOTONIC, &t);
- return static_cast<uint64_t>(t.tv_sec * NS_PER_SEC + t.tv_nsec);
-}
-
-static std::string DumpFrames(Backtrace* backtrace) {
- if (backtrace->NumFrames() == 0) {
- return " No frames to dump.\n";
- }
-
- std::string frame;
- for (size_t i = 0; i < backtrace->NumFrames(); i++) {
- frame += " " + backtrace->FormatFrameData(i) + '\n';
- }
- return frame;
-}
-
-static void WaitForStop(pid_t pid) {
- uint64_t start = NanoTime();
-
- siginfo_t si;
- while (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) < 0 && (errno == EINTR || errno == ESRCH)) {
- if ((NanoTime() - start) > NS_PER_SEC) {
- printf("The process did not get to a stopping point in 1 second.\n");
- break;
- }
- usleep(US_PER_MSEC);
- }
-}
-
-static void CreateRemoteProcess(pid_t* pid) {
- if ((*pid = fork()) == 0) {
- while (true)
- ;
- _exit(0);
- }
- ASSERT_NE(-1, *pid);
-
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, *pid, 0, 0) == 0);
-
- // Wait for the process to get to a stopping point.
- WaitForStop(*pid);
-}
-
-static void FinishRemoteProcess(pid_t pid) {
- ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
-
- kill(pid, SIGKILL);
- ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
-}
-
-#if !defined(__ANDROID__) || defined(__arm__)
-// On host and arm target we aren't guaranteed that we will terminate cleanly.
-#define VERIFY_NO_ERROR(error_code) \
- ASSERT_TRUE(error_code == BACKTRACE_UNWIND_NO_ERROR || \
- error_code == BACKTRACE_UNWIND_ERROR_UNWIND_INFO || \
- error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING) \
- << "Unknown error code " << std::to_string(error_code);
-#else
-#define VERIFY_NO_ERROR(error_code) ASSERT_EQ(BACKTRACE_UNWIND_NO_ERROR, error_code);
-#endif
-
-static bool ReadyLevelBacktrace(Backtrace* backtrace) {
- // See if test_level_four is in the backtrace.
- bool found = false;
- for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
- if (it->func_name == "test_level_four") {
- found = true;
- break;
- }
- }
-
- return found;
-}
-
-static void VerifyLevelDump(Backtrace* backtrace, create_func_t, map_create_func_t) {
- ASSERT_GT(backtrace->NumFrames(), static_cast<size_t>(0))
- << DumpFrames(backtrace);
- ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
- << DumpFrames(backtrace);
-
- // Look through the frames starting at the highest to find the
- // frame we want.
- size_t frame_num = 0;
- for (size_t i = backtrace->NumFrames()-1; i > 2; i--) {
- if (backtrace->GetFrame(i)->func_name == "test_level_one") {
- frame_num = i;
- break;
- }
- }
- ASSERT_LT(static_cast<size_t>(0), frame_num) << DumpFrames(backtrace);
- ASSERT_LE(static_cast<size_t>(3), frame_num) << DumpFrames(backtrace);
-
- ASSERT_EQ(backtrace->GetFrame(frame_num)->func_name, "test_level_one")
- << DumpFrames(backtrace);
- ASSERT_EQ(backtrace->GetFrame(frame_num-1)->func_name, "test_level_two")
- << DumpFrames(backtrace);
- ASSERT_EQ(backtrace->GetFrame(frame_num-2)->func_name, "test_level_three")
- << DumpFrames(backtrace);
- ASSERT_EQ(backtrace->GetFrame(frame_num-3)->func_name, "test_level_four")
- << DumpFrames(backtrace);
-}
-
-static void VerifyLevelBacktrace(void*) {
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
-
- VerifyLevelDump(backtrace.get());
-}
-
-static bool ReadyMaxBacktrace(Backtrace* backtrace) {
- return (backtrace->NumFrames() == MAX_BACKTRACE_FRAMES);
-}
-
-static void VerifyMaxDump(Backtrace* backtrace, create_func_t, map_create_func_t) {
- ASSERT_EQ(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
- << DumpFrames(backtrace);
- // Verify that the last frame is our recursive call.
- ASSERT_EQ(backtrace->GetFrame(MAX_BACKTRACE_FRAMES-1)->func_name, "test_recursive_call")
- << DumpFrames(backtrace);
-}
-
-static void VerifyMaxBacktrace(void*) {
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
-
- VerifyMaxDump(backtrace.get());
-}
-
-static void ThreadSetState(void* data) {
- thread_t* thread = reinterpret_cast<thread_t*>(data);
- android_atomic_acquire_store(1, &thread->state);
- volatile int i = 0;
- while (thread->state) {
- i++;
- }
-}
-
-static bool WaitForNonZero(int32_t* value, uint64_t seconds) {
- uint64_t start = NanoTime();
- do {
- if (android_atomic_acquire_load(value)) {
- return true;
- }
- } while ((NanoTime() - start) < seconds * NS_PER_SEC);
- return false;
-}
-
-TEST_F(BacktraceTest, local_no_unwind_frames) {
- // Verify that a local unwind does not include any frames within
- // libunwind or libbacktrace.
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
-
- ASSERT_TRUE(backtrace->NumFrames() != 0);
- // None of the frames should be in the backtrace libraries.
- for (const auto& frame : *backtrace ) {
- if (BacktraceMap::IsValid(frame.map)) {
- const std::string name = basename(frame.map.name.c_str());
- for (const auto& lib : kBacktraceLibs) {
- ASSERT_TRUE(name != lib) << DumpFrames(backtrace.get());
- }
- }
- }
-}
-
-TEST_F(BacktraceTest, local_unwind_frames) {
- // Verify that a local unwind with the skip frames disabled does include
- // frames within the backtrace libraries.
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), getpid()));
- ASSERT_TRUE(backtrace.get() != nullptr);
- backtrace->SetSkipFrames(false);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
-
- ASSERT_TRUE(backtrace->NumFrames() != 0);
- size_t first_frame_non_backtrace_lib = 0;
- for (const auto& frame : *backtrace) {
- if (BacktraceMap::IsValid(frame.map)) {
- const std::string name = basename(frame.map.name.c_str());
- bool found = false;
- for (const auto& lib : kBacktraceLibs) {
- if (name == lib) {
- found = true;
- break;
- }
- }
- if (!found) {
- first_frame_non_backtrace_lib = frame.num;
- break;
- }
- }
- }
-
- ASSERT_NE(0U, first_frame_non_backtrace_lib) << "No frames found in backtrace libraries:\n"
- << DumpFrames(backtrace.get());
-}
-
-TEST_F(BacktraceTest, local_trace) {
- ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelBacktrace, nullptr), 0);
-}
-
-static void VerifyIgnoreFrames(Backtrace* bt_all, Backtrace* bt_ign1, Backtrace* bt_ign2,
- const char* cur_proc) {
- ASSERT_EQ(bt_all->NumFrames(), bt_ign1->NumFrames() + 1) << "All backtrace:\n"
- << DumpFrames(bt_all)
- << "Ignore 1 backtrace:\n"
- << DumpFrames(bt_ign1);
- ASSERT_EQ(bt_all->NumFrames(), bt_ign2->NumFrames() + 2) << "All backtrace:\n"
- << DumpFrames(bt_all)
- << "Ignore 2 backtrace:\n"
- << DumpFrames(bt_ign2);
-
- // Check all of the frames are the same > the current frame.
- bool check = (cur_proc == nullptr);
- for (size_t i = 0; i < bt_ign2->NumFrames(); i++) {
- if (check) {
- EXPECT_EQ(bt_ign2->GetFrame(i)->pc, bt_ign1->GetFrame(i+1)->pc);
- EXPECT_EQ(bt_ign2->GetFrame(i)->sp, bt_ign1->GetFrame(i+1)->sp);
- EXPECT_EQ(bt_ign2->GetFrame(i)->stack_size, bt_ign1->GetFrame(i+1)->stack_size);
-
- EXPECT_EQ(bt_ign2->GetFrame(i)->pc, bt_all->GetFrame(i+2)->pc);
- EXPECT_EQ(bt_ign2->GetFrame(i)->sp, bt_all->GetFrame(i+2)->sp);
- EXPECT_EQ(bt_ign2->GetFrame(i)->stack_size, bt_all->GetFrame(i+2)->stack_size);
- }
- if (!check && bt_ign2->GetFrame(i)->func_name == cur_proc) {
- check = true;
- }
- }
-}
-
-static void VerifyLevelIgnoreFrames(void*) {
- std::unique_ptr<Backtrace> all(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(all.get() != nullptr);
- ASSERT_TRUE(all->Unwind(0));
- VERIFY_NO_ERROR(all->GetError().error_code);
-
- std::unique_ptr<Backtrace> ign1(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(ign1.get() != nullptr);
- ASSERT_TRUE(ign1->Unwind(1));
- VERIFY_NO_ERROR(ign1->GetError().error_code);
-
- std::unique_ptr<Backtrace> ign2(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(ign2.get() != nullptr);
- ASSERT_TRUE(ign2->Unwind(2));
- VERIFY_NO_ERROR(ign2->GetError().error_code);
-
- VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), "VerifyLevelIgnoreFrames");
-}
-
-TEST_F(BacktraceTest, local_trace_ignore_frames) {
- ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelIgnoreFrames, nullptr), 0);
-}
-
-TEST_F(BacktraceTest, local_max_trace) {
- ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxBacktrace, nullptr), 0);
-}
-
-static void VerifyProcTest(pid_t pid, pid_t tid, bool (*ReadyFunc)(Backtrace*),
- void (*VerifyFunc)(Backtrace*, create_func_t, map_create_func_t),
- create_func_t create_func, map_create_func_t map_create_func) {
- pid_t ptrace_tid;
- if (tid < 0) {
- ptrace_tid = pid;
- } else {
- ptrace_tid = tid;
- }
- uint64_t start = NanoTime();
- bool verified = false;
- std::string last_dump;
- do {
- usleep(US_PER_MSEC);
- if (ptrace(PTRACE_ATTACH, ptrace_tid, 0, 0) == 0) {
- // Wait for the process to get to a stopping point.
- WaitForStop(ptrace_tid);
-
- std::unique_ptr<BacktraceMap> map;
- map.reset(map_create_func(pid, false));
- std::unique_ptr<Backtrace> backtrace(create_func(pid, tid, map.get()));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- if (ReadyFunc(backtrace.get())) {
- VerifyFunc(backtrace.get(), create_func, map_create_func);
- verified = true;
- } else {
- last_dump = DumpFrames(backtrace.get());
- }
-
- ASSERT_TRUE(ptrace(PTRACE_DETACH, ptrace_tid, 0, 0) == 0);
- }
- // If 5 seconds have passed, then we are done.
- } while (!verified && (NanoTime() - start) <= 5 * NS_PER_SEC);
- ASSERT_TRUE(verified) << "Last backtrace:\n" << last_dump;
-}
-
-TEST_F(BacktraceTest, ptrace_trace) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
- _exit(1);
- }
- VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyLevelDump,
- Backtrace::Create, BacktraceMap::Create);
-
- kill(pid, SIGKILL);
- int status;
- ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
-TEST_F(BacktraceTest, ptrace_max_trace) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, nullptr, nullptr), 0);
- _exit(1);
- }
- VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyMaxBacktrace, VerifyMaxDump, Backtrace::Create,
- BacktraceMap::Create);
-
- kill(pid, SIGKILL);
- int status;
- ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
-static void VerifyProcessIgnoreFrames(Backtrace* bt_all, create_func_t create_func,
- map_create_func_t map_create_func) {
- std::unique_ptr<BacktraceMap> map(map_create_func(bt_all->Pid(), false));
- std::unique_ptr<Backtrace> ign1(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
- ASSERT_TRUE(ign1.get() != nullptr);
- ASSERT_TRUE(ign1->Unwind(1));
- VERIFY_NO_ERROR(ign1->GetError().error_code);
-
- std::unique_ptr<Backtrace> ign2(create_func(bt_all->Pid(), BACKTRACE_CURRENT_THREAD, map.get()));
- ASSERT_TRUE(ign2.get() != nullptr);
- ASSERT_TRUE(ign2->Unwind(2));
- VERIFY_NO_ERROR(ign2->GetError().error_code);
-
- VerifyIgnoreFrames(bt_all, ign1.get(), ign2.get(), nullptr);
-}
-
-TEST_F(BacktraceTest, ptrace_ignore_frames) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
- _exit(1);
- }
- VerifyProcTest(pid, BACKTRACE_CURRENT_THREAD, ReadyLevelBacktrace, VerifyProcessIgnoreFrames,
- Backtrace::Create, BacktraceMap::Create);
-
- kill(pid, SIGKILL);
- int status;
- ASSERT_EQ(waitpid(pid, &status, 0), pid);
-}
-
-// Create a process with multiple threads and dump all of the threads.
-static void* PtraceThreadLevelRun(void*) {
- EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
- return nullptr;
-}
-
-static void GetThreads(pid_t pid, std::vector<pid_t>* threads) {
- // Get the list of tasks.
- char task_path[128];
- snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);
-
- std::unique_ptr<DIR, decltype(&closedir)> tasks_dir(opendir(task_path), closedir);
- ASSERT_TRUE(tasks_dir != nullptr);
- struct dirent* entry;
- while ((entry = readdir(tasks_dir.get())) != nullptr) {
- char* end;
- pid_t tid = strtoul(entry->d_name, &end, 10);
- if (*end == '\0') {
- threads->push_back(tid);
- }
- }
-}
-
-TEST_F(BacktraceTest, ptrace_threads) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- for (size_t i = 0; i < NUM_PTRACE_THREADS; i++) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- pthread_t thread;
- ASSERT_TRUE(pthread_create(&thread, &attr, PtraceThreadLevelRun, nullptr) == 0);
- }
- ASSERT_NE(test_level_one_(1, 2, 3, 4, nullptr, nullptr), 0);
- _exit(1);
- }
-
- // Check to see that all of the threads are running before unwinding.
- std::vector<pid_t> threads;
- uint64_t start = NanoTime();
- do {
- usleep(US_PER_MSEC);
- threads.clear();
- GetThreads(pid, &threads);
- } while ((threads.size() != NUM_PTRACE_THREADS + 1) &&
- ((NanoTime() - start) <= 5 * NS_PER_SEC));
- ASSERT_EQ(threads.size(), static_cast<size_t>(NUM_PTRACE_THREADS + 1));
-
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
- WaitForStop(pid);
- for (std::vector<int>::const_iterator it = threads.begin(); it != threads.end(); ++it) {
- // Skip the current forked process, we only care about the threads.
- if (pid == *it) {
- continue;
- }
- VerifyProcTest(pid, *it, ReadyLevelBacktrace, VerifyLevelDump, Backtrace::Create,
- BacktraceMap::Create);
- }
-
- FinishRemoteProcess(pid);
-}
-
-void VerifyLevelThread(void*) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), android::base::GetThreadId()));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
-
- VerifyLevelDump(backtrace.get());
-}
-
-TEST_F(BacktraceTest, thread_current_level) {
- ASSERT_NE(test_level_one_(1, 2, 3, 4, VerifyLevelThread, nullptr), 0);
-}
-
-static void VerifyMaxThread(void*) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), android::base::GetThreadId()));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
-
- VerifyMaxDump(backtrace.get());
-}
-
-TEST_F(BacktraceTest, thread_current_max) {
- ASSERT_NE(test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, VerifyMaxThread, nullptr), 0);
-}
-
-static void* ThreadLevelRun(void* data) {
- thread_t* thread = reinterpret_cast<thread_t*>(data);
-
- thread->tid = android::base::GetThreadId();
- EXPECT_NE(BacktraceTest::test_level_one_(1, 2, 3, 4, ThreadSetState, data), 0);
- return nullptr;
-}
-
-TEST_F(BacktraceTest, thread_level_trace) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- thread_t thread_data = { 0, 0, 0, nullptr };
- pthread_t thread;
- ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
-
- // Wait up to 2 seconds for the tid to be set.
- ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
-
- // Make sure that the thread signal used is not visible when compiled for
- // the target.
-#if !defined(__GLIBC__)
- ASSERT_LT(THREAD_SIGNAL, SIGRTMIN);
-#endif
-
- // Save the current signal action and make sure it is restored afterwards.
- struct sigaction cur_action;
- ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &cur_action) == 0);
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
-
- VerifyLevelDump(backtrace.get());
-
- // Tell the thread to exit its infinite loop.
- android_atomic_acquire_store(0, &thread_data.state);
-
- // Verify that the old action was restored.
- struct sigaction new_action;
- ASSERT_TRUE(sigaction(THREAD_SIGNAL, nullptr, &new_action) == 0);
- EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction);
- // The SA_RESTORER flag gets set behind our back, so a direct comparison
- // doesn't work unless we mask the value off. Mips doesn't have this
- // flag, so skip this on that platform.
-#if defined(SA_RESTORER)
- cur_action.sa_flags &= ~SA_RESTORER;
- new_action.sa_flags &= ~SA_RESTORER;
-#elif defined(__GLIBC__)
- // Our host compiler doesn't appear to define this flag for some reason.
- cur_action.sa_flags &= ~0x04000000;
- new_action.sa_flags &= ~0x04000000;
-#endif
- EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags);
-}
-
-TEST_F(BacktraceTest, thread_ignore_frames) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- thread_t thread_data = { 0, 0, 0, nullptr };
- pthread_t thread;
- ASSERT_TRUE(pthread_create(&thread, &attr, ThreadLevelRun, &thread_data) == 0);
-
- // Wait up to 2 seconds for the tid to be set.
- ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
-
- std::unique_ptr<Backtrace> all(Backtrace::Create(getpid(), thread_data.tid));
- ASSERT_TRUE(all.get() != nullptr);
- ASSERT_TRUE(all->Unwind(0));
- VERIFY_NO_ERROR(all->GetError().error_code);
-
- std::unique_ptr<Backtrace> ign1(Backtrace::Create(getpid(), thread_data.tid));
- ASSERT_TRUE(ign1.get() != nullptr);
- ASSERT_TRUE(ign1->Unwind(1));
- VERIFY_NO_ERROR(ign1->GetError().error_code);
-
- std::unique_ptr<Backtrace> ign2(Backtrace::Create(getpid(), thread_data.tid));
- ASSERT_TRUE(ign2.get() != nullptr);
- ASSERT_TRUE(ign2->Unwind(2));
- VERIFY_NO_ERROR(ign2->GetError().error_code);
-
- VerifyIgnoreFrames(all.get(), ign1.get(), ign2.get(), nullptr);
-
- // Tell the thread to exit its infinite loop.
- android_atomic_acquire_store(0, &thread_data.state);
-}
-
-static void* ThreadMaxRun(void* data) {
- thread_t* thread = reinterpret_cast<thread_t*>(data);
-
- thread->tid = android::base::GetThreadId();
- EXPECT_NE(BacktraceTest::test_recursive_call_(MAX_BACKTRACE_FRAMES + 10, ThreadSetState, data),
- 0);
- return nullptr;
-}
-
-TEST_F(BacktraceTest, thread_max_trace) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- thread_t thread_data = { 0, 0, 0, nullptr };
- pthread_t thread;
- ASSERT_TRUE(pthread_create(&thread, &attr, ThreadMaxRun, &thread_data) == 0);
-
- // Wait for the tid to be set.
- ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT, backtrace->GetError().error_code);
-
- VerifyMaxDump(backtrace.get());
-
- // Tell the thread to exit its infinite loop.
- android_atomic_acquire_store(0, &thread_data.state);
-}
-
-static void* ThreadDump(void* data) {
- dump_thread_t* dump = reinterpret_cast<dump_thread_t*>(data);
- while (true) {
- if (android_atomic_acquire_load(dump->now)) {
- break;
- }
- }
-
- // The status of the actual unwind will be checked elsewhere.
- dump->backtrace = Backtrace::Create(getpid(), dump->thread.tid, dump->map);
- dump->backtrace->Unwind(0);
-
- android_atomic_acquire_store(1, &dump->done);
-
- return nullptr;
-}
-
-static void MultipleThreadDumpTest(bool share_map) {
- // Dump NUM_THREADS simultaneously using the same map.
- std::vector<thread_t> runners(NUM_THREADS);
- std::vector<dump_thread_t> dumpers(NUM_THREADS);
-
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- for (size_t i = 0; i < NUM_THREADS; i++) {
- // Launch the runners, they will spin in hard loops doing nothing.
- runners[i].tid = 0;
- runners[i].state = 0;
- ASSERT_TRUE(pthread_create(&runners[i].threadId, &attr, ThreadMaxRun, &runners[i]) == 0);
- }
-
- // Wait for tids to be set.
- for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) {
- ASSERT_TRUE(WaitForNonZero(&it->state, 30));
- }
-
- // Start all of the dumpers at once, they will spin until they are signalled
- // to begin their dump run.
- std::unique_ptr<BacktraceMap> map;
- if (share_map) {
- map.reset(BacktraceMap::Create(getpid()));
- }
- int32_t dump_now = 0;
- for (size_t i = 0; i < NUM_THREADS; i++) {
- dumpers[i].thread.tid = runners[i].tid;
- dumpers[i].thread.state = 0;
- dumpers[i].done = 0;
- dumpers[i].now = &dump_now;
- dumpers[i].map = map.get();
-
- ASSERT_TRUE(pthread_create(&dumpers[i].thread.threadId, &attr, ThreadDump, &dumpers[i]) == 0);
- }
-
- // Start all of the dumpers going at once.
- android_atomic_acquire_store(1, &dump_now);
-
- for (size_t i = 0; i < NUM_THREADS; i++) {
- ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30));
-
- // Tell the runner thread to exit its infinite loop.
- android_atomic_acquire_store(0, &runners[i].state);
-
- ASSERT_TRUE(dumpers[i].backtrace != nullptr);
- VerifyMaxDump(dumpers[i].backtrace);
-
- delete dumpers[i].backtrace;
- dumpers[i].backtrace = nullptr;
- }
-}
-
-TEST_F(BacktraceTest, thread_multiple_dump) {
- MultipleThreadDumpTest(false);
-}
-
-TEST_F(BacktraceTest, thread_multiple_dump_same_map) {
- MultipleThreadDumpTest(true);
-}
-
-// This test is for UnwindMaps that should share the same map cursor when
-// multiple maps are created for the current process at the same time.
-TEST_F(BacktraceTest, simultaneous_maps) {
- BacktraceMap* map1 = BacktraceMap::Create(getpid());
- BacktraceMap* map2 = BacktraceMap::Create(getpid());
- BacktraceMap* map3 = BacktraceMap::Create(getpid());
-
- Backtrace* back1 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map1);
- ASSERT_TRUE(back1 != nullptr);
- EXPECT_TRUE(back1->Unwind(0));
- VERIFY_NO_ERROR(back1->GetError().error_code);
- delete back1;
- delete map1;
-
- Backtrace* back2 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map2);
- ASSERT_TRUE(back2 != nullptr);
- EXPECT_TRUE(back2->Unwind(0));
- VERIFY_NO_ERROR(back2->GetError().error_code);
- delete back2;
- delete map2;
-
- Backtrace* back3 = Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD, map3);
- ASSERT_TRUE(back3 != nullptr);
- EXPECT_TRUE(back3->Unwind(0));
- VERIFY_NO_ERROR(back3->GetError().error_code);
- delete back3;
- delete map3;
-}
-
-TEST_F(BacktraceTest, fillin_erases) {
- BacktraceMap* back_map = BacktraceMap::Create(getpid());
-
- backtrace_map_t map;
-
- map.start = 1;
- map.end = 3;
- map.flags = 1;
- map.name = "Initialized";
- back_map->FillIn(0, &map);
- delete back_map;
-
- ASSERT_FALSE(BacktraceMap::IsValid(map));
- ASSERT_EQ(static_cast<uint64_t>(0), map.start);
- ASSERT_EQ(static_cast<uint64_t>(0), map.end);
- ASSERT_EQ(0, map.flags);
- ASSERT_EQ("", map.name);
-}
-
-TEST_F(BacktraceTest, format_test) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
-
- backtrace_frame_data_t frame;
- frame.num = 1;
- frame.pc = 2;
- frame.rel_pc = 2;
- frame.sp = 0;
- frame.stack_size = 0;
- frame.func_offset = 0;
-
- // Check no map set.
- frame.num = 1;
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 0000000000000002 <unknown>",
-#else
- EXPECT_EQ("#01 pc 00000002 <unknown>",
-#endif
- backtrace->FormatFrameData(&frame));
-
- // Check map name empty, but exists.
- frame.pc = 0xb0020;
- frame.rel_pc = 0x20;
- frame.map.start = 0xb0000;
- frame.map.end = 0xbffff;
- frame.map.load_bias = 0;
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 0000000000000020 <anonymous:00000000000b0000>",
-#else
- EXPECT_EQ("#01 pc 00000020 <anonymous:000b0000>",
-#endif
- backtrace->FormatFrameData(&frame));
-
- // Check map name begins with a [.
- frame.pc = 0xc0020;
- frame.map.start = 0xc0000;
- frame.map.end = 0xcffff;
- frame.map.load_bias = 0;
- frame.map.name = "[anon:thread signal stack]";
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 0000000000000020 [anon:thread signal stack:00000000000c0000]",
-#else
- EXPECT_EQ("#01 pc 00000020 [anon:thread signal stack:000c0000]",
-#endif
- backtrace->FormatFrameData(&frame));
-
- // Check relative pc is set and map name is set.
- frame.pc = 0x12345679;
- frame.rel_pc = 0x12345678;
- frame.map.name = "MapFake";
- frame.map.start = 1;
- frame.map.end = 1;
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 0000000012345678 MapFake",
-#else
- EXPECT_EQ("#01 pc 12345678 MapFake",
-#endif
- backtrace->FormatFrameData(&frame));
-
- // Check func_name is set, but no func offset.
- frame.func_name = "ProcFake";
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 0000000012345678 MapFake (ProcFake)",
-#else
- EXPECT_EQ("#01 pc 12345678 MapFake (ProcFake)",
-#endif
- backtrace->FormatFrameData(&frame));
-
- // Check func_name is set, and func offset is non-zero.
- frame.func_offset = 645;
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 0000000012345678 MapFake (ProcFake+645)",
-#else
- EXPECT_EQ("#01 pc 12345678 MapFake (ProcFake+645)",
-#endif
- backtrace->FormatFrameData(&frame));
-
- // Check func_name is set, func offset is non-zero, and load_bias is non-zero.
- frame.rel_pc = 0x123456dc;
- frame.func_offset = 645;
- frame.map.load_bias = 100;
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 00000000123456dc MapFake (ProcFake+645)",
-#else
- EXPECT_EQ("#01 pc 123456dc MapFake (ProcFake+645)",
-#endif
- backtrace->FormatFrameData(&frame));
-
- // Check a non-zero map offset.
- frame.map.offset = 0x1000;
-#if defined(__LP64__)
- EXPECT_EQ("#01 pc 00000000123456dc MapFake (offset 0x1000) (ProcFake+645)",
-#else
- EXPECT_EQ("#01 pc 123456dc MapFake (offset 0x1000) (ProcFake+645)",
-#endif
- backtrace->FormatFrameData(&frame));
-}
-
-struct map_test_t {
- uint64_t start;
- uint64_t end;
-};
-
-static bool map_sort(map_test_t i, map_test_t j) { return i.start < j.start; }
-
-static std::string GetTestMapsAsString(const std::vector<map_test_t>& maps) {
- if (maps.size() == 0) {
- return "No test map entries\n";
- }
- std::string map_txt;
- for (auto map : maps) {
- map_txt += android::base::StringPrintf("%" PRIx64 "-%" PRIx64 "\n", map.start, map.end);
- }
- return map_txt;
-}
-
-static std::string GetMapsAsString(BacktraceMap* maps) {
- if (maps->size() == 0) {
- return "No map entries\n";
- }
- std::string map_txt;
- for (const backtrace_map_t* map : *maps) {
- map_txt += android::base::StringPrintf(
- "%" PRIx64 "-%" PRIx64 " flags: 0x%x offset: 0x%" PRIx64 " load_bias: 0x%" PRIx64,
- map->start, map->end, map->flags, map->offset, map->load_bias);
- if (!map->name.empty()) {
- map_txt += ' ' + map->name;
- }
- map_txt += '\n';
- }
- return map_txt;
-}
-
-static void VerifyMap(pid_t pid) {
- char buffer[4096];
- snprintf(buffer, sizeof(buffer), "/proc/%d/maps", pid);
-
- FILE* map_file = fopen(buffer, "r");
- ASSERT_TRUE(map_file != nullptr);
- std::vector<map_test_t> test_maps;
- while (fgets(buffer, sizeof(buffer), map_file)) {
- map_test_t map;
- ASSERT_EQ(2, sscanf(buffer, "%" SCNx64 "-%" SCNx64 " ", &map.start, &map.end));
- test_maps.push_back(map);
- }
- fclose(map_file);
- std::sort(test_maps.begin(), test_maps.end(), map_sort);
-
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
-
- // Basic test that verifies that the map is in the expected order.
- auto test_it = test_maps.begin();
- for (auto it = map->begin(); it != map->end(); ++it) {
- ASSERT_TRUE(test_it != test_maps.end()) << "Mismatch in number of maps, expected test maps:\n"
- << GetTestMapsAsString(test_maps) << "Actual maps:\n"
- << GetMapsAsString(map.get());
- ASSERT_EQ(test_it->start, (*it)->start) << "Mismatch in map data, expected test maps:\n"
- << GetTestMapsAsString(test_maps) << "Actual maps:\n"
- << GetMapsAsString(map.get());
- ASSERT_EQ(test_it->end, (*it)->end) << "Mismatch maps in map data, expected test maps:\n"
- << GetTestMapsAsString(test_maps) << "Actual maps:\n"
- << GetMapsAsString(map.get());
- // Make sure the load bias get set to a value.
- ASSERT_NE(static_cast<uint64_t>(-1), (*it)->load_bias) << "Found uninitialized load_bias\n"
- << GetMapsAsString(map.get());
- ++test_it;
- }
- ASSERT_TRUE(test_it == test_maps.end());
-}
-
-TEST_F(BacktraceTest, verify_map_remote) {
- pid_t pid;
- CreateRemoteProcess(&pid);
-
- // The maps should match exactly since the forked process has been paused.
- VerifyMap(pid);
-
- FinishRemoteProcess(pid);
-}
-
-static void InitMemory(uint8_t* memory, size_t bytes) {
- for (size_t i = 0; i < bytes; i++) {
- memory[i] = i;
- if (memory[i] == '\0') {
- // Don't use '\0' in our data so we can verify that an overread doesn't
- // occur by using a '\0' as the character after the read data.
- memory[i] = 23;
- }
- }
-}
-
-static void* ThreadReadTest(void* data) {
- thread_t* thread_data = reinterpret_cast<thread_t*>(data);
-
- thread_data->tid = android::base::GetThreadId();
-
- // Create two map pages.
- // Mark the second page as not-readable.
- size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
- uint8_t* memory;
- if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) {
- return reinterpret_cast<void*>(-1);
- }
-
- if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
- return reinterpret_cast<void*>(-1);
- }
-
- // Set up a simple pattern in memory.
- InitMemory(memory, pagesize);
-
- thread_data->data = memory;
-
- // Tell the caller it's okay to start reading memory.
- android_atomic_acquire_store(1, &thread_data->state);
-
- // Loop waiting for the caller to finish reading the memory.
- while (thread_data->state) {
- }
-
- // Re-enable read-write on the page so that we don't crash if we try
- // and access data on this page when freeing the memory.
- if (mprotect(&memory[pagesize], pagesize, PROT_READ | PROT_WRITE) != 0) {
- return reinterpret_cast<void*>(-1);
- }
- free(memory);
-
- android_atomic_acquire_store(1, &thread_data->state);
-
- return nullptr;
-}
-
-static void RunReadTest(Backtrace* backtrace, uint64_t read_addr) {
- size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
-
- // Create a page of data to use to do quick compares.
- uint8_t* expected = new uint8_t[pagesize];
- InitMemory(expected, pagesize);
-
- uint8_t* data = new uint8_t[2 * pagesize];
- // Verify that we can only read one page worth of data.
- size_t bytes_read = backtrace->Read(read_addr, data, 2 * pagesize);
- ASSERT_EQ(pagesize, bytes_read);
- ASSERT_TRUE(memcmp(data, expected, pagesize) == 0);
-
- // Verify unaligned reads.
- for (size_t i = 1; i < sizeof(word_t); i++) {
- bytes_read = backtrace->Read(read_addr + i, data, 2 * sizeof(word_t));
- ASSERT_EQ(2 * sizeof(word_t), bytes_read);
- ASSERT_TRUE(memcmp(data, &expected[i], 2 * sizeof(word_t)) == 0)
- << "Offset at " << i << " failed";
- }
-
- // Verify small unaligned reads.
- for (size_t i = 1; i < sizeof(word_t); i++) {
- for (size_t j = 1; j < sizeof(word_t); j++) {
- // Set one byte past what we expect to read, to guarantee we don't overread.
- data[j] = '\0';
- bytes_read = backtrace->Read(read_addr + i, data, j);
- ASSERT_EQ(j, bytes_read);
- ASSERT_TRUE(memcmp(data, &expected[i], j) == 0)
- << "Offset at " << i << " length " << j << " miscompared";
- ASSERT_EQ('\0', data[j])
- << "Offset at " << i << " length " << j << " wrote too much data";
- }
- }
- delete[] data;
- delete[] expected;
-}
-
-TEST_F(BacktraceTest, thread_read) {
- pthread_attr_t attr;
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
- pthread_t thread;
- thread_t thread_data = { 0, 0, 0, nullptr };
- ASSERT_TRUE(pthread_create(&thread, &attr, ThreadReadTest, &thread_data) == 0);
-
- ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(getpid(), thread_data.tid));
- ASSERT_TRUE(backtrace.get() != nullptr);
-
- RunReadTest(backtrace.get(), reinterpret_cast<uint64_t>(thread_data.data));
-
- android_atomic_acquire_store(0, &thread_data.state);
-
- ASSERT_TRUE(WaitForNonZero(&thread_data.state, 10));
-}
-
-// The code requires these variables are the same size.
-volatile uint64_t g_ready = 0;
-volatile uint64_t g_addr = 0;
-static_assert(sizeof(g_ready) == sizeof(g_addr), "g_ready/g_addr must be same size");
-
-static void ForkedReadTest() {
- // Create two map pages.
- size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
- uint8_t* memory;
- if (posix_memalign(reinterpret_cast<void**>(&memory), pagesize, 2 * pagesize) != 0) {
- perror("Failed to allocate memory\n");
- exit(1);
- }
-
- // Mark the second page as not-readable.
- if (mprotect(&memory[pagesize], pagesize, PROT_NONE) != 0) {
- perror("Failed to mprotect memory\n");
- exit(1);
- }
-
- // Set up a simple pattern in memory.
- InitMemory(memory, pagesize);
-
- g_addr = reinterpret_cast<uint64_t>(memory);
- g_ready = 1;
-
- while (1) {
- usleep(US_PER_MSEC);
- }
-}
-
-TEST_F(BacktraceTest, process_read) {
- g_ready = 0;
- pid_t pid;
- if ((pid = fork()) == 0) {
- ForkedReadTest();
- exit(0);
- }
- ASSERT_NE(-1, pid);
-
- bool test_executed = false;
- uint64_t start = NanoTime();
- while (1) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
- WaitForStop(pid);
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
- ASSERT_TRUE(backtrace.get() != nullptr);
-
- uint64_t read_addr;
- size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
- reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_ready));
- ASSERT_EQ(sizeof(g_ready), bytes_read);
- if (read_addr) {
- // The forked process is ready to be read.
- bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
- reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_addr));
- ASSERT_EQ(sizeof(g_addr), bytes_read);
-
- RunReadTest(backtrace.get(), read_addr);
-
- test_executed = true;
- break;
- }
- ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
- }
- if ((NanoTime() - start) > 5 * NS_PER_SEC) {
- break;
- }
- usleep(US_PER_MSEC);
- }
- kill(pid, SIGKILL);
- ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
-
- ASSERT_TRUE(test_executed);
-}
-
-static void VerifyFunctionsFound(const std::vector<std::string>& found_functions) {
- // We expect to find these functions in libbacktrace_test. If we don't
- // find them, that's a bug in the memory read handling code in libunwind.
- std::list<std::string> expected_functions;
- expected_functions.push_back("test_recursive_call");
- expected_functions.push_back("test_level_one");
- expected_functions.push_back("test_level_two");
- expected_functions.push_back("test_level_three");
- expected_functions.push_back("test_level_four");
- for (const auto& found_function : found_functions) {
- for (const auto& expected_function : expected_functions) {
- if (found_function == expected_function) {
- expected_functions.remove(found_function);
- break;
- }
- }
- }
- ASSERT_TRUE(expected_functions.empty()) << "Not all functions found in shared library.";
-}
-
-static void CopySharedLibrary(const char* tmp_dir, std::string* tmp_so_name) {
- std::string test_lib(testing::internal::GetArgvs()[0]);
- auto const value = test_lib.find_last_of('/');
- if (value == std::string::npos) {
- test_lib = "../backtrace_test_libs/";
- } else {
- test_lib = test_lib.substr(0, value + 1) + "../backtrace_test_libs/";
- }
- test_lib += "libbacktrace_test.so";
-
- *tmp_so_name = std::string(tmp_dir) + "/libbacktrace_test.so";
- std::string cp_cmd = android::base::StringPrintf("cp %s %s", test_lib.c_str(), tmp_dir);
-
- // Copy the shared so to a tempory directory.
- ASSERT_EQ(0, system(cp_cmd.c_str()));
-}
-
-TEST_F(BacktraceTest, check_unreadable_elf_local) {
- TemporaryDir td;
- std::string tmp_so_name;
- ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
-
- struct stat buf;
- ASSERT_TRUE(stat(tmp_so_name.c_str(), &buf) != -1);
- uint64_t map_size = buf.st_size;
-
- int fd = open(tmp_so_name.c_str(), O_RDONLY);
- ASSERT_TRUE(fd != -1);
-
- void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
- ASSERT_TRUE(map != MAP_FAILED);
- close(fd);
- ASSERT_TRUE(unlink(tmp_so_name.c_str()) != -1);
-
- std::vector<std::string> found_functions;
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
- BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
-
- // Needed before GetFunctionName will work.
- backtrace->Unwind(0);
-
- // Loop through the entire map, and get every function we can find.
- map_size += reinterpret_cast<uint64_t>(map);
- std::string last_func;
- for (uint64_t read_addr = reinterpret_cast<uint64_t>(map); read_addr < map_size; read_addr += 4) {
- uint64_t offset;
- std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
- if (!func_name.empty() && last_func != func_name) {
- found_functions.push_back(func_name);
- }
- last_func = func_name;
- }
-
- ASSERT_TRUE(munmap(map, map_size - reinterpret_cast<uint64_t>(map)) == 0);
-
- VerifyFunctionsFound(found_functions);
-}
-
-TEST_F(BacktraceTest, check_unreadable_elf_remote) {
- TemporaryDir td;
- std::string tmp_so_name;
- ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
-
- g_ready = 0;
-
- struct stat buf;
- ASSERT_TRUE(stat(tmp_so_name.c_str(), &buf) != -1);
- uint64_t map_size = buf.st_size;
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- int fd = open(tmp_so_name.c_str(), O_RDONLY);
- if (fd == -1) {
- fprintf(stderr, "Failed to open file %s: %s\n", tmp_so_name.c_str(), strerror(errno));
- unlink(tmp_so_name.c_str());
- exit(0);
- }
-
- void* map = mmap(nullptr, map_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
- if (map == MAP_FAILED) {
- fprintf(stderr, "Failed to map in memory: %s\n", strerror(errno));
- unlink(tmp_so_name.c_str());
- exit(0);
- }
- close(fd);
- if (unlink(tmp_so_name.c_str()) == -1) {
- fprintf(stderr, "Failed to unlink: %s\n", strerror(errno));
- exit(0);
- }
-
- g_addr = reinterpret_cast<uint64_t>(map);
- g_ready = 1;
- while (true) {
- usleep(US_PER_MSEC);
- }
- exit(0);
- }
- ASSERT_TRUE(pid > 0);
-
- std::vector<std::string> found_functions;
- uint64_t start = NanoTime();
- while (true) {
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
-
- // Wait for the process to get to a stopping point.
- WaitForStop(pid);
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
-
- uint64_t read_addr;
- ASSERT_EQ(sizeof(g_ready),
- backtrace->Read(reinterpret_cast<uint64_t>(&g_ready),
- reinterpret_cast<uint8_t*>(&read_addr), sizeof(g_ready)));
- if (read_addr) {
- ASSERT_EQ(sizeof(g_addr),
- backtrace->Read(reinterpret_cast<uint64_t>(&g_addr),
- reinterpret_cast<uint8_t*>(&read_addr), sizeof(uint64_t)));
-
- // Needed before GetFunctionName will work.
- backtrace->Unwind(0);
-
- // Loop through the entire map, and get every function we can find.
- map_size += read_addr;
- std::string last_func;
- for (; read_addr < map_size; read_addr += 4) {
- uint64_t offset;
- std::string func_name = backtrace->GetFunctionName(read_addr, &offset);
- if (!func_name.empty() && last_func != func_name) {
- found_functions.push_back(func_name);
- }
- last_func = func_name;
- }
- break;
- }
- ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
-
- if ((NanoTime() - start) > 5 * NS_PER_SEC) {
- break;
- }
- usleep(US_PER_MSEC);
- }
-
- kill(pid, SIGKILL);
- ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
-
- VerifyFunctionsFound(found_functions);
-}
-
-static bool FindFuncFrameInBacktrace(Backtrace* backtrace, uint64_t test_func, size_t* frame_num) {
- backtrace_map_t map;
- backtrace->FillInMap(test_func, &map);
- if (!BacktraceMap::IsValid(map)) {
- return false;
- }
-
- // Loop through the frames, and find the one that is in the map.
- *frame_num = 0;
- for (Backtrace::const_iterator it = backtrace->begin(); it != backtrace->end(); ++it) {
- if (BacktraceMap::IsValid(it->map) && map.start == it->map.start &&
- it->pc >= test_func) {
- *frame_num = it->num;
- return true;
- }
- }
- return false;
-}
-
-static void VerifyUnreadableElfFrame(Backtrace* backtrace, uint64_t test_func, size_t frame_num) {
- ASSERT_LT(backtrace->NumFrames(), static_cast<size_t>(MAX_BACKTRACE_FRAMES))
- << DumpFrames(backtrace);
-
- ASSERT_TRUE(frame_num != 0) << DumpFrames(backtrace);
- // Make sure that there is at least one more frame above the test func call.
- ASSERT_LT(frame_num, backtrace->NumFrames()) << DumpFrames(backtrace);
-
- uint64_t diff = backtrace->GetFrame(frame_num)->pc - test_func;
- ASSERT_LT(diff, 200U) << DumpFrames(backtrace);
-}
-
-static void VerifyUnreadableElfBacktrace(void* func) {
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS,
- BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
-
- size_t frame_num;
- uint64_t test_func = reinterpret_cast<uint64_t>(func);
- ASSERT_TRUE(FindFuncFrameInBacktrace(backtrace.get(), test_func, &frame_num))
- << DumpFrames(backtrace.get());
-
- VerifyUnreadableElfFrame(backtrace.get(), test_func, frame_num);
-}
-
-typedef int (*test_func_t)(int, int, int, int, void (*)(void*), void*);
-
-TEST_F(BacktraceTest, unwind_through_unreadable_elf_local) {
- TemporaryDir td;
- std::string tmp_so_name;
- ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
-
- void* lib_handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
- ASSERT_TRUE(lib_handle != nullptr);
- ASSERT_TRUE(unlink(tmp_so_name.c_str()) != -1);
-
- test_func_t test_func;
- test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
- ASSERT_TRUE(test_func != nullptr);
-
- ASSERT_NE(test_func(1, 2, 3, 4, VerifyUnreadableElfBacktrace, reinterpret_cast<void*>(test_func)),
- 0);
-}
-
-TEST_F(BacktraceTest, unwind_through_unreadable_elf_remote) {
- TemporaryDir td;
- std::string tmp_so_name;
- ASSERT_NO_FATAL_FAILURE(CopySharedLibrary(td.path, &tmp_so_name));
-
- void* lib_handle = dlopen(tmp_so_name.c_str(), RTLD_NOW);
- ASSERT_TRUE(lib_handle != nullptr);
- ASSERT_TRUE(unlink(tmp_so_name.c_str()) != -1);
-
- test_func_t test_func;
- test_func = reinterpret_cast<test_func_t>(dlsym(lib_handle, "test_level_one"));
- ASSERT_TRUE(test_func != nullptr);
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- test_func(1, 2, 3, 4, 0, 0);
- exit(0);
- }
- ASSERT_TRUE(pid > 0);
-
- uint64_t start = NanoTime();
- bool done = false;
- while (!done) {
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
-
- // Wait for the process to get to a stopping point.
- WaitForStop(pid);
-
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
-
- size_t frame_num;
- if (FindFuncFrameInBacktrace(backtrace.get(), reinterpret_cast<uint64_t>(test_func),
- &frame_num) &&
- frame_num != 0) {
- VerifyUnreadableElfFrame(backtrace.get(), reinterpret_cast<uint64_t>(test_func), frame_num);
- done = true;
- }
-
- ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
-
- if ((NanoTime() - start) > 5 * NS_PER_SEC) {
- break;
- }
- usleep(US_PER_MSEC);
- }
-
- kill(pid, SIGKILL);
- ASSERT_EQ(waitpid(pid, nullptr, 0), pid);
-
- ASSERT_TRUE(done) << "Test function never found in unwind.";
-}
-
-TEST_F(BacktraceTest, unwind_thread_doesnt_exist) {
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, 99999999));
- ASSERT_TRUE(backtrace.get() != nullptr);
- ASSERT_FALSE(backtrace->Unwind(0));
- ASSERT_EQ(BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST, backtrace->GetError().error_code);
-}
-
-TEST_F(BacktraceTest, local_get_function_name_before_unwind) {
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace.get() != nullptr);
-
- // Verify that trying to get a function name before doing an unwind works.
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
- uint64_t offset;
- ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
-}
-
-TEST_F(BacktraceTest, remote_get_function_name_before_unwind) {
- pid_t pid;
- CreateRemoteProcess(&pid);
-
- // Now create an unwind object.
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
-
- // Verify that trying to get a function name before doing an unwind works.
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(test_level_one_) + 1;
- uint64_t offset;
- ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset));
-
- FinishRemoteProcess(pid);
-}
-
-static void SetUcontextSp(uint64_t sp, ucontext_t* ucontext) {
-#if defined(__arm__)
- ucontext->uc_mcontext.arm_sp = sp;
-#elif defined(__aarch64__)
- ucontext->uc_mcontext.sp = sp;
-#elif defined(__i386__)
- ucontext->uc_mcontext.gregs[REG_ESP] = sp;
-#elif defined(__x86_64__)
- ucontext->uc_mcontext.gregs[REG_RSP] = sp;
-#else
- UNUSED(sp);
- UNUSED(ucontext);
- ASSERT_TRUE(false) << "Unsupported architecture";
-#endif
-}
-
-static void SetUcontextPc(uint64_t pc, ucontext_t* ucontext) {
-#if defined(__arm__)
- ucontext->uc_mcontext.arm_pc = pc;
-#elif defined(__aarch64__)
- ucontext->uc_mcontext.pc = pc;
-#elif defined(__i386__)
- ucontext->uc_mcontext.gregs[REG_EIP] = pc;
-#elif defined(__x86_64__)
- ucontext->uc_mcontext.gregs[REG_RIP] = pc;
-#else
- UNUSED(pc);
- UNUSED(ucontext);
- ASSERT_TRUE(false) << "Unsupported architecture";
-#endif
-}
-
-static void SetUcontextLr(uint64_t lr, ucontext_t* ucontext) {
-#if defined(__arm__)
- ucontext->uc_mcontext.arm_lr = lr;
-#elif defined(__aarch64__)
- ucontext->uc_mcontext.regs[30] = lr;
-#elif defined(__i386__)
- // The lr is on the stack.
- ASSERT_TRUE(lr != 0);
- ASSERT_TRUE(ucontext != nullptr);
-#elif defined(__x86_64__)
- // The lr is on the stack.
- ASSERT_TRUE(lr != 0);
- ASSERT_TRUE(ucontext != nullptr);
-#else
- UNUSED(lr);
- UNUSED(ucontext);
- ASSERT_TRUE(false) << "Unsupported architecture";
-#endif
-}
-
-static constexpr size_t DEVICE_MAP_SIZE = 1024;
-
-static void SetupDeviceMap(void** device_map) {
- // Make sure that anything in a device map will result in fails
- // to read.
- android::base::unique_fd device_fd(open("/dev/zero", O_RDONLY | O_CLOEXEC));
-
- *device_map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE, device_fd, 0);
- ASSERT_TRUE(*device_map != MAP_FAILED);
-
- // Make sure the map is readable.
- ASSERT_EQ(0, reinterpret_cast<int*>(*device_map)[0]);
-}
-
-static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
- uint64_t device_map_uint = reinterpret_cast<uint64_t>(device_map);
-
- backtrace_map_t map;
- backtrace->FillInMap(device_map_uint, &map);
- // Verify the flag is set.
- ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP);
-
- // Quick basic checks of functionality.
- uint64_t offset;
- ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset));
- ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
- ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
-
- uint64_t cur_func_offset = reinterpret_cast<uint64_t>(BacktraceTest::test_level_one_) + 1;
- // Now verify the device map flag actually causes the function name to be empty.
- backtrace->FillInMap(cur_func_offset, &map);
- ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
- ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
- map.flags |= PROT_DEVICE_MAP;
- ASSERT_EQ(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
-
- ucontext_t ucontext;
-
- // Create a context that has the pc in the device map, but the sp
- // in a non-device map.
- memset(&ucontext, 0, sizeof(ucontext));
- SetUcontextSp(reinterpret_cast<uint64_t>(&ucontext), &ucontext);
- SetUcontextPc(device_map_uint, &ucontext);
- SetUcontextLr(cur_func_offset, &ucontext);
-
- ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
-
- // The buffer should only be a single element.
- ASSERT_EQ(1U, backtrace->NumFrames());
- const backtrace_frame_data_t* frame = backtrace->GetFrame(0);
- ASSERT_EQ(device_map_uint, frame->pc);
- ASSERT_EQ(reinterpret_cast<uint64_t>(&ucontext), frame->sp);
-
- // Check what happens when skipping the first frame.
- ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
- ASSERT_EQ(0U, backtrace->NumFrames());
-
- // Create a context that has the sp in the device map, but the pc
- // in a non-device map.
- memset(&ucontext, 0, sizeof(ucontext));
- SetUcontextSp(device_map_uint, &ucontext);
- SetUcontextPc(cur_func_offset, &ucontext);
- SetUcontextLr(cur_func_offset, &ucontext);
-
- ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
-
- // The buffer should only be a single element.
- ASSERT_EQ(1U, backtrace->NumFrames());
- frame = backtrace->GetFrame(0);
- ASSERT_EQ(cur_func_offset, frame->pc);
- ASSERT_EQ(device_map_uint, frame->sp);
-
- // Check what happens when skipping the first frame.
- ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
- ASSERT_EQ(0U, backtrace->NumFrames());
-}
-
-TEST_F(BacktraceTest, unwind_disallow_device_map_local) {
- void* device_map;
- SetupDeviceMap(&device_map);
-
- // Now create an unwind object.
- std::unique_ptr<Backtrace> backtrace(
- Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
- ASSERT_TRUE(backtrace);
-
- UnwindFromDevice(backtrace.get(), device_map);
-
- munmap(device_map, DEVICE_MAP_SIZE);
-}
-
-TEST_F(BacktraceTest, unwind_disallow_device_map_remote) {
- void* device_map;
- SetupDeviceMap(&device_map);
-
- // Fork a process to do a remote backtrace.
- pid_t pid;
- CreateRemoteProcess(&pid);
-
- // Now create an unwind object.
- std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
-
- UnwindFromDevice(backtrace.get(), device_map);
-
- FinishRemoteProcess(pid);
-
- munmap(device_map, DEVICE_MAP_SIZE);
-}
-
-class ScopedSignalHandler {
- public:
- ScopedSignalHandler(int signal_number, void (*handler)(int)) : signal_number_(signal_number) {
- memset(&action_, 0, sizeof(action_));
- action_.sa_handler = handler;
- sigaction(signal_number_, &action_, &old_action_);
- }
-
- ScopedSignalHandler(int signal_number, void (*action)(int, siginfo_t*, void*))
- : signal_number_(signal_number) {
- memset(&action_, 0, sizeof(action_));
- action_.sa_flags = SA_SIGINFO;
- action_.sa_sigaction = action;
- sigaction(signal_number_, &action_, &old_action_);
- }
-
- ~ScopedSignalHandler() { sigaction(signal_number_, &old_action_, nullptr); }
-
- private:
- struct sigaction action_;
- struct sigaction old_action_;
- const int signal_number_;
-};
-
-static void SetValueAndLoop(void* data) {
- volatile int* value = reinterpret_cast<volatile int*>(data);
-
- *value = 1;
- for (volatile int i = 0;; i++)
- ;
-}
-
-static void UnwindThroughSignal(bool use_action, create_func_t create_func,
- map_create_func_t map_create_func) {
- volatile int value = 0;
- pid_t pid;
- if ((pid = fork()) == 0) {
- if (use_action) {
- ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_action_);
-
- BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
- } else {
- ScopedSignalHandler ssh(SIGUSR1, BacktraceTest::test_signal_handler_);
-
- BacktraceTest::test_level_one_(1, 2, 3, 4, SetValueAndLoop, const_cast<int*>(&value));
- }
- }
- ASSERT_NE(-1, pid);
-
- int read_value = 0;
- uint64_t start = NanoTime();
- while (read_value == 0) {
- usleep(1000);
-
- // Loop until the remote function gets into the final function.
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
-
- WaitForStop(pid);
-
- std::unique_ptr<BacktraceMap> map(map_create_func(pid, false));
- std::unique_ptr<Backtrace> backtrace(create_func(pid, pid, map.get()));
-
- size_t bytes_read = backtrace->Read(reinterpret_cast<uint64_t>(const_cast<int*>(&value)),
- reinterpret_cast<uint8_t*>(&read_value), sizeof(read_value));
- ASSERT_EQ(sizeof(read_value), bytes_read);
-
- ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
-
- ASSERT_TRUE(NanoTime() - start < 5 * NS_PER_SEC)
- << "Remote process did not execute far enough in 5 seconds.";
- }
-
- // Now need to send a signal to the remote process.
- kill(pid, SIGUSR1);
-
- // Wait for the process to get to the signal handler loop.
- Backtrace::const_iterator frame_iter;
- start = NanoTime();
- std::unique_ptr<BacktraceMap> map;
- std::unique_ptr<Backtrace> backtrace;
- while (true) {
- usleep(1000);
-
- ASSERT_TRUE(ptrace(PTRACE_ATTACH, pid, 0, 0) == 0);
-
- WaitForStop(pid);
-
- map.reset(map_create_func(pid, false));
- ASSERT_TRUE(map.get() != nullptr);
- backtrace.reset(create_func(pid, pid, map.get()));
- ASSERT_TRUE(backtrace->Unwind(0));
- bool found = false;
- for (frame_iter = backtrace->begin(); frame_iter != backtrace->end(); ++frame_iter) {
- if (frame_iter->func_name == "test_loop_forever") {
- ++frame_iter;
- found = true;
- break;
- }
- }
- if (found) {
- break;
- }
-
- ASSERT_TRUE(ptrace(PTRACE_DETACH, pid, 0, 0) == 0);
-
- ASSERT_TRUE(NanoTime() - start < 5 * NS_PER_SEC)
- << "Remote process did not get in signal handler in 5 seconds." << std::endl
- << DumpFrames(backtrace.get());
- }
-
- std::vector<std::string> names;
- // Loop through the frames, and save the function names.
- size_t frame = 0;
- for (; frame_iter != backtrace->end(); ++frame_iter) {
- if (frame_iter->func_name == "test_level_four") {
- frame = names.size() + 1;
- }
- names.push_back(frame_iter->func_name);
- }
- ASSERT_NE(0U, frame) << "Unable to find test_level_four in backtrace" << std::endl
- << DumpFrames(backtrace.get());
-
- // The expected order of the frames:
- // test_loop_forever
- // test_signal_handler|test_signal_action
- // <OPTIONAL_FRAME> May or may not exist.
- // SetValueAndLoop (but the function name might be empty)
- // test_level_four
- // test_level_three
- // test_level_two
- // test_level_one
- ASSERT_LE(frame + 2, names.size()) << DumpFrames(backtrace.get());
- ASSERT_LE(2U, frame) << DumpFrames(backtrace.get());
- if (use_action) {
- ASSERT_EQ("test_signal_action", names[0]) << DumpFrames(backtrace.get());
- } else {
- ASSERT_EQ("test_signal_handler", names[0]) << DumpFrames(backtrace.get());
- }
- ASSERT_EQ("test_level_three", names[frame]) << DumpFrames(backtrace.get());
- ASSERT_EQ("test_level_two", names[frame + 1]) << DumpFrames(backtrace.get());
- ASSERT_EQ("test_level_one", names[frame + 2]) << DumpFrames(backtrace.get());
-
- FinishRemoteProcess(pid);
-}
-
-TEST_F(BacktraceTest, unwind_remote_through_signal_using_handler) {
- UnwindThroughSignal(false, Backtrace::Create, BacktraceMap::Create);
-}
-
-TEST_F(BacktraceTest, unwind_remote_through_signal_using_action) {
- UnwindThroughSignal(true, Backtrace::Create, BacktraceMap::Create);
-}
-
-static void TestFrameSkipNumbering(create_func_t create_func, map_create_func_t map_create_func) {
- std::unique_ptr<BacktraceMap> map(map_create_func(getpid(), false));
- std::unique_ptr<Backtrace> backtrace(
- create_func(getpid(), android::base::GetThreadId(), map.get()));
- backtrace->Unwind(1);
- ASSERT_NE(0U, backtrace->NumFrames());
- ASSERT_EQ(0U, backtrace->GetFrame(0)->num);
-}
-
-TEST_F(BacktraceTest, unwind_frame_skip_numbering) {
- TestFrameSkipNumbering(Backtrace::Create, BacktraceMap::Create);
-}
-
-#define MAX_LEAK_BYTES (32*1024UL)
-
-static void CheckForLeak(pid_t pid, pid_t tid) {
- std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
-
- // Loop enough that even a small leak should be detectable.
- size_t first_allocated_bytes = 0;
- size_t last_allocated_bytes = 0;
- for (size_t i = 0; i < 4096; i++) {
- Backtrace* backtrace = Backtrace::Create(pid, tid, map.get());
- ASSERT_TRUE(backtrace != nullptr);
- ASSERT_TRUE(backtrace->Unwind(0));
- VERIFY_NO_ERROR(backtrace->GetError().error_code);
- delete backtrace;
-
- size_t allocated_bytes = mallinfo().uordblks;
- if (first_allocated_bytes == 0) {
- first_allocated_bytes = allocated_bytes;
- } else if (last_allocated_bytes > first_allocated_bytes) {
- // Check that the memory did not increase too much over the first loop.
- ASSERT_LE(last_allocated_bytes - first_allocated_bytes, MAX_LEAK_BYTES);
- }
- last_allocated_bytes = allocated_bytes;
- }
-}
-
-TEST_F(BacktraceTest, check_for_leak_local) {
- CheckForLeak(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD);
-}
-
-TEST_F(BacktraceTest, check_for_leak_local_thread) {
- thread_t thread_data = { 0, 0, 0, nullptr };
- pthread_t thread;
- ASSERT_TRUE(pthread_create(&thread, nullptr, ThreadLevelRun, &thread_data) == 0);
-
- // Wait up to 2 seconds for the tid to be set.
- ASSERT_TRUE(WaitForNonZero(&thread_data.state, 2));
-
- CheckForLeak(BACKTRACE_CURRENT_PROCESS, thread_data.tid);
-
- // Tell the thread to exit its infinite loop.
- android_atomic_acquire_store(0, &thread_data.state);
-
- ASSERT_TRUE(pthread_join(thread, nullptr) == 0);
-}
-
-TEST_F(BacktraceTest, check_for_leak_remote) {
- pid_t pid;
- CreateRemoteProcess(&pid);
-
- CheckForLeak(pid, BACKTRACE_CURRENT_THREAD);
-
- FinishRemoteProcess(pid);
-}
diff --git a/libbacktrace/backtrace_testlib.cpp b/libbacktrace/backtrace_testlib.cpp
deleted file mode 100644
index fec7d98..0000000
--- a/libbacktrace/backtrace_testlib.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2013 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 <signal.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <memory>
-#include <vector>
-
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsGetLocal.h>
-
-#include "backtrace_testlib.h"
-
-void test_loop_forever() {
- while (1)
- ;
-}
-
-void test_signal_handler(int) { test_loop_forever(); }
-
-void test_signal_action(int, siginfo_t*, void*) { test_loop_forever(); }
-
-int test_level_four(int one, int two, int three, int four, void (*callback_func)(void*),
- void* data) {
- if (callback_func != NULL) {
- callback_func(data);
- } else {
- while (1)
- ;
- }
- return one + two + three + four;
-}
-
-int test_level_three(int one, int two, int three, int four, void (*callback_func)(void*),
- void* data) {
- return test_level_four(one + 3, two + 6, three + 9, four + 12, callback_func, data) + 3;
-}
-
-int test_level_two(int one, int two, int three, int four, void (*callback_func)(void*), void* data) {
- return test_level_three(one + 2, two + 4, three + 6, four + 8, callback_func, data) + 2;
-}
-
-int test_level_one(int one, int two, int three, int four, void (*callback_func)(void*), void* data) {
- return test_level_two(one + 1, two + 2, three + 3, four + 4, callback_func, data) + 1;
-}
-
-int test_recursive_call(int level, void (*callback_func)(void*), void* data) {
- if (level > 0) {
- return test_recursive_call(level - 1, callback_func, data) + level;
- } else if (callback_func != NULL) {
- callback_func(data);
- } else {
- while (1) {
- }
- }
- return 0;
-}
-
-typedef struct {
- std::vector<uint8_t>* ucontext;
- volatile int* exit_flag;
-} GetContextArg;
-
-static void GetContextAndExit(void* data) {
- GetContextArg* arg = reinterpret_cast<GetContextArg*>(data);
-
- std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
- unwindstack::RegsGetLocal(regs.get());
-
- ucontext_t ucontext;
- memset(&ucontext, 0, sizeof(ucontext));
-#if defined(__arm__)
- memcpy(&ucontext.uc_mcontext, regs->RawData(), sizeof(uint32_t) * 16);
-#elif defined(__aarch64__)
- memcpy(&ucontext.uc_mcontext, regs->RawData(), sizeof(uint64_t) * 33);
-#elif defined(__i386__)
- uint32_t* reg_data = reinterpret_cast<uint32_t*>(regs->RawData());
- ucontext.uc_mcontext.gregs[0] = reg_data[15];
- ucontext.uc_mcontext.gregs[1] = reg_data[14];
- ucontext.uc_mcontext.gregs[2] = reg_data[13];
- ucontext.uc_mcontext.gregs[3] = reg_data[12];
- ucontext.uc_mcontext.gregs[4] = reg_data[7];
- ucontext.uc_mcontext.gregs[5] = reg_data[6];
- ucontext.uc_mcontext.gregs[6] = reg_data[5];
- ucontext.uc_mcontext.gregs[7] = reg_data[4];
- ucontext.uc_mcontext.gregs[8] = reg_data[3];
- ucontext.uc_mcontext.gregs[9] = reg_data[2];
- ucontext.uc_mcontext.gregs[10] = reg_data[1];
- ucontext.uc_mcontext.gregs[11] = reg_data[0];
- ucontext.uc_mcontext.gregs[14] = reg_data[8];
- ucontext.uc_mcontext.gregs[15] = reg_data[10];
-#elif defined(__x86_64__)
- uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
- ucontext.uc_mcontext.gregs[0] = reg_data[8];
- ucontext.uc_mcontext.gregs[1] = reg_data[9];
- ucontext.uc_mcontext.gregs[2] = reg_data[10];
- ucontext.uc_mcontext.gregs[3] = reg_data[11];
- ucontext.uc_mcontext.gregs[4] = reg_data[12];
- ucontext.uc_mcontext.gregs[5] = reg_data[13];
- ucontext.uc_mcontext.gregs[6] = reg_data[14];
- ucontext.uc_mcontext.gregs[7] = reg_data[15];
- ucontext.uc_mcontext.gregs[8] = reg_data[5];
- ucontext.uc_mcontext.gregs[9] = reg_data[4];
- ucontext.uc_mcontext.gregs[10] = reg_data[6];
- ucontext.uc_mcontext.gregs[11] = reg_data[3];
- ucontext.uc_mcontext.gregs[12] = reg_data[1];
- ucontext.uc_mcontext.gregs[13] = reg_data[0];
- ucontext.uc_mcontext.gregs[14] = reg_data[2];
- ucontext.uc_mcontext.gregs[15] = reg_data[7];
- ucontext.uc_mcontext.gregs[16] = reg_data[16];
-#endif
-
- arg->ucontext->resize(sizeof(ucontext));
- memcpy(arg->ucontext->data(), &ucontext, sizeof(ucontext));
-
- // Don't touch the stack anymore.
- while (*arg->exit_flag == 0) {
- }
-}
-
-void test_get_context_and_wait(void* ucontext, volatile int* exit_flag) {
- GetContextArg arg;
- arg.ucontext = reinterpret_cast<std::vector<uint8_t>*>(ucontext);
- arg.exit_flag = exit_flag;
- test_level_one(1, 2, 3, 4, GetContextAndExit, &arg);
-}
diff --git a/libbacktrace/backtrace_testlib.h b/libbacktrace/backtrace_testlib.h
deleted file mode 100644
index 9b55e56..0000000
--- a/libbacktrace/backtrace_testlib.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 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 _LIBBACKTRACE_BACKTRACE_TESTLIB_H
-#define _LIBBACKTRACE_BACKTRACE_TESTLIB_H
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-
-void test_loop_forever();
-void test_signal_handler(int);
-void test_signal_action(int, siginfo_t*, void*);
-int test_level_four(int, int, int, int, void (*)(void*), void*);
-int test_level_three(int, int, int, int, void (*)(void*), void*);
-int test_level_two(int, int, int, int, void (*)(void*), void*);
-int test_level_one(int, int, int, int, void (*)(void*), void*);
-int test_recursive_call(int, void (*)(void*), void*);
-void test_get_context_and_wait(void*, volatile int*);
-
-__END_DECLS
-
-#endif // _LIBBACKTRACE_BACKTRACE_TESTLIB_H
diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h
deleted file mode 100644
index 664b531..0000000
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2013 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 _BACKTRACE_BACKTRACE_H
-#define _BACKTRACE_BACKTRACE_H
-
-#include <inttypes.h>
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include <backtrace/backtrace_constants.h>
-#include <backtrace/BacktraceMap.h>
-
-#if defined(__LP64__)
-#define PRIPTR "016" PRIx64
-typedef uint64_t word_t;
-#else
-#define PRIPTR "08" PRIx64
-typedef uint32_t word_t;
-#endif
-
-enum BacktraceUnwindErrorCode : uint32_t {
- BACKTRACE_UNWIND_NO_ERROR,
- // Something failed while trying to perform the setup to begin the unwind.
- BACKTRACE_UNWIND_ERROR_SETUP_FAILED,
- // There is no map information to use with the unwind.
- BACKTRACE_UNWIND_ERROR_MAP_MISSING,
- // An error occurred that indicates a programming error.
- BACKTRACE_UNWIND_ERROR_INTERNAL,
- // The thread to unwind has disappeared before the unwind can begin.
- BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST,
- // The thread to unwind has not responded to a signal in a timely manner.
- BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT,
- // Attempt to do an unsupported operation.
- BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION,
- // Attempt to do an offline unwind without a context.
- BACKTRACE_UNWIND_ERROR_NO_CONTEXT,
- // The count of frames exceed MAX_BACKTRACE_FRAMES.
- BACKTRACE_UNWIND_ERROR_EXCEED_MAX_FRAMES_LIMIT,
- // Failed to read memory.
- BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED,
- // Failed to read registers.
- BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED,
- // Failed to find a function in debug sections.
- BACKTRACE_UNWIND_ERROR_FIND_PROC_INFO_FAILED,
- // Failed to execute dwarf instructions in debug sections.
- BACKTRACE_UNWIND_ERROR_EXECUTE_DWARF_INSTRUCTION_FAILED,
- // Unwind information is incorrect.
- BACKTRACE_UNWIND_ERROR_UNWIND_INFO,
- // Unwind information stopped due to sp/pc repeating.
- BACKTRACE_UNWIND_ERROR_REPEATED_FRAME,
- // Unwind information stopped due to invalid elf.
- BACKTRACE_UNWIND_ERROR_INVALID_ELF,
-};
-
-struct BacktraceUnwindError {
- enum BacktraceUnwindErrorCode error_code;
-
- union {
- // for BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED
- uint64_t addr;
- // for BACKTRACE_UNWIND_ERROR_ACCESS_REG_FAILED
- uint64_t regno;
- } error_info;
-
- BacktraceUnwindError() : error_code(BACKTRACE_UNWIND_NO_ERROR) {}
-};
-
-struct backtrace_frame_data_t {
- size_t num; // The current fame number.
- uint64_t pc; // The absolute pc.
- uint64_t rel_pc; // The relative pc.
- uint64_t sp; // The top of the stack.
- size_t stack_size; // The size of the stack, zero indicate an unknown stack size.
- backtrace_map_t map; // The map associated with the given pc.
- std::string func_name; // The function name associated with this pc, NULL if not found.
- uint64_t func_offset; // pc relative to the start of the function, only valid if func_name is not
- // NULL.
-};
-
-struct backtrace_stackinfo_t {
- uint64_t start;
- uint64_t end;
- const uint8_t* data;
-};
-
-namespace unwindstack {
-class Regs;
-}
-
-class Backtrace {
- public:
- enum ArchEnum : uint8_t {
- ARCH_ARM,
- ARCH_ARM64,
- ARCH_X86,
- ARCH_X86_64,
- };
-
- static void SetGlobalElfCache(bool enable);
-
- // Create the correct Backtrace object based on what is to be unwound.
- // If pid < 0 or equals the current pid, then the Backtrace object
- // corresponds to the current process.
- // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace
- // object corresponds to a thread in the current process.
- // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
- // different process.
- // Tracing a thread in a different process is not supported.
- // If map is NULL, then create the map and manage it internally.
- // If map is not NULL, the map is still owned by the caller.
- static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = nullptr);
-
- virtual ~Backtrace();
-
- // Get the current stack trace and store in the backtrace_ structure.
- virtual bool Unwind(size_t num_ignore_frames, void* context = nullptr) = 0;
-
- static bool Unwind(unwindstack::Regs* regs, BacktraceMap* back_map,
- std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
- std::vector<std::string>* skip_names, BacktraceUnwindError* error = nullptr);
-
- // Get the function name and offset into the function given the pc.
- // If the string is empty, then no valid function name was found,
- // or the pc is not in any valid map.
- virtual std::string GetFunctionName(uint64_t pc, uint64_t* offset,
- const backtrace_map_t* map = nullptr);
-
- // Fill in the map data associated with the given pc.
- virtual void FillInMap(uint64_t pc, backtrace_map_t* map);
-
- // Read the data at a specific address.
- virtual bool ReadWord(uint64_t ptr, word_t* out_value) = 0;
-
- // Read arbitrary data from a specific address. If a read request would
- // span from one map to another, this call only reads up until the end
- // of the current map.
- // Returns the total number of bytes actually read.
- virtual size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) = 0;
-
- // Create a string representing the formatted line of backtrace information
- // for a single frame.
- virtual std::string FormatFrameData(size_t frame_num);
- static std::string FormatFrameData(const backtrace_frame_data_t* frame);
-
- pid_t Pid() const { return pid_; }
- pid_t Tid() const { return tid_; }
- size_t NumFrames() const { return frames_.size(); }
-
- const backtrace_frame_data_t* GetFrame(size_t frame_num) {
- if (frame_num >= frames_.size()) {
- return nullptr;
- }
- return &frames_[frame_num];
- }
-
- typedef std::vector<backtrace_frame_data_t>::iterator iterator;
- iterator begin() { return frames_.begin(); }
- iterator end() { return frames_.end(); }
-
- typedef std::vector<backtrace_frame_data_t>::const_iterator const_iterator;
- const_iterator begin() const { return frames_.begin(); }
- const_iterator end() const { return frames_.end(); }
-
- BacktraceMap* GetMap() { return map_; }
-
- BacktraceUnwindError GetError() { return error_; }
-
- std::string GetErrorString(BacktraceUnwindError error);
-
- // Set whether to skip frames in libbacktrace/libunwindstack when doing a local unwind.
- void SetSkipFrames(bool skip_frames) { skip_frames_ = skip_frames; }
-
- protected:
- Backtrace(pid_t pid, pid_t tid, BacktraceMap* map);
-
- // The name returned is not demangled, GetFunctionName() takes care of
- // demangling the name.
- virtual std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) = 0;
-
- virtual bool VerifyReadWordArgs(uint64_t ptr, word_t* out_value);
-
- bool BuildMap();
-
- pid_t pid_;
- pid_t tid_;
-
- BacktraceMap* map_;
- bool map_shared_;
-
- std::vector<backtrace_frame_data_t> frames_;
-
- // Skip frames in libbacktrace/libunwindstack when doing a local unwind.
- bool skip_frames_ = true;
-
- BacktraceUnwindError error_;
-};
-
-#endif // _BACKTRACE_BACKTRACE_H
diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h
deleted file mode 100644
index e000a00..0000000
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2014 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 _BACKTRACE_BACKTRACE_MAP_H
-#define _BACKTRACE_BACKTRACE_MAP_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#ifdef _WIN32
-// MINGW does not define these constants.
-#define PROT_NONE 0
-#define PROT_READ 0x1
-#define PROT_WRITE 0x2
-#define PROT_EXEC 0x4
-#else
-#include <sys/mman.h>
-#endif
-
-#include <deque>
-#include <iterator>
-#include <memory>
-#include <string>
-#include <vector>
-
-// Forward declaration.
-struct backtrace_stackinfo_t;
-
-// Special flag to indicate a map is in /dev/. However, a map in
-// /dev/ashmem/... does not set this flag.
-static constexpr int PROT_DEVICE_MAP = 0x8000;
-// Special flag to indicate that this map represents an elf file
-// created by ART for use with the gdb jit debug interface.
-// This should only ever appear in offline maps data.
-static constexpr int PROT_JIT_SYMFILE_MAP = 0x4000;
-
-struct backtrace_map_t {
- uint64_t start = 0;
- uint64_t end = 0;
- uint64_t offset = 0;
- uint64_t load_bias = 0;
- int flags = 0;
- std::string name;
-
- // Returns `name` if non-empty, or `<anonymous:0x...>` otherwise.
- std::string Name() const;
-};
-
-namespace unwindstack {
-class Memory;
-}
-
-class BacktraceMap {
-public:
- // If uncached is true, then parse the current process map as of the call.
- // Passing a map created with uncached set to true to Backtrace::Create()
- // is unsupported.
- static BacktraceMap* Create(pid_t pid, bool uncached = false);
-
- virtual ~BacktraceMap();
-
- class iterator : public std::iterator<std::bidirectional_iterator_tag, backtrace_map_t*> {
- public:
- iterator(BacktraceMap* map, size_t index) : map_(map), index_(index) {}
-
- iterator& operator++() {
- index_++;
- return *this;
- }
- const iterator operator++(int increment) {
- index_ += increment;
- return *this;
- }
- iterator& operator--() {
- index_--;
- return *this;
- }
- const iterator operator--(int decrement) {
- index_ -= decrement;
- return *this;
- }
-
- bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
- bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
-
- const backtrace_map_t* operator*() {
- if (index_ >= map_->size()) {
- return nullptr;
- }
- backtrace_map_t* map = &map_->maps_[index_];
- if (map->load_bias == static_cast<uint64_t>(-1)) {
- map->load_bias = map_->GetLoadBias(index_);
- }
- return map;
- }
-
- private:
- BacktraceMap* map_ = nullptr;
- size_t index_ = 0;
- };
-
- iterator begin() { return iterator(this, 0); }
- iterator end() { return iterator(this, maps_.size()); }
-
- // Fill in the map data structure for the given address.
- virtual void FillIn(uint64_t addr, backtrace_map_t* map);
-
- // Only supported with the new unwinder.
- virtual std::string GetFunctionName(uint64_t /*pc*/, uint64_t* /*offset*/) { return ""; }
- virtual std::shared_ptr<unwindstack::Memory> GetProcessMemory() { return nullptr; }
-
- // The flags returned are the same flags as used by the mmap call.
- // The values are PROT_*.
- int GetFlags(uint64_t pc) {
- backtrace_map_t map;
- FillIn(pc, &map);
- if (IsValid(map)) {
- return map.flags;
- }
- return PROT_NONE;
- }
-
- bool IsReadable(uint64_t pc) { return GetFlags(pc) & PROT_READ; }
- bool IsWritable(uint64_t pc) { return GetFlags(pc) & PROT_WRITE; }
- bool IsExecutable(uint64_t pc) { return GetFlags(pc) & PROT_EXEC; }
-
- // In order to use the iterators on this object, a caller must
- // call the LockIterator and UnlockIterator function to guarantee
- // that the data does not change while it's being used.
- virtual void LockIterator() {}
- virtual void UnlockIterator() {}
-
- size_t size() const { return maps_.size(); }
-
- virtual bool Build();
-
- static inline bool IsValid(const backtrace_map_t& map) {
- return map.end > 0;
- }
-
- void SetSuffixesToIgnore(std::vector<std::string> suffixes) {
- suffixes_to_ignore_.insert(suffixes_to_ignore_.end(), suffixes.begin(), suffixes.end());
- }
-
- const std::vector<std::string>& GetSuffixesToIgnore() { return suffixes_to_ignore_; }
-
- // Disabling the resolving of names results in the function name being
- // set to an empty string and the function offset being set to zero
- // in the frame data when unwinding.
- void SetResolveNames(bool resolve) { resolve_names_ = resolve; }
-
- bool ResolveNames() { return resolve_names_; }
-
- protected:
- BacktraceMap(pid_t pid);
-
- virtual uint64_t GetLoadBias(size_t /* index */) { return 0; }
-
- pid_t pid_;
- std::deque<backtrace_map_t> maps_;
- std::vector<std::string> suffixes_to_ignore_;
- bool resolve_names_ = true;
-};
-
-class ScopedBacktraceMapIteratorLock {
-public:
- explicit ScopedBacktraceMapIteratorLock(BacktraceMap* map) : map_(map) {
- map->LockIterator();
- }
-
- ~ScopedBacktraceMapIteratorLock() {
- map_->UnlockIterator();
- }
-
-private:
- BacktraceMap* map_;
-};
-
-#endif // _BACKTRACE_BACKTRACE_MAP_H
diff --git a/libbacktrace/include/backtrace/backtrace_constants.h b/libbacktrace/include/backtrace/backtrace_constants.h
deleted file mode 100644
index 1a2da36..0000000
--- a/libbacktrace/include/backtrace/backtrace_constants.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2014 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 _BACKTRACE_BACKTRACE_CONSTANTS_H
-#define _BACKTRACE_BACKTRACE_CONSTANTS_H
-
-// When the pid to be traced is set to this value, then trace the current
-// process. If the tid value is not BACKTRACE_NO_TID, then the specified
-// thread from the current process will be traced.
-#define BACKTRACE_CURRENT_PROCESS (-1)
-// When the tid to be traced is set to this value, then trace the specified
-// current thread of the specified pid.
-#define BACKTRACE_CURRENT_THREAD (-1)
-
-#define MAX_BACKTRACE_FRAMES 256
-
-#endif // _BACKTRACE_BACKTRACE_CONSTANTS_H
diff --git a/libbacktrace/testdata/arm/libGLESv2_adreno.so b/libbacktrace/testdata/arm/libGLESv2_adreno.so
deleted file mode 100644
index 871f6dc..0000000
--- a/libbacktrace/testdata/arm/libGLESv2_adreno.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm/libandroid_runtime.so b/libbacktrace/testdata/arm/libandroid_runtime.so
deleted file mode 100644
index e4283e6..0000000
--- a/libbacktrace/testdata/arm/libandroid_runtime.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm/libart.so b/libbacktrace/testdata/arm/libart.so
deleted file mode 100644
index bed8e35..0000000
--- a/libbacktrace/testdata/arm/libart.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm/libbacktrace_test_arm_exidx.so b/libbacktrace/testdata/arm/libbacktrace_test_arm_exidx.so
deleted file mode 100755
index 454b032..0000000
--- a/libbacktrace/testdata/arm/libbacktrace_test_arm_exidx.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm/libbacktrace_test_debug_frame.so b/libbacktrace/testdata/arm/libbacktrace_test_debug_frame.so
deleted file mode 100755
index 787f2cb..0000000
--- a/libbacktrace/testdata/arm/libbacktrace_test_debug_frame.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm/libbacktrace_test_gnu_debugdata.so b/libbacktrace/testdata/arm/libbacktrace_test_gnu_debugdata.so
deleted file mode 100755
index 9340d98..0000000
--- a/libbacktrace/testdata/arm/libbacktrace_test_gnu_debugdata.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm/offline_testdata b/libbacktrace/testdata/arm/offline_testdata
deleted file mode 100644
index d5b8f47..0000000
--- a/libbacktrace/testdata/arm/offline_testdata
+++ /dev/null
@@ -1,105 +0,0 @@
-pid: 32232 tid: 32233
-map: start: aad19000 end: aad6c000 offset: 0 load_bias: 0 flags: 5 name: /data/backtrace_test32
-map: start: aad6c000 end: aad6e000 offset: 52000 load_bias: 0 flags: 1 name: /data/backtrace_test32
-map: start: aad6e000 end: aad6f000 offset: 54000 load_bias: 0 flags: 3 name: /data/backtrace_test32
-map: start: e7380000 end: e7400000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
-map: start: e745f000 end: e7463000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libnetd_client.so
-map: start: e7463000 end: e7464000 offset: 3000 load_bias: 0 flags: 1 name: /system/lib/libnetd_client.so
-map: start: e7464000 end: e7465000 offset: 4000 load_bias: 0 flags: 3 name: /system/lib/libnetd_client.so
-map: start: e7480000 end: e7500000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
-map: start: e7558000 end: e756c000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libunwind.so
-map: start: e756c000 end: e756d000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: e756d000 end: e756e000 offset: 14000 load_bias: 0 flags: 1 name: /system/lib/libunwind.so
-map: start: e756e000 end: e756f000 offset: 15000 load_bias: 0 flags: 3 name: /system/lib/libunwind.so
-map: start: e756f000 end: e75b5000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: e75d4000 end: e75e1000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libbase.so
-map: start: e75e1000 end: e75e2000 offset: c000 load_bias: 0 flags: 1 name: /system/lib/libbase.so
-map: start: e75e2000 end: e75e3000 offset: d000 load_bias: 0 flags: 3 name: /system/lib/libbase.so
-map: start: e7600000 end: e7616000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/liblzma.so
-map: start: e7616000 end: e7617000 offset: 15000 load_bias: 0 flags: 1 name: /system/lib/liblzma.so
-map: start: e7617000 end: e7618000 offset: 16000 load_bias: 0 flags: 3 name: /system/lib/liblzma.so
-map: start: e7618000 end: e761d000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: e7647000 end: e7656000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/liblog.so
-map: start: e7656000 end: e7657000 offset: e000 load_bias: 0 flags: 1 name: /system/lib/liblog.so
-map: start: e7657000 end: e7658000 offset: f000 load_bias: 0 flags: 3 name: /system/lib/liblog.so
-map: start: e7681000 end: e76a2000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libm.so
-map: start: e76a2000 end: e76a3000 offset: 20000 load_bias: 0 flags: 1 name: /system/lib/libm.so
-map: start: e76a3000 end: e76a4000 offset: 21000 load_bias: 0 flags: 3 name: /system/lib/libm.so
-map: start: e76eb000 end: e76ee000 offset: 0 load_bias: 0 flags: 5 name: /data/libbacktrace_test.so
-map: start: e76ee000 end: e76ef000 offset: 2000 load_bias: 0 flags: 1 name: /data/libbacktrace_test.so
-map: start: e76ef000 end: e76f0000 offset: 3000 load_bias: 0 flags: 3 name: /data/libbacktrace_test.so
-map: start: e7712000 end: e771f000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libbacktrace.so
-map: start: e771f000 end: e7720000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: e7720000 end: e7721000 offset: d000 load_bias: 0 flags: 1 name: /system/lib/libbacktrace.so
-map: start: e7721000 end: e7722000 offset: e000 load_bias: 0 flags: 3 name: /system/lib/libbacktrace.so
-map: start: e7761000 end: e7778000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libutils.so
-map: start: e7778000 end: e7779000 offset: 16000 load_bias: 0 flags: 1 name: /system/lib/libutils.so
-map: start: e7779000 end: e777a000 offset: 17000 load_bias: 0 flags: 3 name: /system/lib/libutils.so
-map: start: e77a5000 end: e782d000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libc.so
-map: start: e782d000 end: e7831000 offset: 87000 load_bias: 0 flags: 1 name: /system/lib/libc.so
-map: start: e7831000 end: e7833000 offset: 8b000 load_bias: 0 flags: 3 name: /system/lib/libc.so
-map: start: e7833000 end: e7834000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: e7834000 end: e7835000 offset: 0 load_bias: 0 flags: 1 name: [anon:.bss]
-map: start: e7835000 end: e783b000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: e7845000 end: e8437000 offset: 0 load_bias: 2b000 flags: 5 name: /system/lib/libLLVM.so
-map: start: e8437000 end: e8438000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: e8438000 end: e848a000 offset: bf2000 load_bias: 0 flags: 1 name: /system/lib/libLLVM.so
-map: start: e848a000 end: e848b000 offset: c44000 load_bias: 0 flags: 3 name: /system/lib/libLLVM.so
-map: start: e848b000 end: e84a1000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: e84eb000 end: e84f7000 offset: 0 load_bias: 0 flags: 5 name: /system/lib/libcutils.so
-map: start: e84f7000 end: e84f8000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: e84f8000 end: e84f9000 offset: c000 load_bias: 0 flags: 1 name: /system/lib/libcutils.so
-map: start: e84f9000 end: e84fa000 offset: d000 load_bias: 0 flags: 3 name: /system/lib/libcutils.so
-map: start: e852e000 end: e85b3000 offset: 0 load_bias: 2000 flags: 5 name: /system/lib/libc++.so
-map: start: e85b3000 end: e85b4000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: e85b4000 end: e85b8000 offset: 85000 load_bias: 0 flags: 1 name: /system/lib/libc++.so
-map: start: e85b8000 end: e85b9000 offset: 89000 load_bias: 0 flags: 3 name: /system/lib/libc++.so
-map: start: e85b9000 end: e85ba000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: e85ce000 end: e85cf000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
-map: start: e85e4000 end: e85e5000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e8607000 end: e8608000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
-map: start: e8680000 end: e8700000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
-map: start: e870d000 end: e8719000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: e8719000 end: e871b000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
-map: start: e871b000 end: e873b000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
-map: start: e873b000 end: e875b000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: e875b000 end: e875c000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e875c000 end: e875d000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
-map: start: e875d000 end: e875e000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
-map: start: e875e000 end: e875f000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
-map: start: e875f000 end: e877f000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
-map: start: e877f000 end: e879f000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: e879f000 end: e87a0000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87a0000 end: e87a1000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e87a1000 end: e87a2000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87a2000 end: e87a3000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: e87a3000 end: e87a4000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: e87a4000 end: e87a5000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: e87a5000 end: e87a6000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_lob]
-map: start: e87a6000 end: e87a7000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
-map: start: e87a7000 end: e87a8000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87a8000 end: e87a9000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e87a9000 end: e87aa000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: e87aa000 end: e87ab000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: e87ab000 end: e87ac000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
-map: start: e87ac000 end: e87ad000 offset: 0 load_bias: 0 flags: 0 name: [anon:thread signal stack guard page]
-map: start: e87ad000 end: e87af000 offset: 0 load_bias: 0 flags: 3 name: [anon:thread signal stack]
-map: start: e87af000 end: e87b0000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
-map: start: e87b0000 end: e880d000 offset: 0 load_bias: 0 flags: 5 name: /system/bin/linker
-map: start: e880d000 end: e880f000 offset: 5c000 load_bias: 0 flags: 1 name: /system/bin/linker
-map: start: e880f000 end: e8810000 offset: 5e000 load_bias: 0 flags: 3 name: /system/bin/linker
-map: start: e8810000 end: e8812000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: e8812000 end: e8813000 offset: 0 load_bias: 0 flags: 1 name:
-map: start: e8813000 end: e8815000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: ff886000 end: ff8a9000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-map: start: ffff0000 end: ffff1000 offset: 0 load_bias: 0 flags: 5 name: [vectors]
-ucontext: 104 000000000000000000000000000000000000000000000000000000000000000034868affdc8871e8150000001c0000001c000000150000000e00000007000000e08771e834868aff2354d2aa24f9ffffdc8871e88c8771e875b86ee778ba6ee70000000000000000
-stack: start: e8715000 end: e8719000 size: 16384 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dc8871e87dba6ee734868affdc8871e8dc8871e85dba6ee7070000000e000000150000001c000000dc8871e85dba6ee71c000000150000000e00000007000000100000000c0000000800000004000000ddb86ee75dba6ee7dc8871e804000000080000000c00000010000000dc8871e85dba6ee7100000000c000000080000000400000008000000060000000400000002000000288871e835b96ee75dba6ee7dc8871e802000000040000000600000008000000dc8871e85dba6ee70800000006000000040000000200000004000000030000000200000001000000708871e88db96ee75dba6ee7dc8871e801000000020000000300000004000000dc8871e85dba6ee70400000003000000020000000100000004000000208971e8208971e878000000e87d00003dba6ee75dba6ee7dc8871e878000000c5807ce7fc7183e734868aff78868aff78868aff34868aff34868aff78868affe0879437208971e84154d2aa0020000034868aff34868aff34868aff78000000c9b87ee7b1b87ee7a3f47be7288971e8b1b87ee7208971e800000000f83481e800000000e97d0000e87d000000000000005071e82039000000100000000000000000000000000000000000002354d2aa34868aff00000000002071e801000000000000000000000000000000708971e8208971e8000000000000000000000000e0879437000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-function: start: 0 end: e76eb835 name: unknown_start
-function: start: e76eb835 end: e76eb88d name: test_level_four
-function: start: e76eb88d end: e76eb8e5 name: test_level_three
-function: start: e76eb8e5 end: e76eb93d name: test_level_two
-function: start: e76eb93d end: e76eb995 name: test_level_one
-function: start: e76eb995 end: e76eb9f1 name: test_recursive_call
-function: start: e76eb9f1 end: ffffffff name: test_get_context_and_wait
-function: start: ffffffff end: ffffffff name: unknown_end
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno b/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
deleted file mode 100644
index d7c186e..0000000
--- a/libbacktrace/testdata/arm/offline_testdata_for_libGLESv2_adreno
+++ /dev/null
@@ -1,6 +0,0 @@
-pid: 7288 tid: 31656
-ucontext: 104 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f017cc00000000356241cc0000000000000000
-map: start: cc361000 end: cc758000 offset: 0 load_bias: 9000 flags: 5 name: /vendor/lib/egl/libGLESv2_adreno.so
-stack: start: cc17f234 end: cc17f258 size: 36 0000000000000000000000000000000000000000000000000000000000000000b36141cc
-function: start: be1f0 end: be304 name: EsxContext::Clear(unsigned int, unsigned int, unsigned int, EsxClearValues*)
-function: start: be058 end: be1f0 name: EsxContext::ClearBuffersForDebug()
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime b/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
deleted file mode 100644
index 54f3525..0000000
--- a/libbacktrace/testdata/arm/offline_testdata_for_libandroid_runtime
+++ /dev/null
@@ -1,6 +0,0 @@
-pid: 7288 tid: 31656
-ucontext: 104 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003069fed80000000049dcf6f10000000000000000
-map: start: f1f10000 end: f2049000 offset: 0 load_bias: 10000 flags: 5 name: /system/lib/libandroid_runtime.so
-stack: start: d8fe6948 end: d8fe6958 size: 16 000000000000000000000000e7dcf6f1
-function: start: 6dbf9 end: 6dce5 name: android::AndroidRuntime::javaThreadShell
-function: start: 6dce5 end: 6dd79 name: android::AndroidRuntime::javaCreateThreadEtc
diff --git a/libbacktrace/testdata/arm/offline_testdata_for_libart b/libbacktrace/testdata/arm/offline_testdata_for_libart
deleted file mode 100644
index c1369ff..0000000
--- a/libbacktrace/testdata/arm/offline_testdata_for_libart
+++ /dev/null
@@ -1,10 +0,0 @@
-pid: 32232 tid: 32233
-ucontext: 104 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006473602451b3e2e700000000d82fd1ff5600000000908eec00000000d42dd1ff00000000c02dd1ff617171e9617171e90000000000000000
-map: start: e9380000 end: e9766000 offset: 0 load_bias: b000 flags: 5 name: /system/lib/libart.so
-stack: start: ffd12dc0 end: ffd1306c size: 684 00000000000c5024070000000300000005070a0a0100000051b3e2e700000000d82fd1ff560000004c2ed1ff000000000000000081b771e9d82fd1ff000000004c2ed1ff0c2ed1ff40a8d27024bf76e900908eec000000000834d1ff0000000000000000000000000d000000050000000000000000000000080000000101d1ff44b8bfeb4b0000000000000000000000e8b8952400000000fc2ed1ff4fb3e2e7bc49ac6f00908eecb02ed1ffd82fd1ff040000008c908eec942fd1ffd5c141e9d82fd1ff4fb3e2e7542fd1ff336c68e940000000400000007030d1fff031d1ff00000000bc49ac6f5c30d1ff942fd1ff842fd1ffd82fd1ff00000000b8f1786f4fb3e2e7610d67e9d82fd1ff4fb3e2e77880adeb7980adeb7a80adeb7b80adeb7c80adeb7d80adeb7e80adeb7f80adeb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007430d1ff02000000e8b89524e8d895240200000000908eec5c30d1ffbc49ac6f4fb3e2e74030d1ffe8d8952400000000b8f1786fbc49ac6f332367e94fb3e2e701000000637171e9637171e9000000005c30d1ff8430d1ffe0c08bec882fd1ff4fb3e2e70200000004000000942fd1ffe8b8952400908eec58d8952458d895247fbd69e90500000000400fe40100000000908eec58d89524060000009c86bd6f6b876fe900908eece0c08bec00008eec0000000000000000000000000000000044b8bfeb4b000000009be86f040000000038d1ff01000000c8e7446f060000000000000000908eec30d89524e8b895249c86bd6f7893476f00908eec00000000358c6fe970400fe4116e71e9a0285a6fa4d49c6f4489bd6f30d8952458d89524e8d8952400908eeca431d1ff2c31d1ffb75861e90100000000908eec30528bec409181e958d89524
-function: start: 3a2121 end: 3a217a name: art_quick_invoke_stub_internal
-function: start: 3a66a5 end: 3a6787 name: art_quick_invoke_static_stub
-function: start: a7129 end: a72f1 name: art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)
-function: start: 2fbd35 end: 2fc789 name: art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, art::ArgArray*, art::JValue*, char const*)
-function: start: 2fcf75 end: 2fd88d name: art::InvokeMethod(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, _jobject*, _jobject*, unsigned int)
-function: start: 2a089d end: 2a08bb name: art::Method_invoke(_JNIEnv*, _jobject*, _jobject*, _jobject*)
diff --git a/libbacktrace/testdata/arm64/eglSubDriverAndroid.so b/libbacktrace/testdata/arm64/eglSubDriverAndroid.so
deleted file mode 100644
index 10ce06b..0000000
--- a/libbacktrace/testdata/arm64/eglSubDriverAndroid.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm64/libbacktrace_test_eh_frame.so b/libbacktrace/testdata/arm64/libbacktrace_test_eh_frame.so
deleted file mode 100755
index 880f337..0000000
--- a/libbacktrace/testdata/arm64/libbacktrace_test_eh_frame.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm64/libskia.so b/libbacktrace/testdata/arm64/libskia.so
deleted file mode 100644
index ef1a6a1..0000000
--- a/libbacktrace/testdata/arm64/libskia.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/arm64/offline_testdata b/libbacktrace/testdata/arm64/offline_testdata
deleted file mode 100644
index cee9f72..0000000
--- a/libbacktrace/testdata/arm64/offline_testdata
+++ /dev/null
@@ -1,107 +0,0 @@
-pid: 32438 tid: 32439
-map: start: 557066e000 end: 55706ee000 offset: 0 load_bias: 0 flags: 5 name: /data/backtrace_test64
-map: start: 55706ef000 end: 55706f2000 offset: 80000 load_bias: 0 flags: 1 name: /data/backtrace_test64
-map: start: 55706f2000 end: 55706f3000 offset: 83000 load_bias: 0 flags: 3 name: /data/backtrace_test64
-map: start: 7014200000 end: 7014600000 offset: 0 load_bias: 0 flags: 3 name: [anon:libc_malloc]
-map: start: 701464c000 end: 701465c000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libcutils.so
-map: start: 701465c000 end: 701465d000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: 701465d000 end: 701465e000 offset: 10000 load_bias: 0 flags: 1 name: /system/lib64/libcutils.so
-map: start: 701465e000 end: 701465f000 offset: 11000 load_bias: 0 flags: 3 name: /system/lib64/libcutils.so
-map: start: 7014691000 end: 70146b5000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/liblzma.so
-map: start: 70146b5000 end: 70146b6000 offset: 23000 load_bias: 0 flags: 1 name: /system/lib64/liblzma.so
-map: start: 70146b6000 end: 70146b7000 offset: 24000 load_bias: 0 flags: 3 name: /system/lib64/liblzma.so
-map: start: 70146b7000 end: 70146bc000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: 70146c9000 end: 70158b5000 offset: 0 load_bias: af000 flags: 5 name: /system/lib64/libLLVM.so
-map: start: 70158b5000 end: 701596b000 offset: 11eb000 load_bias: 0 flags: 1 name: /system/lib64/libLLVM.so
-map: start: 701596b000 end: 701596c000 offset: 12a1000 load_bias: 0 flags: 3 name: /system/lib64/libLLVM.so
-map: start: 701596c000 end: 701599f000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: 70159c2000 end: 70159f9000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libm.so
-map: start: 70159f9000 end: 70159fa000 offset: 36000 load_bias: 0 flags: 1 name: /system/lib64/libm.so
-map: start: 70159fa000 end: 70159fb000 offset: 37000 load_bias: 0 flags: 3 name: /system/lib64/libm.so
-map: start: 7015a1e000 end: 7015a2e000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libbacktrace.so
-map: start: 7015a2e000 end: 7015a2f000 offset: f000 load_bias: 0 flags: 1 name: /system/lib64/libbacktrace.so
-map: start: 7015a2f000 end: 7015a30000 offset: 10000 load_bias: 0 flags: 3 name: /system/lib64/libbacktrace.so
-map: start: 7015a5e000 end: 7015a7d000 offset: 0 load_bias: 1000 flags: 5 name: /system/lib64/libutils.so
-map: start: 7015a7d000 end: 7015a7e000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: 7015a7e000 end: 7015a7f000 offset: 1f000 load_bias: 0 flags: 1 name: /system/lib64/libutils.so
-map: start: 7015a7f000 end: 7015a80000 offset: 20000 load_bias: 0 flags: 3 name: /system/lib64/libutils.so
-map: start: 7015a99000 end: 7015b6d000 offset: 0 load_bias: 9000 flags: 5 name: /system/lib64/libc++.so
-map: start: 7015b6d000 end: 7015b6e000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: 7015b6e000 end: 7015b76000 offset: d4000 load_bias: 0 flags: 1 name: /system/lib64/libc++.so
-map: start: 7015b76000 end: 7015b77000 offset: dc000 load_bias: 0 flags: 3 name: /system/lib64/libc++.so
-map: start: 7015b77000 end: 7015b7a000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: 7015b81000 end: 7015b92000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/liblog.so
-map: start: 7015b92000 end: 7015b93000 offset: 10000 load_bias: 0 flags: 1 name: /system/lib64/liblog.so
-map: start: 7015b93000 end: 7015b94000 offset: 11000 load_bias: 0 flags: 3 name: /system/lib64/liblog.so
-map: start: 7015be3000 end: 7015ca3000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libc.so
-map: start: 7015ca3000 end: 7015ca9000 offset: bf000 load_bias: 0 flags: 1 name: /system/lib64/libc.so
-map: start: 7015ca9000 end: 7015cab000 offset: c5000 load_bias: 0 flags: 3 name: /system/lib64/libc.so
-map: start: 7015cab000 end: 7015cac000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: 7015cac000 end: 7015cad000 offset: 0 load_bias: 0 flags: 1 name: [anon:.bss]
-map: start: 7015cad000 end: 7015cb4000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: 7015cf5000 end: 7015cf6000 offset: 0 load_bias: 0 flags: 5 name: /data/libbacktrace_test.so
-map: start: 7015cf6000 end: 7015cf7000 offset: 0 load_bias: 0 flags: 1 name: /data/libbacktrace_test.so
-map: start: 7015cf7000 end: 7015cf8000 offset: 1000 load_bias: 0 flags: 3 name: /data/libbacktrace_test.so
-map: start: 7015d1f000 end: 7015d39000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libunwind.so
-map: start: 7015d39000 end: 7015d3a000 offset: 19000 load_bias: 0 flags: 1 name: /system/lib64/libunwind.so
-map: start: 7015d3a000 end: 7015d3b000 offset: 1a000 load_bias: 0 flags: 3 name: /system/lib64/libunwind.so
-map: start: 7015d3b000 end: 7015da4000 offset: 0 load_bias: 0 flags: 3 name: [anon:.bss]
-map: start: 7015de8000 end: 7015df7000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libbase.so
-map: start: 7015df7000 end: 7015df8000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: 7015df8000 end: 7015df9000 offset: f000 load_bias: 0 flags: 1 name: /system/lib64/libbase.so
-map: start: 7015df9000 end: 7015dfa000 offset: 10000 load_bias: 0 flags: 3 name: /system/lib64/libbase.so
-map: start: 7015e35000 end: 7015e36000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
-map: start: 7015e4f000 end: 7015e50000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7015f11000 end: 7015f13000 offset: 0 load_bias: 0 flags: 5 name: /system/lib64/libnetd_client.so
-map: start: 7015f13000 end: 7015f14000 offset: 1000 load_bias: 0 flags: 1 name: /system/lib64/libnetd_client.so
-map: start: 7015f14000 end: 7015f15000 offset: 2000 load_bias: 0 flags: 3 name: /system/lib64/libnetd_client.so
-map: start: 7015f6c000 end: 7015f79000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7015f79000 end: 7015f99000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:default_prop:s0
-map: start: 7015f99000 end: 7015f9a000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015f9a000 end: 7015f9b000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7015fa6000 end: 7015fa7000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015fa8000 end: 7015fa9000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
-map: start: 7015faf000 end: 7015fcf000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: 7015fcf000 end: 7015fd0000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015fd0000 end: 7015fd1000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7015fd1000 end: 7015fd2000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7015fd4000 end: 7015fd7000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7015fd7000 end: 7015fdb000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
-map: start: 7015fdb000 end: 7015fdc000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc]
-map: start: 7015fdc000 end: 7015fdd000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7015fdd000 end: 7015fde000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
-map: start: 7015fde000 end: 7015ffe000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/u:object_r:debug_prop:s0
-map: start: 7015ffe000 end: 701601e000 offset: 0 load_bias: 0 flags: 32769 name: /dev/__properties__/properties_serial
-map: start: 701601e000 end: 701601f000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 701601f000 end: 7016020000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: 7016020000 end: 7016021000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7016021000 end: 7016022000 offset: 0 load_bias: 0 flags: 0 name:
-map: start: 7016022000 end: 7016023000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_lob]
-map: start: 7016023000 end: 7016025000 offset: 0 load_bias: 0 flags: 1 name: [anon:linker_alloc]
-map: start: 7016025000 end: 7016026000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7016026000 end: 7016027000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_vector]
-map: start: 7016027000 end: 7016028000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 7016028000 end: 7016029000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
-map: start: 7016029000 end: 701602a000 offset: 0 load_bias: 0 flags: 3 name: [anon:linker_alloc_small_objects]
-map: start: 701602a000 end: 701602b000 offset: 0 load_bias: 0 flags: 1 name: [anon:atexit handlers]
-map: start: 701602b000 end: 701602c000 offset: 0 load_bias: 0 flags: 0 name: [anon:thread signal stack guard page]
-map: start: 701602c000 end: 7016030000 offset: 0 load_bias: 0 flags: 3 name: [anon:thread signal stack]
-map: start: 7016030000 end: 7016031000 offset: 0 load_bias: 0 flags: 3 name: [anon:arc4random data]
-map: start: 7016031000 end: 7016033000 offset: 0 load_bias: 0 flags: 5 name: [vdso]
-map: start: 7016033000 end: 70160dd000 offset: 0 load_bias: 0 flags: 5 name: /system/bin/linker64
-map: start: 70160dd000 end: 70160e0000 offset: a9000 load_bias: 0 flags: 1 name: /system/bin/linker64
-map: start: 70160e0000 end: 70160e1000 offset: ac000 load_bias: 0 flags: 3 name: /system/bin/linker64
-map: start: 70160e1000 end: 70160e4000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 70160e4000 end: 70160e5000 offset: 0 load_bias: 0 flags: 1 name:
-map: start: 70160e5000 end: 70160e8000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd8baf000 end: 7fd8be6000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-ucontext: 464 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000000e0000000000000015000000000000001c00000000000000ec59cf1570000000b863fd15700000005064fd15700000000000000000000000ec59cf15700000000200000000000000b863fd1570000000144abed87f0000006064fd15700000005064fd157000000000010000000000005826bed87f000000d86fcf15700000006057cf157000000000000000000000005064fd15700000005064fd15700000005064fd1570000000b67e00000000000040fd677055000000d064fd15700000000030fd157000000002000000000000000100000000000000fcb58a56000000000063fd15700000009857cf1570000000c062fd15700000001c5acf157000000000000000000000000000000000000000
-stack: start: 7015fd3000 end: 7015fd7000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f838bed87f0000004038bed87f000000b863fd1570000000b863fd1570000000b863fd1570000000ec59cf15700000001c000000150000000e000000070000003063fd15700000001c58cf1570000000b863fd1570000000ec59cf1570000000100000000c00000008000000040000006063fd15700000007c58cf1570000000b863fd1570000000ec59cf1570000000080000000600000004000000020000009063fd1570000000dc58cf1570000000b863fd1570000000ec59cf157000000004000000030000000200000001000000d063fd1570000000c459cf15700000000100000000000000144abed87f0000004038bed87f0000004038bed87f000000144abed87f000000d3aec914588f4bcd1064fd157000000074fd6770550000004038bed87f0000004038bed87f000000ec84c41570000000e484c41570000000c484c4157000000000000000000000004064fd15700000004015c01570000000b67e0000000000000000000000000000705a0e1670000000185b0e167000000000000000000000000000000000000000705a0e16700000000000000000000000b77e0000b67e000000000000550000000030fd157000000050340000000000000010000000000000000000000000000000b222147000000000102a14700000000000000000000000000000000000000040fd6770550000004038bed87f000000000000000000000000a0fa1570000000010000000000000000000000000000000000000000000000e864fd15700000005064fd1570000000000000000000000000000000000000000000000000000000d3aec914588f4bcd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-function: start: 0 end: 7015cf5760 name: unknown_start
-function: start: 7015cf5760 end: 7015cf57cc name: test_level_four
-function: start: 7015cf57cc end: 7015cf582c name: test_level_three
-function: start: 7015cf582c end: 7015cf588c name: test_level_two
-function: start: 7015cf588c end: 7015cf58ec name: test_level_one
-function: start: 7015cf58ec end: 7015cf5968 name: test_recursive_call
-function: start: 7015cf5968 end: ffffffffffffffff name: test_get_context_and_wait
-function: start: ffffffffffffffff end: ffffffffffffffff name: unknown_end
diff --git a/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid b/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
deleted file mode 100644
index 673e30e..0000000
--- a/libbacktrace/testdata/arm64/offline_testdata_for_eglSubDriverAndroid
+++ /dev/null
@@ -1,6 +0,0 @@
-pid: 12276 tid: 12303
-map: start: 7b8c01e000 end: 7b8c030000 offset: 0 load_bias: 0 flags: 5 name: /vendor/lib64/egl/eglSubDriverAndroid.so
-ucontext: 464 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004070158c7b00000000000000000000001070158c7b000000647f028c7b00000000000000000000000000000000000000
-stack: start: 7b8c157020 end: 7b8c157050 size: 48 00000000000000000000000000000000000000000000000000000000000000000000000000000000547e028c7b000000
-function: start: 9ed8 end: a1b0 name: EglAndroidWindowSurface::Initialize(EglAndroidConfig*, int const*)
-function: start: 9dcc end: 9ed8 name: EglAndroidWindowSurface::Create(ANativeWindow*, EglAndroidConfig*, EglAndroidWindowSurface**, int const*)
diff --git a/libbacktrace/testdata/arm64/offline_testdata_for_libskia b/libbacktrace/testdata/arm64/offline_testdata_for_libskia
deleted file mode 100644
index da820c0..0000000
--- a/libbacktrace/testdata/arm64/offline_testdata_for_libskia
+++ /dev/null
@@ -1,6 +0,0 @@
-pid: 32232 tid: 32233
-map: start: 7c24c80000 end: 7c25413000 offset: 0 load_bias: 5f000 flags: 5 name: /system/lib64/libskia.so
-ucontext: 464 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b04b158c7b0000000000000000000000504b158c7b0000000c9a18257c00000000000000000000000000000000000000
-stack: start: 7b8c154b80 end: 7b8c154bc0 size: 64 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ec43f2247c000000
-function: start: 568970 end: 568c08 name: SkScalerContext_FreeType::generateImage(SkGlyph const&)
-function: start: 30330c end: 3044b0 name: SkScalerContext::getImage(SkGlyph const&)
diff --git a/libbacktrace/testdata/x86/libbacktrace_test_debug_frame.so b/libbacktrace/testdata/x86/libbacktrace_test_debug_frame.so
deleted file mode 100755
index a6f3b29..0000000
--- a/libbacktrace/testdata/x86/libbacktrace_test_debug_frame.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/x86/libbacktrace_test_gnu_debugdata.so b/libbacktrace/testdata/x86/libbacktrace_test_gnu_debugdata.so
deleted file mode 100755
index ea58dfb..0000000
--- a/libbacktrace/testdata/x86/libbacktrace_test_gnu_debugdata.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/x86/offline_testdata b/libbacktrace/testdata/x86/offline_testdata
deleted file mode 100644
index 920b338..0000000
--- a/libbacktrace/testdata/x86/offline_testdata
+++ /dev/null
@@ -1,82 +0,0 @@
-pid: 34545 tid: 34546
-map: start: f705a000 end: f705c000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f705c000 end: f707f000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
-map: start: f707f000 end: f7080000 offset: 22000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
-map: start: f7080000 end: f7081000 offset: 23000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblzma.so
-map: start: f7081000 end: f7088000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f7088000 end: f7230000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7230000 end: f7231000 offset: 1a8000 load_bias: 0 flags: 0 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7231000 end: f7233000 offset: 1a8000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7233000 end: f7234000 offset: 1aa000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libc-2.19.so
-map: start: f7234000 end: f7237000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f7237000 end: f727b000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libm-2.19.so
-map: start: f727b000 end: f727c000 offset: 43000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libm-2.19.so
-map: start: f727c000 end: f727d000 offset: 44000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libm-2.19.so
-map: start: f727d000 end: f7299000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libgcc_s.so.1
-map: start: f7299000 end: f729a000 offset: 1b000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libgcc_s.so.1
-map: start: f729a000 end: f72b8000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72b8000 end: f72b9000 offset: 1e000 load_bias: 0 flags: 0 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72b9000 end: f72bb000 offset: 1e000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72bb000 end: f72bc000 offset: 20000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libtinfo.so.5.9
-map: start: f72bc000 end: f72bd000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f72bd000 end: f72e0000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libncurses.so.5.9
-map: start: f72e0000 end: f72e1000 offset: 22000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libncurses.so.5.9
-map: start: f72e1000 end: f72e2000 offset: 23000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libncurses.so.5.9
-map: start: f72e2000 end: f72e5000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libdl-2.19.so
-map: start: f72e5000 end: f72e6000 offset: 2000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libdl-2.19.so
-map: start: f72e6000 end: f72e7000 offset: 3000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libdl-2.19.so
-map: start: f72e7000 end: f72ee000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/librt-2.19.so
-map: start: f72ee000 end: f72ef000 offset: 6000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/librt-2.19.so
-map: start: f72ef000 end: f72f0000 offset: 7000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/librt-2.19.so
-map: start: f72f0000 end: f7308000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/libpthread-2.19.so
-map: start: f7308000 end: f7309000 offset: 18000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/libpthread-2.19.so
-map: start: f7309000 end: f730a000 offset: 19000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/libpthread-2.19.so
-map: start: f730a000 end: f730c000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f732f000 end: f7331000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f7331000 end: f7425000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f7425000 end: f7426000 offset: f4000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f7426000 end: f742a000 offset: f4000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f742a000 end: f742b000 offset: f8000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libc++.so
-map: start: f742b000 end: f742d000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f742d000 end: f7446000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
-map: start: f7446000 end: f7447000 offset: 18000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
-map: start: f7447000 end: f7448000 offset: 19000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libunwind.so
-map: start: f7448000 end: f7457000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f7457000 end: f745c000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
-map: start: f745c000 end: f745d000 offset: 4000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
-map: start: f745d000 end: f745e000 offset: 5000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/liblog.so
-map: start: f745e000 end: f7467000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f7467000 end: f7468000 offset: 9000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f7468000 end: f7469000 offset: 9000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f7469000 end: f746a000 offset: a000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libcutils.so
-map: start: f746a000 end: f7477000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
-map: start: f7477000 end: f7478000 offset: c000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
-map: start: f7478000 end: f7479000 offset: d000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbase.so
-map: start: f7479000 end: f7489000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
-map: start: f7489000 end: f748a000 offset: f000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
-map: start: f748a000 end: f748b000 offset: 10000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace.so
-map: start: f748b000 end: f748c000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f748c000 end: f748d000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
-map: start: f748d000 end: f748e000 offset: 0 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
-map: start: f748e000 end: f748f000 offset: 1000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib/libbacktrace_test.so
-map: start: f748f000 end: f7491000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f7491000 end: f74b1000 offset: 0 load_bias: 0 flags: 5 name: /lib/i386-linux-gnu/ld-2.19.so
-map: start: f74b1000 end: f74b2000 offset: 1f000 load_bias: 0 flags: 1 name: /lib/i386-linux-gnu/ld-2.19.so
-map: start: f74b2000 end: f74b3000 offset: 20000 load_bias: 0 flags: 3 name: /lib/i386-linux-gnu/ld-2.19.so
-map: start: f74b3000 end: f77c6000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
-map: start: f77c6000 end: f77c7000 offset: 0 load_bias: ffffe000 flags: 5 name: [vdso]
-map: start: f77c7000 end: f77d4000 offset: 313000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
-map: start: f77d4000 end: f77d5000 offset: 320000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest/backtrace_test/backtrace_test32
-map: start: f77d5000 end: f77d6000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: f7ec6000 end: f7ee7000 offset: 0 load_bias: 0 flags: 3 name: [heap]
-map: start: ffe4e000 end: ffe70000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-ucontext: 96 0000000000000000000000000000000000000000abdae6ff00000000afdae6ff78dae6ff150000001c000000b8f132f7a0f132f7d0df48f7a0ca48f728d9e6ff000000000000000000000000ceca48f7a8dae6ff000000000000000000000000
-stack: start: f732c000 end: f7330000 size: 16384 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009d9d49f761b009f71e382ff7000000000000000000000000000000000000000002000000f6372ff704c82bf70000000000204bf7f0a908f7ceca48f728d9e6fff4a449f70000000020f332f720f332f7d0df48f7f8f132f794c748f720f332f70c144205978142a8d4be08f7d0df48f720f332f7a0ca48f71c000000150000000e000000070000001c000000a0ca48f7d0df48f748f232f739c848f7070000000e000000150000001c000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7100000000c000000080000000400000010000000a0ca48f7d0df48f798f232f7c9c848f704000000080000000c00000010000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f70800000006000000040000000200000008000000a0ca48f7d0df48f7e8f232f759c948f702000000040000000600000008000000a0ca48f720f332f70000000000000000d0df48f720f332f7a0ca48f7040000000300000002000000010000000046bdaa00000000d0df48f738f332f77cca48f701000000020000000300000004000000a0ca48f720f332f700000000f83b7df7696d4df7d0df48f788dae6ff28d9e6ff28d9e6ff88dae6ff58f332f70046bdaa40fb32f7f83b7df758f332f78d6d4df728d9e6ff88dae6fff83b7df728d9e6ff28d9e6ff009030f728f432f7726f2ff728d9e6ff40fb32f740fb32f740fb32f790f332f700000000000000000000000000000000000000000000000000000000009030f740fb32f7000f3d0028f432f703b12c75032f144e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a06e2ff700000000000f3d00000000008e3f17f740fb32f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a03823f7c4fd32f700000000e0341df7e02e1df7e03d1df70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040fb32f7188eecf740fb32f70100000030647cf70046bdaa28658876000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060a705f7a4b130f7f2860000f1860000b0fb32f7ecffffff000000000000000090f332f7000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ccfb32f70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c2638cfa7f3e1d0000000000000000000000000000000000406d4df728d9e6ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c032f7004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-function: start: 0 end: f748c740 name: unknown_start
-function: start: f748c740 end: f748c7c0 name: test_level_four
-function: start: f748c7c0 end: f748c850 name: test_level_three
-function: start: f748c850 end: f748c8e0 name: test_level_two
-function: start: f748c8e0 end: f748c970 name: test_level_one
-function: start: f748c970 end: f748ca10 name: test_recursive_call
-function: start: f748ca10 end: ffffffff name: test_get_context_and_wait
-function: start: ffffffff end: ffffffff name: unknown_end
diff --git a/libbacktrace/testdata/x86_64/libbacktrace_test_eh_frame.so b/libbacktrace/testdata/x86_64/libbacktrace_test_eh_frame.so
deleted file mode 100755
index f116658..0000000
--- a/libbacktrace/testdata/x86_64/libbacktrace_test_eh_frame.so
+++ /dev/null
Binary files differ
diff --git a/libbacktrace/testdata/x86_64/offline_testdata b/libbacktrace/testdata/x86_64/offline_testdata
deleted file mode 100644
index c6bb241..0000000
--- a/libbacktrace/testdata/x86_64/offline_testdata
+++ /dev/null
@@ -1,93 +0,0 @@
-pid: 25683 tid: 25692
-map: start: 7fd5aa784000 end: 7fd5aa93e000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aa93e000 end: 7fd5aab3e000 offset: 1ba000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aab3e000 end: 7fd5aab42000 offset: 1ba000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aab42000 end: 7fd5aab44000 offset: 1be000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libc-2.19.so
-map: start: 7fd5aab44000 end: 7fd5aab49000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5aab49000 end: 7fd5aac4e000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aac4e000 end: 7fd5aae4d000 offset: 105000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aae4d000 end: 7fd5aae4e000 offset: 104000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aae4e000 end: 7fd5aae4f000 offset: 105000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libm-2.19.so
-map: start: 7fd5aae4f000 end: 7fd5aae65000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
-map: start: 7fd5aae65000 end: 7fd5ab064000 offset: 16000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
-map: start: 7fd5ab064000 end: 7fd5ab065000 offset: 15000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libgcc_s.so.1
-map: start: 7fd5ab065000 end: 7fd5ab08a000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab08a000 end: 7fd5ab289000 offset: 25000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab289000 end: 7fd5ab28d000 offset: 24000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab28d000 end: 7fd5ab28e000 offset: 28000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libtinfo.so.5.9
-map: start: 7fd5ab28e000 end: 7fd5ab2b0000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab2b0000 end: 7fd5ab4af000 offset: 22000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab4af000 end: 7fd5ab4b0000 offset: 21000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab4b0000 end: 7fd5ab4b1000 offset: 22000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libncurses.so.5.9
-map: start: 7fd5ab4b1000 end: 7fd5ab4b4000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab4b4000 end: 7fd5ab6b3000 offset: 3000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab6b3000 end: 7fd5ab6b4000 offset: 2000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab6b4000 end: 7fd5ab6b5000 offset: 3000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libdl-2.19.so
-map: start: 7fd5ab6b5000 end: 7fd5ab6bc000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab6bc000 end: 7fd5ab8bb000 offset: 7000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab8bb000 end: 7fd5ab8bc000 offset: 6000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab8bc000 end: 7fd5ab8bd000 offset: 7000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/librt-2.19.so
-map: start: 7fd5ab8bd000 end: 7fd5ab8d6000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5ab8d6000 end: 7fd5abad5000 offset: 19000 load_bias: 0 flags: 0 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5abad5000 end: 7fd5abad6000 offset: 18000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5abad6000 end: 7fd5abad7000 offset: 19000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/libpthread-2.19.so
-map: start: 7fd5abad7000 end: 7fd5abadb000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abadb000 end: 7fd5abafe000 offset: 0 load_bias: 0 flags: 5 name: /lib/x86_64-linux-gnu/ld-2.19.so
-map: start: 7fd5abb17000 end: 7fd5abb1a000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abb1a000 end: 7fd5abb40000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
-map: start: 7fd5abb40000 end: 7fd5abb41000 offset: 25000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
-map: start: 7fd5abb41000 end: 7fd5abb42000 offset: 26000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblzma.so
-map: start: 7fd5abb42000 end: 7fd5abb4b000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abb6a000 end: 7fd5abb70000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abb70000 end: 7fd5abc62000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc62000 end: 7fd5abc63000 offset: f2000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc63000 end: 7fd5abc6b000 offset: f2000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc6b000 end: 7fd5abc6c000 offset: fa000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libc++.so
-map: start: 7fd5abc6c000 end: 7fd5abc70000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abc70000 end: 7fd5abc8d000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
-map: start: 7fd5abc8d000 end: 7fd5abc8e000 offset: 1c000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
-map: start: 7fd5abc8e000 end: 7fd5abc8f000 offset: 1d000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libunwind.so
-map: start: 7fd5abc8f000 end: 7fd5abcb8000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abcb8000 end: 7fd5abcbe000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcbe000 end: 7fd5abcbf000 offset: 6000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcbf000 end: 7fd5abcc0000 offset: 6000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcc0000 end: 7fd5abcc1000 offset: 7000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/liblog.so
-map: start: 7fd5abcc1000 end: 7fd5abcc2000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abcc2000 end: 7fd5abccd000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abccd000 end: 7fd5abcce000 offset: b000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abcce000 end: 7fd5abccf000 offset: b000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abccf000 end: 7fd5abcd0000 offset: c000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libcutils.so
-map: start: 7fd5abcd0000 end: 7fd5abcdf000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abcdf000 end: 7fd5abce0000 offset: f000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abce0000 end: 7fd5abce1000 offset: f000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abce1000 end: 7fd5abce2000 offset: 10000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbase.so
-map: start: 7fd5abce2000 end: 7fd5abcf5000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
-map: start: 7fd5abcf5000 end: 7fd5abcf6000 offset: 12000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
-map: start: 7fd5abcf6000 end: 7fd5abcf7000 offset: 13000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace.so
-map: start: 7fd5abcf7000 end: 7fd5abcf8000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcf8000 end: 7fd5abcf9000 offset: 1000 load_bias: 0 flags: 0 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcf9000 end: 7fd5abcfa000 offset: 1000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcfa000 end: 7fd5abcfb000 offset: 2000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/lib64/libbacktrace_test.so
-map: start: 7fd5abcfb000 end: 7fd5abcfd000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abcfd000 end: 7fd5abcfe000 offset: 22000 load_bias: 0 flags: 1 name: /lib/x86_64-linux-gnu/ld-2.19.so
-map: start: 7fd5abcfe000 end: 7fd5abcff000 offset: 23000 load_bias: 0 flags: 3 name: /lib/x86_64-linux-gnu/ld-2.19.so
-map: start: 7fd5abcff000 end: 7fd5abd00000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5abd00000 end: 7fd5ac053000 offset: 0 load_bias: 0 flags: 5 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
-map: start: 7fd5ac053000 end: 7fd5ac054000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5ac054000 end: 7fd5ac06f000 offset: 353000 load_bias: 0 flags: 1 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
-map: start: 7fd5ac06f000 end: 7fd5ac070000 offset: 36e000 load_bias: 0 flags: 3 name: /ssd/android/aosp_master/out/host/linux-x86/nativetest64/backtrace_test/backtrace_test64
-map: start: 7fd5ac070000 end: 7fd5ac071000 offset: 0 load_bias: 0 flags: 3 name:
-map: start: 7fd5ad54e000 end: 7fd5ad56f000 offset: 0 load_bias: 0 flags: 3 name: [heap]
-map: start: 7ffcf47ed000 end: 7ffcf480f000 offset: 0 load_bias: 0 flags: 3 name: [stack]
-map: start: 7ffcf48d5000 end: 7ffcf48d7000 offset: 0 load_bias: ffffffffff700000 flags: 5 name: [vdso]
-map: start: ffffffffff600000 end: ffffffffff601000 offset: 0 load_bias: 0 flags: 5 name: [vsyscall]
-ucontext: 224 00000000000000000000000000000000000000000000000000000000000000000000000000000000b07bcfabd57f000098deb6abd57f0000b82455add57f0000010000000000000000000000000000000000000000000000c0e354add57f000000e7b6abd57f0000c8b080f4fc7f00000e0000000000000080ddb6abd57f000000000000000000001500000000000000b07bcfabd57f00001c0000000000000060ddb6abd57f0000d07bcfabd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-stack: start: 7fd5abb6b000 end: 7fd5abb6f000 size: 16384 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c4eaeabd57f00000000000000000000978142a8000000000f0000000000000012000000000000003888b4abd57f0000e657aeabd57f00000000000000000000a0dcb6abd57f0000307d78aad57f0000b0ddb6abd57f000028d978aad57f0000060aa10200000000a0ddb6abd57f0000000000000000000000000000000000002091b1abd57f0000e094b4abd57f000017008cabd57f0000c84d79aad57f000028e28babd57f00000000000005000000d503000001000000000000000000000068deb6abd57f000040deb6abd57f00002091b1abd57f00000100000000000000e0f3c6abd57f000088f0c6abd57f00006159aeabd57f000000000000000000002091b1abd57f000005000000000000000000000000000000010000000000000088f0c6abd57f00000000000000000000d07bcfabd57f00000000000000000000000000000000000098deb6abd57f000098deb6abd57f0000b0ddb6abd57f00006179cfabd57f000098deb6abd57f0000b07bcfabd57f00001c000000150000000e00000007000000f0ddb6abd57f0000e179cfabd57f00000000000000000000150000001c00000098deb6abd57f0000b07bcfabd57f0000100000000c000000080000000400000030deb6abd57f0000417acfabd57f000000000000000000000c0000001000000098deb6abd57f0000b07bcfabd57f00000800000006000000040000000200000070deb6abd57f0000a17acfabd57f00000000000000000000060000000800000098deb6abd57f0000b07bcfabd57f000004000000030000000200000001000000b0deb6abd57f0000817bcfabd57f0000000000000000000074b480f4fc7f0000c8b080f4fc7f0000c8b080f4fc7f000074b480f4fc7f000000006a80f3f73cf1d0deb6abd57f00002a52d5abd57f0000c8b080f4fc7f0000c8b080f4fc7f0000000000000000000084518cabd57f0000000000000000000000e7b6abd57f000000e7b6abd57f00008f990b1e3bad5a6700000000000000000000000000000000c0e354add57f000000e7b6abd57f00008f99cba356faf1988f9991bc23faf1980000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f00007de387aad57f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006030b4aad57f0000b8edb6abd57f00000000000000000000000000000000000080b88eaad57f0000000000000000000080b28eaad57f0000000000000000000080c18eaad57f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e7b6abd57f0000402555add57f000000e7b6abd57f00000100000000000000000000000000000000006a80f3f73cf1058f9d56adb3c7cc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000407ab1abd57f000030a3adabd57f00005c64000053640000e0e9b6abd57f0000e0e9b6abd57f0000e0ffffffffffffff00000000000000000000000000000000f0deb6abd57f00000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010eab6abd57f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000c46ad90f52391d00000000000000000000000000000000000000000000000000f051d5abd57f0000c8b080f4fc7f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b0b6abd57f000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
-function: start: 0 end: 7fd5abcf7930 name: unknown_start
-function: start: 7fd5abcf7930 end: 7fd5abcf7990 name: test_level_four
-function: start: 7fd5abcf7990 end: 7fd5abcf79f0 name: test_level_three
-function: start: 7fd5abcf79f0 end: 7fd5abcf7a50 name: test_level_two
-function: start: 7fd5abcf7a50 end: 7fd5abcf7ab0 name: test_level_one
-function: start: 7fd5abcf7ab0 end: 7fd5abcf7b30 name: test_recursive_call
-function: start: 7fd5abcf7b30 end: ffffffffffffffff name: test_get_context_and_wait
-function: start: ffffffffffffffff end: ffffffffffffffff name: unknown_end
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 60400c9..0c75dc7 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -14,6 +14,11 @@
// limitations under the License.
//
+filegroup {
+ name: "android_filesystem_config_header",
+ srcs: ["include/private/android_filesystem_config.h"],
+}
+
// some files must not be compiled when building against Mingw
// they correspond to features not used by our host development tools
// which are also hard or even impossible to port to native Win32
@@ -28,6 +33,7 @@
name: "libcutils_headers",
vendor_available: true,
recovery_available: true,
+ ramdisk_available: true,
host_supported: true,
apex_available: [
"//apex_available:platform",
@@ -54,6 +60,7 @@
name: "libcutils_sockets",
vendor_available: true,
recovery_available: true,
+ ramdisk_available: true,
host_supported: true,
native_bridge_supported: true,
apex_available: [
@@ -151,6 +158,7 @@
"canned_fs_config.cpp",
"iosched_policy.cpp",
"load_file.cpp",
+ "memory.cpp",
"native_handle.cpp",
"properties.cpp",
"record_stream.cpp",
@@ -193,25 +201,22 @@
"uevent.cpp",
],
},
+ bionic: {
+ header_libs: ["bionic_libc_platform_headers"],
+ },
android_arm: {
- srcs: ["arch-arm/memset32.S"],
sanitize: {
misc_undefined: ["integer"],
},
},
android_arm64: {
- srcs: ["arch-arm64/android_memset.S"],
sanitize: {
misc_undefined: ["integer"],
},
},
android_x86: {
- srcs: [
- "arch-x86/android_memset16.S",
- "arch-x86/android_memset32.S",
- ],
// TODO: This is to work around b/29412086.
// Remove once __mulodi4 is available and move the "sanitize" block
// to the android target.
@@ -221,10 +226,6 @@
},
android_x86_64: {
- srcs: [
- "arch-x86_64/android_memset16.S",
- "arch-x86_64/android_memset32.S",
- ],
sanitize: {
misc_undefined: ["integer"],
},
@@ -279,7 +280,6 @@
"android_get_control_socket_test.cpp",
"ashmem_test.cpp",
"fs_config_test.cpp",
- "memset_test.cpp",
"multiuser_test.cpp",
"sched_policy_test.cpp",
"str_parms_test.cpp",
diff --git a/libcutils/arch-arm/memset32.S b/libcutils/arch-arm/memset32.S
deleted file mode 100644
index 1e89636..0000000
--- a/libcutils/arch-arm/memset32.S
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-/*
- * memset32.S
- *
- */
-
- .syntax unified
-
- .text
- .align
-
- .global android_memset32
- .type android_memset32, %function
- .global android_memset16
- .type android_memset16, %function
-
- /*
- * Optimized memset32 and memset16 for ARM.
- *
- * void android_memset16(uint16_t* dst, uint16_t value, size_t size);
- * void android_memset32(uint32_t* dst, uint32_t value, size_t size);
- *
- */
-
-android_memset16:
- .fnstart
- cmp r2, #1
- bxle lr
-
- /* expand the data to 32 bits */
- mov r1, r1, lsl #16
- orr r1, r1, r1, lsr #16
-
- /* align to 32 bits */
- tst r0, #2
- strhne r1, [r0], #2
- subne r2, r2, #2
- .fnend
-
-android_memset32:
- .fnstart
- .cfi_startproc
- str lr, [sp, #-4]!
- .cfi_def_cfa_offset 4
- .cfi_rel_offset lr, 0
-
- /* align the destination to a cache-line */
- mov r12, r1
- mov lr, r1
- rsb r3, r0, #0
- ands r3, r3, #0x1C
- beq .Laligned32
- cmp r3, r2
- andhi r3, r2, #0x1C
- sub r2, r2, r3
-
- /* conditionally writes 0 to 7 words (length in r3) */
- movs r3, r3, lsl #28
- stmiacs r0!, {r1, lr}
- stmiacs r0!, {r1, lr}
- stmiami r0!, {r1, lr}
- movs r3, r3, lsl #2
- strcs r1, [r0], #4
-
-.Laligned32:
- mov r3, r1
-1: subs r2, r2, #32
- stmiahs r0!, {r1,r3,r12,lr}
- stmiahs r0!, {r1,r3,r12,lr}
- bhs 1b
- add r2, r2, #32
-
- /* conditionally stores 0 to 30 bytes */
- movs r2, r2, lsl #28
- stmiacs r0!, {r1,r3,r12,lr}
- stmiami r0!, {r1,lr}
- movs r2, r2, lsl #2
- strcs r1, [r0], #4
- strhmi lr, [r0], #2
-
- ldr lr, [sp], #4
- .cfi_def_cfa_offset 0
- .cfi_restore lr
- bx lr
- .cfi_endproc
- .fnend
diff --git a/libcutils/arch-arm64/android_memset.S b/libcutils/arch-arm64/android_memset.S
deleted file mode 100644
index 9a83a68..0000000
--- a/libcutils/arch-arm64/android_memset.S
+++ /dev/null
@@ -1,211 +0,0 @@
-/* Copyright (c) 2012, Linaro Limited
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the Linaro nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/* Assumptions:
- *
- * ARMv8-a, AArch64
- * Unaligned accesses
- *
- */
-
-/* By default we assume that the DC instruction can be used to zero
- data blocks more efficiently. In some circumstances this might be
- unsafe, for example in an asymmetric multiprocessor environment with
- different DC clear lengths (neither the upper nor lower lengths are
- safe to use). */
-
-#define dst x0
-#define count x2
-#define tmp1 x3
-#define tmp1w w3
-#define tmp2 x4
-#define tmp2w w4
-#define zva_len_x x5
-#define zva_len w5
-#define zva_bits_x x6
-
-#define A_l x1
-#define A_lw w1
-#define tmp3w w9
-
-#define ENTRY(f) \
- .text; \
- .globl f; \
- .align 0; \
- .type f, %function; \
- f: \
- .cfi_startproc \
-
-#define END(f) \
- .cfi_endproc; \
- .size f, .-f; \
-
-ENTRY(android_memset16)
- ands A_lw, A_lw, #0xffff
- b.eq .Lzero_mem
- orr A_lw, A_lw, A_lw, lsl #16
- b .Lexpand_to_64
-END(android_memset16)
-
-ENTRY(android_memset32)
- cmp A_lw, #0
- b.eq .Lzero_mem
-.Lexpand_to_64:
- orr A_l, A_l, A_l, lsl #32
-.Ltail_maybe_long:
- cmp count, #64
- b.ge .Lnot_short
-.Ltail_maybe_tiny:
- cmp count, #15
- b.le .Ltail15tiny
-.Ltail63:
- ands tmp1, count, #0x30
- b.eq .Ltail15
- add dst, dst, tmp1
- cmp tmp1w, #0x20
- b.eq 1f
- b.lt 2f
- stp A_l, A_l, [dst, #-48]
-1:
- stp A_l, A_l, [dst, #-32]
-2:
- stp A_l, A_l, [dst, #-16]
-
-.Ltail15:
- and count, count, #15
- add dst, dst, count
- stp A_l, A_l, [dst, #-16] /* Repeat some/all of last store. */
- ret
-
-.Ltail15tiny:
- /* Set up to 15 bytes. Does not assume earlier memory
- being set. */
- tbz count, #3, 1f
- str A_l, [dst], #8
-1:
- tbz count, #2, 1f
- str A_lw, [dst], #4
-1:
- tbz count, #1, 1f
- strh A_lw, [dst], #2
-1:
- ret
-
- /* Critical loop. Start at a new cache line boundary. Assuming
- * 64 bytes per line, this ensures the entire loop is in one line. */
- .p2align 6
-.Lnot_short:
- neg tmp2, dst
- ands tmp2, tmp2, #15
- b.eq 2f
- /* Bring DST to 128-bit (16-byte) alignment. We know that there's
- * more than that to set, so we simply store 16 bytes and advance by
- * the amount required to reach alignment. */
- sub count, count, tmp2
- stp A_l, A_l, [dst]
- add dst, dst, tmp2
- /* There may be less than 63 bytes to go now. */
- cmp count, #63
- b.le .Ltail63
-2:
- sub dst, dst, #16 /* Pre-bias. */
- sub count, count, #64
-1:
- stp A_l, A_l, [dst, #16]
- stp A_l, A_l, [dst, #32]
- stp A_l, A_l, [dst, #48]
- stp A_l, A_l, [dst, #64]!
- subs count, count, #64
- b.ge 1b
- tst count, #0x3f
- add dst, dst, #16
- b.ne .Ltail63
- ret
-
- /* For zeroing memory, check to see if we can use the ZVA feature to
- * zero entire 'cache' lines. */
-.Lzero_mem:
- mov A_l, #0
- cmp count, #63
- b.le .Ltail_maybe_tiny
- neg tmp2, dst
- ands tmp2, tmp2, #15
- b.eq 1f
- sub count, count, tmp2
- stp A_l, A_l, [dst]
- add dst, dst, tmp2
- cmp count, #63
- b.le .Ltail63
-1:
- /* For zeroing small amounts of memory, it's not worth setting up
- * the line-clear code. */
- cmp count, #128
- b.lt .Lnot_short
- mrs tmp1, dczid_el0
- tbnz tmp1, #4, .Lnot_short
- mov tmp3w, #4
- and zva_len, tmp1w, #15 /* Safety: other bits reserved. */
- lsl zva_len, tmp3w, zva_len
-
-.Lzero_by_line:
- /* Compute how far we need to go to become suitably aligned. We're
- * already at quad-word alignment. */
- cmp count, zva_len_x
- b.lt .Lnot_short /* Not enough to reach alignment. */
- sub zva_bits_x, zva_len_x, #1
- neg tmp2, dst
- ands tmp2, tmp2, zva_bits_x
- b.eq 1f /* Already aligned. */
- /* Not aligned, check that there's enough to copy after alignment. */
- sub tmp1, count, tmp2
- cmp tmp1, #64
- ccmp tmp1, zva_len_x, #8, ge /* NZCV=0b1000 */
- b.lt .Lnot_short
- /* We know that there's at least 64 bytes to zero and that it's safe
- * to overrun by 64 bytes. */
- mov count, tmp1
-2:
- stp A_l, A_l, [dst]
- stp A_l, A_l, [dst, #16]
- stp A_l, A_l, [dst, #32]
- subs tmp2, tmp2, #64
- stp A_l, A_l, [dst, #48]
- add dst, dst, #64
- b.ge 2b
- /* We've overrun a bit, so adjust dst downwards. */
- add dst, dst, tmp2
-1:
- sub count, count, zva_len_x
-3:
- dc zva, dst
- add dst, dst, zva_len_x
- subs count, count, zva_len_x
- b.ge 3b
- ands count, count, zva_bits_x
- b.ne .Ltail_maybe_long
- ret
-END(android_memset32)
diff --git a/libcutils/arch-x86/android_memset16.S b/libcutils/arch-x86/android_memset16.S
deleted file mode 100755
index f4d497e..0000000
--- a/libcutils/arch-x86/android_memset16.S
+++ /dev/null
@@ -1,721 +0,0 @@
-/*
- * Copyright (C) 2010 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 "cache.h"
-
-#ifndef MEMSET
-# define MEMSET android_memset16
-#endif
-
-#ifndef L
-# define L(label) .L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n) .p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc .cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc .cfi_endproc
-#endif
-
-#ifndef cfi_rel_offset
-# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
-#endif
-
-#ifndef cfi_restore
-# define cfi_restore(reg) .cfi_restore reg
-#endif
-
-#ifndef cfi_adjust_cfa_offset
-# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name) \
- .type name, @function; \
- .globl name; \
- .p2align 4; \
-name: \
- cfi_startproc
-#endif
-
-#ifndef END
-# define END(name) \
- cfi_endproc; \
- .size name, .-name
-#endif
-
-#define CFI_PUSH(REG) \
- cfi_adjust_cfa_offset (4); \
- cfi_rel_offset (REG, 0)
-
-#define CFI_POP(REG) \
- cfi_adjust_cfa_offset (-4); \
- cfi_restore (REG)
-
-#define PUSH(REG) pushl REG; CFI_PUSH (REG)
-#define POP(REG) popl REG; CFI_POP (REG)
-
-#ifdef USE_AS_BZERO16
-# define DEST PARMS
-# define LEN DEST+4
-# define SETRTNVAL
-#else
-# define DEST PARMS
-# define CHR DEST+4
-# define LEN CHR+4
-# define SETRTNVAL movl DEST(%esp), %eax
-#endif
-
-#if (defined SHARED || defined __PIC__)
-# define ENTRANCE PUSH (%ebx);
-# define RETURN_END POP (%ebx); ret
-# define RETURN RETURN_END; CFI_PUSH (%ebx)
-# define PARMS 8 /* Preserve EBX. */
-# define JMPTBL(I, B) I - B
-
-/* Load an entry in a jump table into EBX and branch to it. TABLE is a
- jump table with relative offsets. */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \
- /* We first load PC into EBX. */ \
- call __x86.get_pc_thunk.bx; \
- /* Get the address of the jump table. */ \
- add $(TABLE - .), %ebx; \
- /* Get the entry and convert the relative offset to the \
- absolute address. */ \
- add (%ebx,%ecx,4), %ebx; \
- /* We loaded the jump table and adjuested EDX. Go. */ \
- jmp *%ebx
-
- .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
- .globl __x86.get_pc_thunk.bx
- .hidden __x86.get_pc_thunk.bx
- ALIGN (4)
- .type __x86.get_pc_thunk.bx,@function
-__x86.get_pc_thunk.bx:
- cfi_startproc
- movl (%esp), %ebx
- ret
- cfi_endproc
-#else
-# define ENTRANCE
-# define RETURN_END ret
-# define RETURN RETURN_END
-# define PARMS 4
-# define JMPTBL(I, B) I
-
-/* Branch to an entry in a jump table. TABLE is a jump table with
- absolute offsets. */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \
- jmp *TABLE(,%ecx,4)
-#endif
-
- .section .text.sse2,"ax",@progbits
- ALIGN (4)
-ENTRY (MEMSET)
- ENTRANCE
-
- movl LEN(%esp), %ecx
- shr $1, %ecx
-#ifdef USE_AS_BZERO16
- xor %eax, %eax
-#else
- movzwl CHR(%esp), %eax
- mov %eax, %edx
- shl $16, %eax
- or %edx, %eax
-#endif
- movl DEST(%esp), %edx
- cmp $32, %ecx
- jae L(32wordsormore)
-
-L(write_less32words):
- lea (%edx, %ecx, 2), %edx
- BRANCH_TO_JMPTBL_ENTRY (L(table_less32words))
-
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_less32words):
- .int JMPTBL (L(write_0words), L(table_less32words))
- .int JMPTBL (L(write_1words), L(table_less32words))
- .int JMPTBL (L(write_2words), L(table_less32words))
- .int JMPTBL (L(write_3words), L(table_less32words))
- .int JMPTBL (L(write_4words), L(table_less32words))
- .int JMPTBL (L(write_5words), L(table_less32words))
- .int JMPTBL (L(write_6words), L(table_less32words))
- .int JMPTBL (L(write_7words), L(table_less32words))
- .int JMPTBL (L(write_8words), L(table_less32words))
- .int JMPTBL (L(write_9words), L(table_less32words))
- .int JMPTBL (L(write_10words), L(table_less32words))
- .int JMPTBL (L(write_11words), L(table_less32words))
- .int JMPTBL (L(write_12words), L(table_less32words))
- .int JMPTBL (L(write_13words), L(table_less32words))
- .int JMPTBL (L(write_14words), L(table_less32words))
- .int JMPTBL (L(write_15words), L(table_less32words))
- .int JMPTBL (L(write_16words), L(table_less32words))
- .int JMPTBL (L(write_17words), L(table_less32words))
- .int JMPTBL (L(write_18words), L(table_less32words))
- .int JMPTBL (L(write_19words), L(table_less32words))
- .int JMPTBL (L(write_20words), L(table_less32words))
- .int JMPTBL (L(write_21words), L(table_less32words))
- .int JMPTBL (L(write_22words), L(table_less32words))
- .int JMPTBL (L(write_23words), L(table_less32words))
- .int JMPTBL (L(write_24words), L(table_less32words))
- .int JMPTBL (L(write_25words), L(table_less32words))
- .int JMPTBL (L(write_26words), L(table_less32words))
- .int JMPTBL (L(write_27words), L(table_less32words))
- .int JMPTBL (L(write_28words), L(table_less32words))
- .int JMPTBL (L(write_29words), L(table_less32words))
- .int JMPTBL (L(write_30words), L(table_less32words))
- .int JMPTBL (L(write_31words), L(table_less32words))
- .popsection
-
- ALIGN (4)
-L(write_28words):
- movl %eax, -56(%edx)
- movl %eax, -52(%edx)
-L(write_24words):
- movl %eax, -48(%edx)
- movl %eax, -44(%edx)
-L(write_20words):
- movl %eax, -40(%edx)
- movl %eax, -36(%edx)
-L(write_16words):
- movl %eax, -32(%edx)
- movl %eax, -28(%edx)
-L(write_12words):
- movl %eax, -24(%edx)
- movl %eax, -20(%edx)
-L(write_8words):
- movl %eax, -16(%edx)
- movl %eax, -12(%edx)
-L(write_4words):
- movl %eax, -8(%edx)
- movl %eax, -4(%edx)
-L(write_0words):
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(write_29words):
- movl %eax, -58(%edx)
- movl %eax, -54(%edx)
-L(write_25words):
- movl %eax, -50(%edx)
- movl %eax, -46(%edx)
-L(write_21words):
- movl %eax, -42(%edx)
- movl %eax, -38(%edx)
-L(write_17words):
- movl %eax, -34(%edx)
- movl %eax, -30(%edx)
-L(write_13words):
- movl %eax, -26(%edx)
- movl %eax, -22(%edx)
-L(write_9words):
- movl %eax, -18(%edx)
- movl %eax, -14(%edx)
-L(write_5words):
- movl %eax, -10(%edx)
- movl %eax, -6(%edx)
-L(write_1words):
- mov %ax, -2(%edx)
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(write_30words):
- movl %eax, -60(%edx)
- movl %eax, -56(%edx)
-L(write_26words):
- movl %eax, -52(%edx)
- movl %eax, -48(%edx)
-L(write_22words):
- movl %eax, -44(%edx)
- movl %eax, -40(%edx)
-L(write_18words):
- movl %eax, -36(%edx)
- movl %eax, -32(%edx)
-L(write_14words):
- movl %eax, -28(%edx)
- movl %eax, -24(%edx)
-L(write_10words):
- movl %eax, -20(%edx)
- movl %eax, -16(%edx)
-L(write_6words):
- movl %eax, -12(%edx)
- movl %eax, -8(%edx)
-L(write_2words):
- movl %eax, -4(%edx)
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(write_31words):
- movl %eax, -62(%edx)
- movl %eax, -58(%edx)
-L(write_27words):
- movl %eax, -54(%edx)
- movl %eax, -50(%edx)
-L(write_23words):
- movl %eax, -46(%edx)
- movl %eax, -42(%edx)
-L(write_19words):
- movl %eax, -38(%edx)
- movl %eax, -34(%edx)
-L(write_15words):
- movl %eax, -30(%edx)
- movl %eax, -26(%edx)
-L(write_11words):
- movl %eax, -22(%edx)
- movl %eax, -18(%edx)
-L(write_7words):
- movl %eax, -14(%edx)
- movl %eax, -10(%edx)
-L(write_3words):
- movl %eax, -6(%edx)
- movw %ax, -2(%edx)
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-
-L(32wordsormore):
- shl $1, %ecx
- test $0x01, %edx
- jz L(aligned2bytes)
- mov %eax, (%edx)
- mov %eax, -4(%edx, %ecx)
- sub $2, %ecx
- add $1, %edx
- rol $8, %eax
-L(aligned2bytes):
-#ifdef USE_AS_BZERO16
- pxor %xmm0, %xmm0
-#else
- movd %eax, %xmm0
- pshufd $0, %xmm0, %xmm0
-#endif
- testl $0xf, %edx
- jz L(aligned_16)
-/* ECX > 32 and EDX is not 16 byte aligned. */
-L(not_aligned_16):
- movdqu %xmm0, (%edx)
- movl %edx, %eax
- and $-16, %edx
- add $16, %edx
- sub %edx, %eax
- add %eax, %ecx
- movd %xmm0, %eax
-
- ALIGN (4)
-L(aligned_16):
- cmp $128, %ecx
- jae L(128bytesormore)
-
-L(aligned_16_less128bytes):
- add %ecx, %edx
- shr $1, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
- ALIGN (4)
-L(128bytesormore):
-#ifdef SHARED_CACHE_SIZE
- PUSH (%ebx)
- mov $SHARED_CACHE_SIZE, %ebx
-#else
-# if (defined SHARED || defined __PIC__)
- call __x86.get_pc_thunk.bx
- add $_GLOBAL_OFFSET_TABLE_, %ebx
- mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx
-# else
- PUSH (%ebx)
- mov __x86_shared_cache_size, %ebx
-# endif
-#endif
- cmp %ebx, %ecx
- jae L(128bytesormore_nt_start)
-
-
-#ifdef DATA_CACHE_SIZE
- POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
- cmp $DATA_CACHE_SIZE, %ecx
-#else
-# if (defined SHARED || defined __PIC__)
-# define RESTORE_EBX_STATE
- call __x86.get_pc_thunk.bx
- add $_GLOBAL_OFFSET_TABLE_, %ebx
- cmp __x86_data_cache_size@GOTOFF(%ebx), %ecx
-# else
- POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
- cmp __x86_data_cache_size, %ecx
-# endif
-#endif
-
- jae L(128bytes_L2_normal)
- subl $128, %ecx
-L(128bytesormore_normal):
- sub $128, %ecx
- movdqa %xmm0, (%edx)
- movdqa %xmm0, 0x10(%edx)
- movdqa %xmm0, 0x20(%edx)
- movdqa %xmm0, 0x30(%edx)
- movdqa %xmm0, 0x40(%edx)
- movdqa %xmm0, 0x50(%edx)
- movdqa %xmm0, 0x60(%edx)
- movdqa %xmm0, 0x70(%edx)
- lea 128(%edx), %edx
- jb L(128bytesless_normal)
-
-
- sub $128, %ecx
- movdqa %xmm0, (%edx)
- movdqa %xmm0, 0x10(%edx)
- movdqa %xmm0, 0x20(%edx)
- movdqa %xmm0, 0x30(%edx)
- movdqa %xmm0, 0x40(%edx)
- movdqa %xmm0, 0x50(%edx)
- movdqa %xmm0, 0x60(%edx)
- movdqa %xmm0, 0x70(%edx)
- lea 128(%edx), %edx
- jae L(128bytesormore_normal)
-
-L(128bytesless_normal):
- lea 128(%ecx), %ecx
- add %ecx, %edx
- shr $1, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
- ALIGN (4)
-L(128bytes_L2_normal):
- prefetcht0 0x380(%edx)
- prefetcht0 0x3c0(%edx)
- sub $128, %ecx
- movdqa %xmm0, (%edx)
- movaps %xmm0, 0x10(%edx)
- movaps %xmm0, 0x20(%edx)
- movaps %xmm0, 0x30(%edx)
- movaps %xmm0, 0x40(%edx)
- movaps %xmm0, 0x50(%edx)
- movaps %xmm0, 0x60(%edx)
- movaps %xmm0, 0x70(%edx)
- add $128, %edx
- cmp $128, %ecx
- jae L(128bytes_L2_normal)
-
-L(128bytesless_L2_normal):
- add %ecx, %edx
- shr $1, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
- RESTORE_EBX_STATE
-L(128bytesormore_nt_start):
- sub %ebx, %ecx
- mov %ebx, %eax
- and $0x7f, %eax
- add %eax, %ecx
- movd %xmm0, %eax
- ALIGN (4)
-L(128bytesormore_shared_cache_loop):
- prefetcht0 0x3c0(%edx)
- prefetcht0 0x380(%edx)
- sub $0x80, %ebx
- movdqa %xmm0, (%edx)
- movdqa %xmm0, 0x10(%edx)
- movdqa %xmm0, 0x20(%edx)
- movdqa %xmm0, 0x30(%edx)
- movdqa %xmm0, 0x40(%edx)
- movdqa %xmm0, 0x50(%edx)
- movdqa %xmm0, 0x60(%edx)
- movdqa %xmm0, 0x70(%edx)
- add $0x80, %edx
- cmp $0x80, %ebx
- jae L(128bytesormore_shared_cache_loop)
- cmp $0x80, %ecx
- jb L(shared_cache_loop_end)
- ALIGN (4)
-L(128bytesormore_nt):
- sub $0x80, %ecx
- movntdq %xmm0, (%edx)
- movntdq %xmm0, 0x10(%edx)
- movntdq %xmm0, 0x20(%edx)
- movntdq %xmm0, 0x30(%edx)
- movntdq %xmm0, 0x40(%edx)
- movntdq %xmm0, 0x50(%edx)
- movntdq %xmm0, 0x60(%edx)
- movntdq %xmm0, 0x70(%edx)
- add $0x80, %edx
- cmp $0x80, %ecx
- jae L(128bytesormore_nt)
- sfence
-L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
- POP (%ebx)
-#endif
- add %ecx, %edx
- shr $1, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_16_128bytes):
- .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
- .popsection
-
-
- ALIGN (4)
-L(aligned_16_112bytes):
- movdqa %xmm0, -112(%edx)
-L(aligned_16_96bytes):
- movdqa %xmm0, -96(%edx)
-L(aligned_16_80bytes):
- movdqa %xmm0, -80(%edx)
-L(aligned_16_64bytes):
- movdqa %xmm0, -64(%edx)
-L(aligned_16_48bytes):
- movdqa %xmm0, -48(%edx)
-L(aligned_16_32bytes):
- movdqa %xmm0, -32(%edx)
-L(aligned_16_16bytes):
- movdqa %xmm0, -16(%edx)
-L(aligned_16_0bytes):
- SETRTNVAL
- RETURN
-
-
- ALIGN (4)
-L(aligned_16_114bytes):
- movdqa %xmm0, -114(%edx)
-L(aligned_16_98bytes):
- movdqa %xmm0, -98(%edx)
-L(aligned_16_82bytes):
- movdqa %xmm0, -82(%edx)
-L(aligned_16_66bytes):
- movdqa %xmm0, -66(%edx)
-L(aligned_16_50bytes):
- movdqa %xmm0, -50(%edx)
-L(aligned_16_34bytes):
- movdqa %xmm0, -34(%edx)
-L(aligned_16_18bytes):
- movdqa %xmm0, -18(%edx)
-L(aligned_16_2bytes):
- movw %ax, -2(%edx)
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(aligned_16_116bytes):
- movdqa %xmm0, -116(%edx)
-L(aligned_16_100bytes):
- movdqa %xmm0, -100(%edx)
-L(aligned_16_84bytes):
- movdqa %xmm0, -84(%edx)
-L(aligned_16_68bytes):
- movdqa %xmm0, -68(%edx)
-L(aligned_16_52bytes):
- movdqa %xmm0, -52(%edx)
-L(aligned_16_36bytes):
- movdqa %xmm0, -36(%edx)
-L(aligned_16_20bytes):
- movdqa %xmm0, -20(%edx)
-L(aligned_16_4bytes):
- movl %eax, -4(%edx)
- SETRTNVAL
- RETURN
-
-
- ALIGN (4)
-L(aligned_16_118bytes):
- movdqa %xmm0, -118(%edx)
-L(aligned_16_102bytes):
- movdqa %xmm0, -102(%edx)
-L(aligned_16_86bytes):
- movdqa %xmm0, -86(%edx)
-L(aligned_16_70bytes):
- movdqa %xmm0, -70(%edx)
-L(aligned_16_54bytes):
- movdqa %xmm0, -54(%edx)
-L(aligned_16_38bytes):
- movdqa %xmm0, -38(%edx)
-L(aligned_16_22bytes):
- movdqa %xmm0, -22(%edx)
-L(aligned_16_6bytes):
- movl %eax, -6(%edx)
- movw %ax, -2(%edx)
- SETRTNVAL
- RETURN
-
-
- ALIGN (4)
-L(aligned_16_120bytes):
- movdqa %xmm0, -120(%edx)
-L(aligned_16_104bytes):
- movdqa %xmm0, -104(%edx)
-L(aligned_16_88bytes):
- movdqa %xmm0, -88(%edx)
-L(aligned_16_72bytes):
- movdqa %xmm0, -72(%edx)
-L(aligned_16_56bytes):
- movdqa %xmm0, -56(%edx)
-L(aligned_16_40bytes):
- movdqa %xmm0, -40(%edx)
-L(aligned_16_24bytes):
- movdqa %xmm0, -24(%edx)
-L(aligned_16_8bytes):
- movq %xmm0, -8(%edx)
- SETRTNVAL
- RETURN
-
-
- ALIGN (4)
-L(aligned_16_122bytes):
- movdqa %xmm0, -122(%edx)
-L(aligned_16_106bytes):
- movdqa %xmm0, -106(%edx)
-L(aligned_16_90bytes):
- movdqa %xmm0, -90(%edx)
-L(aligned_16_74bytes):
- movdqa %xmm0, -74(%edx)
-L(aligned_16_58bytes):
- movdqa %xmm0, -58(%edx)
-L(aligned_16_42bytes):
- movdqa %xmm0, -42(%edx)
-L(aligned_16_26bytes):
- movdqa %xmm0, -26(%edx)
-L(aligned_16_10bytes):
- movq %xmm0, -10(%edx)
- movw %ax, -2(%edx)
- SETRTNVAL
- RETURN
-
-
- ALIGN (4)
-L(aligned_16_124bytes):
- movdqa %xmm0, -124(%edx)
-L(aligned_16_108bytes):
- movdqa %xmm0, -108(%edx)
-L(aligned_16_92bytes):
- movdqa %xmm0, -92(%edx)
-L(aligned_16_76bytes):
- movdqa %xmm0, -76(%edx)
-L(aligned_16_60bytes):
- movdqa %xmm0, -60(%edx)
-L(aligned_16_44bytes):
- movdqa %xmm0, -44(%edx)
-L(aligned_16_28bytes):
- movdqa %xmm0, -28(%edx)
-L(aligned_16_12bytes):
- movq %xmm0, -12(%edx)
- movl %eax, -4(%edx)
- SETRTNVAL
- RETURN
-
-
- ALIGN (4)
-L(aligned_16_126bytes):
- movdqa %xmm0, -126(%edx)
-L(aligned_16_110bytes):
- movdqa %xmm0, -110(%edx)
-L(aligned_16_94bytes):
- movdqa %xmm0, -94(%edx)
-L(aligned_16_78bytes):
- movdqa %xmm0, -78(%edx)
-L(aligned_16_62bytes):
- movdqa %xmm0, -62(%edx)
-L(aligned_16_46bytes):
- movdqa %xmm0, -46(%edx)
-L(aligned_16_30bytes):
- movdqa %xmm0, -30(%edx)
-L(aligned_16_14bytes):
- movq %xmm0, -14(%edx)
- movl %eax, -6(%edx)
- movw %ax, -2(%edx)
- SETRTNVAL
- RETURN
-
-END (MEMSET)
diff --git a/libcutils/arch-x86/android_memset32.S b/libcutils/arch-x86/android_memset32.S
deleted file mode 100755
index b928f6b..0000000
--- a/libcutils/arch-x86/android_memset32.S
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright (C) 2010 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 "cache.h"
-
-#ifndef MEMSET
-# define MEMSET android_memset32
-#endif
-
-#ifndef L
-# define L(label) .L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n) .p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc .cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc .cfi_endproc
-#endif
-
-#ifndef cfi_rel_offset
-# define cfi_rel_offset(reg, off) .cfi_rel_offset reg, off
-#endif
-
-#ifndef cfi_restore
-# define cfi_restore(reg) .cfi_restore reg
-#endif
-
-#ifndef cfi_adjust_cfa_offset
-# define cfi_adjust_cfa_offset(off) .cfi_adjust_cfa_offset off
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name) \
- .type name, @function; \
- .globl name; \
- .p2align 4; \
-name: \
- cfi_startproc
-#endif
-
-#ifndef END
-# define END(name) \
- cfi_endproc; \
- .size name, .-name
-#endif
-
-#define CFI_PUSH(REG) \
- cfi_adjust_cfa_offset (4); \
- cfi_rel_offset (REG, 0)
-
-#define CFI_POP(REG) \
- cfi_adjust_cfa_offset (-4); \
- cfi_restore (REG)
-
-#define PUSH(REG) pushl REG; CFI_PUSH (REG)
-#define POP(REG) popl REG; CFI_POP (REG)
-
-#ifdef USE_AS_BZERO32
-# define DEST PARMS
-# define LEN DEST+4
-# define SETRTNVAL
-#else
-# define DEST PARMS
-# define DWDS DEST+4
-# define LEN DWDS+4
-# define SETRTNVAL movl DEST(%esp), %eax
-#endif
-
-#if (defined SHARED || defined __PIC__)
-# define ENTRANCE PUSH (%ebx);
-# define RETURN_END POP (%ebx); ret
-# define RETURN RETURN_END; CFI_PUSH (%ebx)
-# define PARMS 8 /* Preserve EBX. */
-# define JMPTBL(I, B) I - B
-
-/* Load an entry in a jump table into EBX and branch to it. TABLE is a
- jump table with relative offsets. */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \
- /* We first load PC into EBX. */ \
- call __x86.get_pc_thunk.bx; \
- /* Get the address of the jump table. */ \
- add $(TABLE - .), %ebx; \
- /* Get the entry and convert the relative offset to the \
- absolute address. */ \
- add (%ebx,%ecx,4), %ebx; \
- /* We loaded the jump table and adjuested EDX. Go. */ \
- jmp *%ebx
-
- .section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
- .globl __x86.get_pc_thunk.bx
- .hidden __x86.get_pc_thunk.bx
- ALIGN (4)
- .type __x86.get_pc_thunk.bx,@function
-__x86.get_pc_thunk.bx:
- cfi_startproc
- movl (%esp), %ebx
- ret
- cfi_endproc
-#else
-# define ENTRANCE
-# define RETURN_END ret
-# define RETURN RETURN_END
-# define PARMS 4
-# define JMPTBL(I, B) I
-
-/* Branch to an entry in a jump table. TABLE is a jump table with
- absolute offsets. */
-# define BRANCH_TO_JMPTBL_ENTRY(TABLE) \
- jmp *TABLE(,%ecx,4)
-#endif
-
- .section .text.sse2,"ax",@progbits
- ALIGN (4)
-ENTRY (MEMSET)
- ENTRANCE
-
- movl LEN(%esp), %ecx
- shr $2, %ecx
-#ifdef USE_AS_BZERO32
- xor %eax, %eax
-#else
- mov DWDS(%esp), %eax
- mov %eax, %edx
-#endif
- movl DEST(%esp), %edx
- cmp $16, %ecx
- jae L(16dbwordsormore)
-
-L(write_less16dbwords):
- lea (%edx, %ecx, 4), %edx
- BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords))
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_less16dbwords):
- .int JMPTBL (L(write_0dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_1dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_2dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_3dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_4dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_5dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_6dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_7dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_8dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_9dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_10dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_11dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_12dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_13dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_14dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_15dbwords), L(table_less16dbwords))
- .popsection
-
- ALIGN (4)
-L(write_15dbwords):
- movl %eax, -60(%edx)
-L(write_14dbwords):
- movl %eax, -56(%edx)
-L(write_13dbwords):
- movl %eax, -52(%edx)
-L(write_12dbwords):
- movl %eax, -48(%edx)
-L(write_11dbwords):
- movl %eax, -44(%edx)
-L(write_10dbwords):
- movl %eax, -40(%edx)
-L(write_9dbwords):
- movl %eax, -36(%edx)
-L(write_8dbwords):
- movl %eax, -32(%edx)
-L(write_7dbwords):
- movl %eax, -28(%edx)
-L(write_6dbwords):
- movl %eax, -24(%edx)
-L(write_5dbwords):
- movl %eax, -20(%edx)
-L(write_4dbwords):
- movl %eax, -16(%edx)
-L(write_3dbwords):
- movl %eax, -12(%edx)
-L(write_2dbwords):
- movl %eax, -8(%edx)
-L(write_1dbwords):
- movl %eax, -4(%edx)
-L(write_0dbwords):
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(16dbwordsormore):
- test $3, %edx
- jz L(aligned4bytes)
- mov %eax, (%edx)
- mov %eax, -4(%edx, %ecx, 4)
- sub $1, %ecx
- rol $24, %eax
- add $1, %edx
- test $3, %edx
- jz L(aligned4bytes)
- ror $8, %eax
- add $1, %edx
- test $3, %edx
- jz L(aligned4bytes)
- ror $8, %eax
- add $1, %edx
-L(aligned4bytes):
- shl $2, %ecx
-
-#ifdef USE_AS_BZERO32
- pxor %xmm0, %xmm0
-#else
- movd %eax, %xmm0
- pshufd $0, %xmm0, %xmm0
-#endif
- testl $0xf, %edx
- jz L(aligned_16)
-/* ECX > 32 and EDX is not 16 byte aligned. */
-L(not_aligned_16):
- movdqu %xmm0, (%edx)
- movl %edx, %eax
- and $-16, %edx
- add $16, %edx
- sub %edx, %eax
- add %eax, %ecx
- movd %xmm0, %eax
- ALIGN (4)
-L(aligned_16):
- cmp $128, %ecx
- jae L(128bytesormore)
-
-L(aligned_16_less128bytes):
- add %ecx, %edx
- shr $2, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
- ALIGN (4)
-L(128bytesormore):
-#ifdef SHARED_CACHE_SIZE
- PUSH (%ebx)
- mov $SHARED_CACHE_SIZE, %ebx
-#else
-# if (defined SHARED || defined __PIC__)
- call __x86.get_pc_thunk.bx
- add $_GLOBAL_OFFSET_TABLE_, %ebx
- mov __x86_shared_cache_size@GOTOFF(%ebx), %ebx
-# else
- PUSH (%ebx)
- mov __x86_shared_cache_size, %ebx
-# endif
-#endif
- cmp %ebx, %ecx
- jae L(128bytesormore_nt_start)
-
-#ifdef DATA_CACHE_SIZE
- POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
- cmp $DATA_CACHE_SIZE, %ecx
-#else
-# if (defined SHARED || defined __PIC__)
-# define RESTORE_EBX_STATE
- call __x86.get_pc_thunk.bx
- add $_GLOBAL_OFFSET_TABLE_, %ebx
- cmp __x86_data_cache_size@GOTOFF(%ebx), %ecx
-# else
- POP (%ebx)
-# define RESTORE_EBX_STATE CFI_PUSH (%ebx)
- cmp __x86_data_cache_size, %ecx
-# endif
-#endif
-
- jae L(128bytes_L2_normal)
- subl $128, %ecx
-L(128bytesormore_normal):
- sub $128, %ecx
- movdqa %xmm0, (%edx)
- movdqa %xmm0, 0x10(%edx)
- movdqa %xmm0, 0x20(%edx)
- movdqa %xmm0, 0x30(%edx)
- movdqa %xmm0, 0x40(%edx)
- movdqa %xmm0, 0x50(%edx)
- movdqa %xmm0, 0x60(%edx)
- movdqa %xmm0, 0x70(%edx)
- lea 128(%edx), %edx
- jb L(128bytesless_normal)
-
-
- sub $128, %ecx
- movdqa %xmm0, (%edx)
- movdqa %xmm0, 0x10(%edx)
- movdqa %xmm0, 0x20(%edx)
- movdqa %xmm0, 0x30(%edx)
- movdqa %xmm0, 0x40(%edx)
- movdqa %xmm0, 0x50(%edx)
- movdqa %xmm0, 0x60(%edx)
- movdqa %xmm0, 0x70(%edx)
- lea 128(%edx), %edx
- jae L(128bytesormore_normal)
-
-L(128bytesless_normal):
- lea 128(%ecx), %ecx
- add %ecx, %edx
- shr $2, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
- ALIGN (4)
-L(128bytes_L2_normal):
- prefetcht0 0x380(%edx)
- prefetcht0 0x3c0(%edx)
- sub $128, %ecx
- movdqa %xmm0, (%edx)
- movaps %xmm0, 0x10(%edx)
- movaps %xmm0, 0x20(%edx)
- movaps %xmm0, 0x30(%edx)
- movaps %xmm0, 0x40(%edx)
- movaps %xmm0, 0x50(%edx)
- movaps %xmm0, 0x60(%edx)
- movaps %xmm0, 0x70(%edx)
- add $128, %edx
- cmp $128, %ecx
- jae L(128bytes_L2_normal)
-
-L(128bytesless_L2_normal):
- add %ecx, %edx
- shr $2, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
- RESTORE_EBX_STATE
-L(128bytesormore_nt_start):
- sub %ebx, %ecx
- mov %ebx, %eax
- and $0x7f, %eax
- add %eax, %ecx
- movd %xmm0, %eax
- ALIGN (4)
-L(128bytesormore_shared_cache_loop):
- prefetcht0 0x3c0(%edx)
- prefetcht0 0x380(%edx)
- sub $0x80, %ebx
- movdqa %xmm0, (%edx)
- movdqa %xmm0, 0x10(%edx)
- movdqa %xmm0, 0x20(%edx)
- movdqa %xmm0, 0x30(%edx)
- movdqa %xmm0, 0x40(%edx)
- movdqa %xmm0, 0x50(%edx)
- movdqa %xmm0, 0x60(%edx)
- movdqa %xmm0, 0x70(%edx)
- add $0x80, %edx
- cmp $0x80, %ebx
- jae L(128bytesormore_shared_cache_loop)
- cmp $0x80, %ecx
- jb L(shared_cache_loop_end)
-
- ALIGN (4)
-L(128bytesormore_nt):
- sub $0x80, %ecx
- movntdq %xmm0, (%edx)
- movntdq %xmm0, 0x10(%edx)
- movntdq %xmm0, 0x20(%edx)
- movntdq %xmm0, 0x30(%edx)
- movntdq %xmm0, 0x40(%edx)
- movntdq %xmm0, 0x50(%edx)
- movntdq %xmm0, 0x60(%edx)
- movntdq %xmm0, 0x70(%edx)
- add $0x80, %edx
- cmp $0x80, %ecx
- jae L(128bytesormore_nt)
- sfence
-L(shared_cache_loop_end):
-#if defined DATA_CACHE_SIZE || !(defined SHARED || defined __PIC__)
- POP (%ebx)
-#endif
- add %ecx, %edx
- shr $2, %ecx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes))
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_16_128bytes):
- .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
- .popsection
-
- ALIGN (4)
-L(aligned_16_112bytes):
- movdqa %xmm0, -112(%edx)
-L(aligned_16_96bytes):
- movdqa %xmm0, -96(%edx)
-L(aligned_16_80bytes):
- movdqa %xmm0, -80(%edx)
-L(aligned_16_64bytes):
- movdqa %xmm0, -64(%edx)
-L(aligned_16_48bytes):
- movdqa %xmm0, -48(%edx)
-L(aligned_16_32bytes):
- movdqa %xmm0, -32(%edx)
-L(aligned_16_16bytes):
- movdqa %xmm0, -16(%edx)
-L(aligned_16_0bytes):
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(aligned_16_116bytes):
- movdqa %xmm0, -116(%edx)
-L(aligned_16_100bytes):
- movdqa %xmm0, -100(%edx)
-L(aligned_16_84bytes):
- movdqa %xmm0, -84(%edx)
-L(aligned_16_68bytes):
- movdqa %xmm0, -68(%edx)
-L(aligned_16_52bytes):
- movdqa %xmm0, -52(%edx)
-L(aligned_16_36bytes):
- movdqa %xmm0, -36(%edx)
-L(aligned_16_20bytes):
- movdqa %xmm0, -20(%edx)
-L(aligned_16_4bytes):
- movl %eax, -4(%edx)
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(aligned_16_120bytes):
- movdqa %xmm0, -120(%edx)
-L(aligned_16_104bytes):
- movdqa %xmm0, -104(%edx)
-L(aligned_16_88bytes):
- movdqa %xmm0, -88(%edx)
-L(aligned_16_72bytes):
- movdqa %xmm0, -72(%edx)
-L(aligned_16_56bytes):
- movdqa %xmm0, -56(%edx)
-L(aligned_16_40bytes):
- movdqa %xmm0, -40(%edx)
-L(aligned_16_24bytes):
- movdqa %xmm0, -24(%edx)
-L(aligned_16_8bytes):
- movq %xmm0, -8(%edx)
- SETRTNVAL
- RETURN
-
- ALIGN (4)
-L(aligned_16_124bytes):
- movdqa %xmm0, -124(%edx)
-L(aligned_16_108bytes):
- movdqa %xmm0, -108(%edx)
-L(aligned_16_92bytes):
- movdqa %xmm0, -92(%edx)
-L(aligned_16_76bytes):
- movdqa %xmm0, -76(%edx)
-L(aligned_16_60bytes):
- movdqa %xmm0, -60(%edx)
-L(aligned_16_44bytes):
- movdqa %xmm0, -44(%edx)
-L(aligned_16_28bytes):
- movdqa %xmm0, -28(%edx)
-L(aligned_16_12bytes):
- movq %xmm0, -12(%edx)
- movl %eax, -4(%edx)
- SETRTNVAL
- RETURN
-
-END (MEMSET)
diff --git a/libcutils/arch-x86_64/android_memset16.S b/libcutils/arch-x86_64/android_memset16.S
deleted file mode 100644
index cb6d4a3..0000000
--- a/libcutils/arch-x86_64/android_memset16.S
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) 2014 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 "cache.h"
-
-#ifndef MEMSET
-# define MEMSET android_memset16
-#endif
-
-#ifndef L
-# define L(label) .L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n) .p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc .cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc .cfi_endproc
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name) \
- .type name, @function; \
- .globl name; \
- .p2align 4; \
-name: \
- cfi_startproc
-#endif
-
-#ifndef END
-# define END(name) \
- cfi_endproc; \
- .size name, .-name
-#endif
-
-#define JMPTBL(I, B) I - B
-
-/* Branch to an entry in a jump table. TABLE is a jump table with
- relative offsets. INDEX is a register contains the index into the
- jump table. SCALE is the scale of INDEX. */
-#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
- lea TABLE(%rip), %r11; \
- movslq (%r11, INDEX, SCALE), INDEX; \
- lea (%r11, INDEX), INDEX; \
- jmp *INDEX
-
- .section .text.sse2,"ax",@progbits
- ALIGN (4)
-ENTRY (MEMSET) // Address in rdi
- shr $1, %rdx // Count in rdx
- movzwl %si, %ecx
- /* Fill the whole ECX with pattern. */
- shl $16, %esi
- or %esi, %ecx // Pattern in ecx
-
- cmp $32, %rdx
- jae L(32wordsormore)
-
-L(write_less32words):
- lea (%rdi, %rdx, 2), %rdi
- BRANCH_TO_JMPTBL_ENTRY (L(table_less32words), %rdx, 4)
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_less32words):
- .int JMPTBL (L(write_0words), L(table_less32words))
- .int JMPTBL (L(write_1words), L(table_less32words))
- .int JMPTBL (L(write_2words), L(table_less32words))
- .int JMPTBL (L(write_3words), L(table_less32words))
- .int JMPTBL (L(write_4words), L(table_less32words))
- .int JMPTBL (L(write_5words), L(table_less32words))
- .int JMPTBL (L(write_6words), L(table_less32words))
- .int JMPTBL (L(write_7words), L(table_less32words))
- .int JMPTBL (L(write_8words), L(table_less32words))
- .int JMPTBL (L(write_9words), L(table_less32words))
- .int JMPTBL (L(write_10words), L(table_less32words))
- .int JMPTBL (L(write_11words), L(table_less32words))
- .int JMPTBL (L(write_12words), L(table_less32words))
- .int JMPTBL (L(write_13words), L(table_less32words))
- .int JMPTBL (L(write_14words), L(table_less32words))
- .int JMPTBL (L(write_15words), L(table_less32words))
- .int JMPTBL (L(write_16words), L(table_less32words))
- .int JMPTBL (L(write_17words), L(table_less32words))
- .int JMPTBL (L(write_18words), L(table_less32words))
- .int JMPTBL (L(write_19words), L(table_less32words))
- .int JMPTBL (L(write_20words), L(table_less32words))
- .int JMPTBL (L(write_21words), L(table_less32words))
- .int JMPTBL (L(write_22words), L(table_less32words))
- .int JMPTBL (L(write_23words), L(table_less32words))
- .int JMPTBL (L(write_24words), L(table_less32words))
- .int JMPTBL (L(write_25words), L(table_less32words))
- .int JMPTBL (L(write_26words), L(table_less32words))
- .int JMPTBL (L(write_27words), L(table_less32words))
- .int JMPTBL (L(write_28words), L(table_less32words))
- .int JMPTBL (L(write_29words), L(table_less32words))
- .int JMPTBL (L(write_30words), L(table_less32words))
- .int JMPTBL (L(write_31words), L(table_less32words))
- .popsection
-
- ALIGN (4)
-L(write_28words):
- movl %ecx, -56(%rdi)
- movl %ecx, -52(%rdi)
-L(write_24words):
- movl %ecx, -48(%rdi)
- movl %ecx, -44(%rdi)
-L(write_20words):
- movl %ecx, -40(%rdi)
- movl %ecx, -36(%rdi)
-L(write_16words):
- movl %ecx, -32(%rdi)
- movl %ecx, -28(%rdi)
-L(write_12words):
- movl %ecx, -24(%rdi)
- movl %ecx, -20(%rdi)
-L(write_8words):
- movl %ecx, -16(%rdi)
- movl %ecx, -12(%rdi)
-L(write_4words):
- movl %ecx, -8(%rdi)
- movl %ecx, -4(%rdi)
-L(write_0words):
- ret
-
- ALIGN (4)
-L(write_29words):
- movl %ecx, -58(%rdi)
- movl %ecx, -54(%rdi)
-L(write_25words):
- movl %ecx, -50(%rdi)
- movl %ecx, -46(%rdi)
-L(write_21words):
- movl %ecx, -42(%rdi)
- movl %ecx, -38(%rdi)
-L(write_17words):
- movl %ecx, -34(%rdi)
- movl %ecx, -30(%rdi)
-L(write_13words):
- movl %ecx, -26(%rdi)
- movl %ecx, -22(%rdi)
-L(write_9words):
- movl %ecx, -18(%rdi)
- movl %ecx, -14(%rdi)
-L(write_5words):
- movl %ecx, -10(%rdi)
- movl %ecx, -6(%rdi)
-L(write_1words):
- mov %cx, -2(%rdi)
- ret
-
- ALIGN (4)
-L(write_30words):
- movl %ecx, -60(%rdi)
- movl %ecx, -56(%rdi)
-L(write_26words):
- movl %ecx, -52(%rdi)
- movl %ecx, -48(%rdi)
-L(write_22words):
- movl %ecx, -44(%rdi)
- movl %ecx, -40(%rdi)
-L(write_18words):
- movl %ecx, -36(%rdi)
- movl %ecx, -32(%rdi)
-L(write_14words):
- movl %ecx, -28(%rdi)
- movl %ecx, -24(%rdi)
-L(write_10words):
- movl %ecx, -20(%rdi)
- movl %ecx, -16(%rdi)
-L(write_6words):
- movl %ecx, -12(%rdi)
- movl %ecx, -8(%rdi)
-L(write_2words):
- movl %ecx, -4(%rdi)
- ret
-
- ALIGN (4)
-L(write_31words):
- movl %ecx, -62(%rdi)
- movl %ecx, -58(%rdi)
-L(write_27words):
- movl %ecx, -54(%rdi)
- movl %ecx, -50(%rdi)
-L(write_23words):
- movl %ecx, -46(%rdi)
- movl %ecx, -42(%rdi)
-L(write_19words):
- movl %ecx, -38(%rdi)
- movl %ecx, -34(%rdi)
-L(write_15words):
- movl %ecx, -30(%rdi)
- movl %ecx, -26(%rdi)
-L(write_11words):
- movl %ecx, -22(%rdi)
- movl %ecx, -18(%rdi)
-L(write_7words):
- movl %ecx, -14(%rdi)
- movl %ecx, -10(%rdi)
-L(write_3words):
- movl %ecx, -6(%rdi)
- movw %cx, -2(%rdi)
- ret
-
- ALIGN (4)
-L(32wordsormore):
- shl $1, %rdx
- test $0x01, %edi
- jz L(aligned2bytes)
- mov %ecx, (%rdi)
- mov %ecx, -4(%rdi, %rdx)
- sub $2, %rdx
- add $1, %rdi
- rol $8, %ecx
-L(aligned2bytes):
- /* Fill xmm0 with the pattern. */
- movd %ecx, %xmm0
- pshufd $0, %xmm0, %xmm0
-
- testl $0xf, %edi
- jz L(aligned_16)
-/* RDX > 32 and RDI is not 16 byte aligned. */
- movdqu %xmm0, (%rdi)
- mov %rdi, %rsi
- and $-16, %rdi
- add $16, %rdi
- sub %rdi, %rsi
- add %rsi, %rdx
-
- ALIGN (4)
-L(aligned_16):
- cmp $128, %rdx
- jge L(128bytesormore)
-
-L(aligned_16_less128bytes):
- add %rdx, %rdi
- shr $1, %rdx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
- ALIGN (4)
-L(128bytesormore):
- cmp $SHARED_CACHE_SIZE, %rdx
- jg L(128bytesormore_nt)
-
-L(128bytesormore_normal):
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jl L(128bytesless_normal)
-
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jl L(128bytesless_normal)
-
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jl L(128bytesless_normal)
-
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jge L(128bytesormore_normal)
-
-L(128bytesless_normal):
- add %rdx, %rdi
- shr $1, %rdx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
- ALIGN (4)
-L(128bytesormore_nt):
- sub $128, %rdx
- movntdq %xmm0, (%rdi)
- movntdq %xmm0, 0x10(%rdi)
- movntdq %xmm0, 0x20(%rdi)
- movntdq %xmm0, 0x30(%rdi)
- movntdq %xmm0, 0x40(%rdi)
- movntdq %xmm0, 0x50(%rdi)
- movntdq %xmm0, 0x60(%rdi)
- movntdq %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jge L(128bytesormore_nt)
-
- sfence
- add %rdx, %rdi
- shr $1, %rdx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_16_128bytes):
- .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_2bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_6bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_10bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_14bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_18bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_22bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_26bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_30bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_34bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_38bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_42bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_46bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_50bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_54bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_58bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_62bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_66bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_70bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_74bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_78bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_82bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_86bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_90bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_94bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_98bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_102bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_106bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_110bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_114bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_118bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_122bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_126bytes), L(table_16_128bytes))
- .popsection
-
- ALIGN (4)
-L(aligned_16_112bytes):
- movdqa %xmm0, -112(%rdi)
-L(aligned_16_96bytes):
- movdqa %xmm0, -96(%rdi)
-L(aligned_16_80bytes):
- movdqa %xmm0, -80(%rdi)
-L(aligned_16_64bytes):
- movdqa %xmm0, -64(%rdi)
-L(aligned_16_48bytes):
- movdqa %xmm0, -48(%rdi)
-L(aligned_16_32bytes):
- movdqa %xmm0, -32(%rdi)
-L(aligned_16_16bytes):
- movdqa %xmm0, -16(%rdi)
-L(aligned_16_0bytes):
- ret
-
- ALIGN (4)
-L(aligned_16_114bytes):
- movdqa %xmm0, -114(%rdi)
-L(aligned_16_98bytes):
- movdqa %xmm0, -98(%rdi)
-L(aligned_16_82bytes):
- movdqa %xmm0, -82(%rdi)
-L(aligned_16_66bytes):
- movdqa %xmm0, -66(%rdi)
-L(aligned_16_50bytes):
- movdqa %xmm0, -50(%rdi)
-L(aligned_16_34bytes):
- movdqa %xmm0, -34(%rdi)
-L(aligned_16_18bytes):
- movdqa %xmm0, -18(%rdi)
-L(aligned_16_2bytes):
- movw %cx, -2(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_116bytes):
- movdqa %xmm0, -116(%rdi)
-L(aligned_16_100bytes):
- movdqa %xmm0, -100(%rdi)
-L(aligned_16_84bytes):
- movdqa %xmm0, -84(%rdi)
-L(aligned_16_68bytes):
- movdqa %xmm0, -68(%rdi)
-L(aligned_16_52bytes):
- movdqa %xmm0, -52(%rdi)
-L(aligned_16_36bytes):
- movdqa %xmm0, -36(%rdi)
-L(aligned_16_20bytes):
- movdqa %xmm0, -20(%rdi)
-L(aligned_16_4bytes):
- movl %ecx, -4(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_118bytes):
- movdqa %xmm0, -118(%rdi)
-L(aligned_16_102bytes):
- movdqa %xmm0, -102(%rdi)
-L(aligned_16_86bytes):
- movdqa %xmm0, -86(%rdi)
-L(aligned_16_70bytes):
- movdqa %xmm0, -70(%rdi)
-L(aligned_16_54bytes):
- movdqa %xmm0, -54(%rdi)
-L(aligned_16_38bytes):
- movdqa %xmm0, -38(%rdi)
-L(aligned_16_22bytes):
- movdqa %xmm0, -22(%rdi)
-L(aligned_16_6bytes):
- movl %ecx, -6(%rdi)
- movw %cx, -2(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_120bytes):
- movdqa %xmm0, -120(%rdi)
-L(aligned_16_104bytes):
- movdqa %xmm0, -104(%rdi)
-L(aligned_16_88bytes):
- movdqa %xmm0, -88(%rdi)
-L(aligned_16_72bytes):
- movdqa %xmm0, -72(%rdi)
-L(aligned_16_56bytes):
- movdqa %xmm0, -56(%rdi)
-L(aligned_16_40bytes):
- movdqa %xmm0, -40(%rdi)
-L(aligned_16_24bytes):
- movdqa %xmm0, -24(%rdi)
-L(aligned_16_8bytes):
- movq %xmm0, -8(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_122bytes):
- movdqa %xmm0, -122(%rdi)
-L(aligned_16_106bytes):
- movdqa %xmm0, -106(%rdi)
-L(aligned_16_90bytes):
- movdqa %xmm0, -90(%rdi)
-L(aligned_16_74bytes):
- movdqa %xmm0, -74(%rdi)
-L(aligned_16_58bytes):
- movdqa %xmm0, -58(%rdi)
-L(aligned_16_42bytes):
- movdqa %xmm0, -42(%rdi)
-L(aligned_16_26bytes):
- movdqa %xmm0, -26(%rdi)
-L(aligned_16_10bytes):
- movq %xmm0, -10(%rdi)
- movw %cx, -2(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_124bytes):
- movdqa %xmm0, -124(%rdi)
-L(aligned_16_108bytes):
- movdqa %xmm0, -108(%rdi)
-L(aligned_16_92bytes):
- movdqa %xmm0, -92(%rdi)
-L(aligned_16_76bytes):
- movdqa %xmm0, -76(%rdi)
-L(aligned_16_60bytes):
- movdqa %xmm0, -60(%rdi)
-L(aligned_16_44bytes):
- movdqa %xmm0, -44(%rdi)
-L(aligned_16_28bytes):
- movdqa %xmm0, -28(%rdi)
-L(aligned_16_12bytes):
- movq %xmm0, -12(%rdi)
- movl %ecx, -4(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_126bytes):
- movdqa %xmm0, -126(%rdi)
-L(aligned_16_110bytes):
- movdqa %xmm0, -110(%rdi)
-L(aligned_16_94bytes):
- movdqa %xmm0, -94(%rdi)
-L(aligned_16_78bytes):
- movdqa %xmm0, -78(%rdi)
-L(aligned_16_62bytes):
- movdqa %xmm0, -62(%rdi)
-L(aligned_16_46bytes):
- movdqa %xmm0, -46(%rdi)
-L(aligned_16_30bytes):
- movdqa %xmm0, -30(%rdi)
-L(aligned_16_14bytes):
- movq %xmm0, -14(%rdi)
- movl %ecx, -6(%rdi)
- movw %cx, -2(%rdi)
- ret
-
-END (MEMSET)
diff --git a/libcutils/arch-x86_64/android_memset32.S b/libcutils/arch-x86_64/android_memset32.S
deleted file mode 100644
index 1514aa2..0000000
--- a/libcutils/arch-x86_64/android_memset32.S
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * Copyright (C) 2014 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 "cache.h"
-
-#ifndef MEMSET
-# define MEMSET android_memset32
-#endif
-
-#ifndef L
-# define L(label) .L##label
-#endif
-
-#ifndef ALIGN
-# define ALIGN(n) .p2align n
-#endif
-
-#ifndef cfi_startproc
-# define cfi_startproc .cfi_startproc
-#endif
-
-#ifndef cfi_endproc
-# define cfi_endproc .cfi_endproc
-#endif
-
-#ifndef ENTRY
-# define ENTRY(name) \
- .type name, @function; \
- .globl name; \
- .p2align 4; \
-name: \
- cfi_startproc
-#endif
-
-#ifndef END
-# define END(name) \
- cfi_endproc; \
- .size name, .-name
-#endif
-
-#define JMPTBL(I, B) I - B
-
-/* Branch to an entry in a jump table. TABLE is a jump table with
- relative offsets. INDEX is a register contains the index into the
- jump table. SCALE is the scale of INDEX. */
-#define BRANCH_TO_JMPTBL_ENTRY(TABLE, INDEX, SCALE) \
- lea TABLE(%rip), %r11; \
- movslq (%r11, INDEX, SCALE), INDEX; \
- lea (%r11, INDEX), INDEX; \
- jmp *INDEX
-
- .section .text.sse2,"ax",@progbits
- ALIGN (4)
-ENTRY (MEMSET) // Address in rdi
- shr $2, %rdx // Count in rdx
- movl %esi, %ecx // Pattern in ecx
-
- cmp $16, %rdx
- jae L(16dbwordsormore)
-
-L(write_less16dbwords):
- lea (%rdi, %rdx, 4), %rdi
- BRANCH_TO_JMPTBL_ENTRY (L(table_less16dbwords), %rdx, 4)
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_less16dbwords):
- .int JMPTBL (L(write_0dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_1dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_2dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_3dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_4dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_5dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_6dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_7dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_8dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_9dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_10dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_11dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_12dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_13dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_14dbwords), L(table_less16dbwords))
- .int JMPTBL (L(write_15dbwords), L(table_less16dbwords))
- .popsection
-
- ALIGN (4)
-L(write_15dbwords):
- movl %ecx, -60(%rdi)
-L(write_14dbwords):
- movl %ecx, -56(%rdi)
-L(write_13dbwords):
- movl %ecx, -52(%rdi)
-L(write_12dbwords):
- movl %ecx, -48(%rdi)
-L(write_11dbwords):
- movl %ecx, -44(%rdi)
-L(write_10dbwords):
- movl %ecx, -40(%rdi)
-L(write_9dbwords):
- movl %ecx, -36(%rdi)
-L(write_8dbwords):
- movl %ecx, -32(%rdi)
-L(write_7dbwords):
- movl %ecx, -28(%rdi)
-L(write_6dbwords):
- movl %ecx, -24(%rdi)
-L(write_5dbwords):
- movl %ecx, -20(%rdi)
-L(write_4dbwords):
- movl %ecx, -16(%rdi)
-L(write_3dbwords):
- movl %ecx, -12(%rdi)
-L(write_2dbwords):
- movl %ecx, -8(%rdi)
-L(write_1dbwords):
- movl %ecx, -4(%rdi)
-L(write_0dbwords):
- ret
-
- ALIGN (4)
-L(16dbwordsormore):
- test $3, %edi
- jz L(aligned4bytes)
- mov %ecx, (%rdi)
- mov %ecx, -4(%rdi, %rdx, 4)
- sub $1, %rdx
- rol $24, %ecx
- add $1, %rdi
- test $3, %edi
- jz L(aligned4bytes)
- ror $8, %ecx
- add $1, %rdi
- test $3, %edi
- jz L(aligned4bytes)
- ror $8, %ecx
- add $1, %rdi
-L(aligned4bytes):
- shl $2, %rdx
-
- /* Fill xmm0 with the pattern. */
- movd %ecx, %xmm0
- pshufd $0, %xmm0, %xmm0
-
- testl $0xf, %edi
- jz L(aligned_16)
-/* RDX > 32 and RDI is not 16 byte aligned. */
- movdqu %xmm0, (%rdi)
- mov %rdi, %rsi
- and $-16, %rdi
- add $16, %rdi
- sub %rdi, %rsi
- add %rsi, %rdx
-
- ALIGN (4)
-L(aligned_16):
- cmp $128, %rdx
- jge L(128bytesormore)
-
-L(aligned_16_less128bytes):
- add %rdx, %rdi
- shr $2, %rdx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
- ALIGN (4)
-L(128bytesormore):
- cmp $SHARED_CACHE_SIZE, %rdx
- jg L(128bytesormore_nt)
-
-L(128bytesormore_normal):
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jl L(128bytesless_normal)
-
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jl L(128bytesless_normal)
-
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jl L(128bytesless_normal)
-
- sub $128, %rdx
- movdqa %xmm0, (%rdi)
- movdqa %xmm0, 0x10(%rdi)
- movdqa %xmm0, 0x20(%rdi)
- movdqa %xmm0, 0x30(%rdi)
- movdqa %xmm0, 0x40(%rdi)
- movdqa %xmm0, 0x50(%rdi)
- movdqa %xmm0, 0x60(%rdi)
- movdqa %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jge L(128bytesormore_normal)
-
-L(128bytesless_normal):
- add %rdx, %rdi
- shr $2, %rdx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
- ALIGN (4)
-L(128bytesormore_nt):
- sub $128, %rdx
- movntdq %xmm0, (%rdi)
- movntdq %xmm0, 0x10(%rdi)
- movntdq %xmm0, 0x20(%rdi)
- movntdq %xmm0, 0x30(%rdi)
- movntdq %xmm0, 0x40(%rdi)
- movntdq %xmm0, 0x50(%rdi)
- movntdq %xmm0, 0x60(%rdi)
- movntdq %xmm0, 0x70(%rdi)
- lea 128(%rdi), %rdi
- cmp $128, %rdx
- jge L(128bytesormore_nt)
-
- sfence
- add %rdx, %rdi
- shr $2, %rdx
- BRANCH_TO_JMPTBL_ENTRY (L(table_16_128bytes), %rdx, 4)
-
- .pushsection .rodata.sse2,"a",@progbits
- ALIGN (2)
-L(table_16_128bytes):
- .int JMPTBL (L(aligned_16_0bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_4bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_8bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_12bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_16bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_20bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_24bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_28bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_32bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_36bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_40bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_44bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_48bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_52bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_56bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_60bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_64bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_68bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_72bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_76bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_80bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_84bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_88bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_92bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_96bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_100bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_104bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_108bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_112bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_116bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_120bytes), L(table_16_128bytes))
- .int JMPTBL (L(aligned_16_124bytes), L(table_16_128bytes))
- .popsection
-
- ALIGN (4)
-L(aligned_16_112bytes):
- movdqa %xmm0, -112(%rdi)
-L(aligned_16_96bytes):
- movdqa %xmm0, -96(%rdi)
-L(aligned_16_80bytes):
- movdqa %xmm0, -80(%rdi)
-L(aligned_16_64bytes):
- movdqa %xmm0, -64(%rdi)
-L(aligned_16_48bytes):
- movdqa %xmm0, -48(%rdi)
-L(aligned_16_32bytes):
- movdqa %xmm0, -32(%rdi)
-L(aligned_16_16bytes):
- movdqa %xmm0, -16(%rdi)
-L(aligned_16_0bytes):
- ret
-
- ALIGN (4)
-L(aligned_16_116bytes):
- movdqa %xmm0, -116(%rdi)
-L(aligned_16_100bytes):
- movdqa %xmm0, -100(%rdi)
-L(aligned_16_84bytes):
- movdqa %xmm0, -84(%rdi)
-L(aligned_16_68bytes):
- movdqa %xmm0, -68(%rdi)
-L(aligned_16_52bytes):
- movdqa %xmm0, -52(%rdi)
-L(aligned_16_36bytes):
- movdqa %xmm0, -36(%rdi)
-L(aligned_16_20bytes):
- movdqa %xmm0, -20(%rdi)
-L(aligned_16_4bytes):
- movl %ecx, -4(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_120bytes):
- movdqa %xmm0, -120(%rdi)
-L(aligned_16_104bytes):
- movdqa %xmm0, -104(%rdi)
-L(aligned_16_88bytes):
- movdqa %xmm0, -88(%rdi)
-L(aligned_16_72bytes):
- movdqa %xmm0, -72(%rdi)
-L(aligned_16_56bytes):
- movdqa %xmm0, -56(%rdi)
-L(aligned_16_40bytes):
- movdqa %xmm0, -40(%rdi)
-L(aligned_16_24bytes):
- movdqa %xmm0, -24(%rdi)
-L(aligned_16_8bytes):
- movq %xmm0, -8(%rdi)
- ret
-
- ALIGN (4)
-L(aligned_16_124bytes):
- movdqa %xmm0, -124(%rdi)
-L(aligned_16_108bytes):
- movdqa %xmm0, -108(%rdi)
-L(aligned_16_92bytes):
- movdqa %xmm0, -92(%rdi)
-L(aligned_16_76bytes):
- movdqa %xmm0, -76(%rdi)
-L(aligned_16_60bytes):
- movdqa %xmm0, -60(%rdi)
-L(aligned_16_44bytes):
- movdqa %xmm0, -44(%rdi)
-L(aligned_16_28bytes):
- movdqa %xmm0, -28(%rdi)
-L(aligned_16_12bytes):
- movq %xmm0, -12(%rdi)
- movl %ecx, -4(%rdi)
- ret
-
-END (MEMSET)
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 233d400..6a27f9a 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -159,9 +159,11 @@
return false;
}
- /* Check if kernel support exists, otherwise fall back to ashmem */
+ // Check if kernel support exists, otherwise fall back to ashmem.
+ // This code needs to build on old API levels, so we can't use the libc
+ // wrapper.
android::base::unique_fd fd(
- syscall(__NR_memfd_create, "test_android_memfd", MFD_ALLOW_SEALING));
+ syscall(__NR_memfd_create, "test_android_memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING));
if (fd == -1) {
ALOGE("memfd_create failed: %s, no memfd support.\n", strerror(errno));
return false;
@@ -333,7 +335,9 @@
}
static int memfd_create_region(const char* name, size_t size) {
- android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_ALLOW_SEALING));
+ // This code needs to build on old API levels, so we can't use the libc
+ // wrapper.
+ android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_CLOEXEC | MFD_ALLOW_SEALING));
if (fd == -1) {
ALOGE("memfd_create(%s, %zd) failed: %s\n", name, size, strerror(errno));
diff --git a/libcutils/ashmem_test.cpp b/libcutils/ashmem_test.cpp
index b37d020..fb657f6 100644
--- a/libcutils/ashmem_test.cpp
+++ b/libcutils/ashmem_test.cpp
@@ -35,6 +35,11 @@
ASSERT_TRUE(ashmem_valid(fd));
ASSERT_EQ(size, static_cast<size_t>(ashmem_get_size_region(fd)));
ASSERT_EQ(0, ashmem_set_prot_region(fd, prot));
+
+ // We've been inconsistent historically about whether or not these file
+ // descriptors were CLOEXEC. Make sure we're consistent going forward.
+ // https://issuetracker.google.com/165667331
+ ASSERT_EQ(FD_CLOEXEC, (fcntl(fd, F_GETFD) & FD_CLOEXEC));
}
void TestMmap(const unique_fd& fd, size_t size, int prot, void** region, off_t off = 0) {
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index b9fc82e..31e1679 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -80,6 +80,7 @@
{ 00771, AID_SYSTEM, AID_SYSTEM, 0, "data" },
{ 00755, AID_ROOT, AID_SYSTEM, 0, "mnt" },
{ 00751, AID_ROOT, AID_SHELL, 0, "product/bin" },
+ { 00751, AID_ROOT, AID_SHELL, 0, "product/apex/*/bin" },
{ 00777, AID_ROOT, AID_ROOT, 0, "sdcard" },
{ 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system/bin" },
@@ -90,6 +91,7 @@
{ 00751, AID_ROOT, AID_SHELL, 0, "system_ext/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "system_ext/apex/*/bin" },
{ 00751, AID_ROOT, AID_SHELL, 0, "vendor/bin" },
+ { 00751, AID_ROOT, AID_SHELL, 0, "vendor/apex/*/bin" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor" },
{ 00755, AID_ROOT, AID_ROOT, 0, 0 },
// clang-format on
@@ -210,12 +212,14 @@
{ 00750, AID_ROOT, AID_SHELL, 0, "init*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "odm/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "product/bin/*" },
+ { 00755, AID_ROOT, AID_SHELL, 0, "product/apex/*bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/xbin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system/apex/*/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system_ext/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "system_ext/apex/*/bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/bin/*" },
+ { 00755, AID_ROOT, AID_SHELL, 0, "vendor/apex/*bin/*" },
{ 00755, AID_ROOT, AID_SHELL, 0, "vendor/xbin/*" },
{ 00644, AID_ROOT, AID_ROOT, 0, 0 },
// clang-format on
diff --git a/libcutils/include/cutils/memory.h b/libcutils/include/cutils/memory.h
index 4d26882..0fba53c 100644
--- a/libcutils/include/cutils/memory.h
+++ b/libcutils/include/cutils/memory.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_CUTILS_MEMORY_H
-#define ANDROID_CUTILS_MEMORY_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -24,19 +23,14 @@
extern "C" {
#endif
-/* size is given in bytes and must be multiple of 2 */
-void android_memset16(uint16_t* dst, uint16_t value, size_t size);
-
-/* size is given in bytes and must be multiple of 4 */
-void android_memset32(uint32_t* dst, uint32_t value, size_t size);
-
#if defined(__GLIBC__) || defined(_WIN32)
/* Declaration of strlcpy() for platforms that don't already have it. */
size_t strlcpy(char *dst, const char *src, size_t size);
#endif
+// Disables memory mitigations for the entire process, and logs appropriately.
+void process_disable_memory_mitigations();
+
#ifdef __cplusplus
} // extern "C"
#endif
-
-#endif // ANDROID_CUTILS_MEMORY_H
diff --git a/libcutils/memory.cpp b/libcutils/memory.cpp
new file mode 100644
index 0000000..f526520
--- /dev/null
+++ b/libcutils/memory.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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 <cutils/memory.h>
+
+#include <log/log.h>
+
+#ifdef __BIONIC__
+#include <bionic/malloc.h>
+#endif
+
+void process_disable_memory_mitigations() {
+ bool success = false;
+#ifdef __BIONIC__
+ // TODO(b/158870657) is fixed and scudo is used globally, we can assert when an
+ // an error is returned.
+
+ success = android_mallopt(M_DISABLE_MEMORY_MITIGATIONS, nullptr, 0);
+#endif
+
+ if (success) {
+ ALOGI("Disabled memory mitigations for process.");
+ } else {
+ ALOGE("Could not disable memory mitigations for process.");
+ }
+}
diff --git a/libcutils/memset_test.cpp b/libcutils/memset_test.cpp
deleted file mode 100644
index a98485f..0000000
--- a/libcutils/memset_test.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2014 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 <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-
-#include <memory>
-
-#include <cutils/memory.h>
-#include <gtest/gtest.h>
-
-#define FENCEPOST_LENGTH 8
-
-#define MAX_TEST_SIZE (64*1024)
-// Choose values that have no repeating byte values.
-#define MEMSET16_PATTERN 0xb139
-#define MEMSET32_PATTERN 0x48193a27
-
-enum test_e {
- MEMSET16 = 0,
- MEMSET32,
-};
-
-static int g_memset16_aligns[][2] = {
- { 2, 0 },
- { 4, 0 },
- { 8, 0 },
- { 16, 0 },
- { 32, 0 },
- { 64, 0 },
- { 128, 0 },
-
- { 4, 2 },
-
- { 8, 2 },
- { 8, 4 },
- { 8, 6 },
-
- { 128, 2 },
- { 128, 4 },
- { 128, 6 },
- { 128, 8 },
- { 128, 10 },
- { 128, 12 },
- { 128, 14 },
- { 128, 16 },
-};
-
-static int g_memset32_aligns[][2] = {
- { 4, 0 },
- { 8, 0 },
- { 16, 0 },
- { 32, 0 },
- { 64, 0 },
- { 128, 0 },
-
- { 8, 4 },
-
- { 128, 4 },
- { 128, 8 },
- { 128, 12 },
- { 128, 16 },
-};
-
-static size_t GetIncrement(size_t len, size_t min_incr) {
- if (len >= 4096) {
- return 1024;
- } else if (len >= 1024) {
- return 256;
- }
- return min_incr;
-}
-
-// Return a pointer into the current buffer with the specified alignment.
-static void *GetAlignedPtr(void *orig_ptr, int alignment, int or_mask) {
- uint64_t ptr = reinterpret_cast<uint64_t>(orig_ptr);
- if (alignment > 0) {
- // When setting the alignment, set it to exactly the alignment chosen.
- // The pointer returned will be guaranteed not to be aligned to anything
- // more than that.
- ptr += alignment - (ptr & (alignment - 1));
- ptr |= alignment | or_mask;
- }
-
- return reinterpret_cast<void*>(ptr);
-}
-
-static void SetFencepost(uint8_t *buffer) {
- for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
- buffer[i] = 0xde;
- buffer[i+1] = 0xad;
- }
-}
-
-static void VerifyFencepost(uint8_t *buffer) {
- for (int i = 0; i < FENCEPOST_LENGTH; i += 2) {
- if (buffer[i] != 0xde || buffer[i+1] != 0xad) {
- uint8_t expected_value;
- if (buffer[i] == 0xde) {
- i++;
- expected_value = 0xad;
- } else {
- expected_value = 0xde;
- }
- ASSERT_EQ(expected_value, buffer[i]);
- }
- }
-}
-
-void RunMemsetTests(test_e test_type, uint32_t value, int align[][2], size_t num_aligns) {
- size_t min_incr = 4;
- if (test_type == MEMSET16) {
- min_incr = 2;
- value |= value << 16;
- }
- std::unique_ptr<uint32_t[]> expected_buf(new uint32_t[MAX_TEST_SIZE/sizeof(uint32_t)]);
- for (size_t i = 0; i < MAX_TEST_SIZE/sizeof(uint32_t); i++) {
- expected_buf[i] = value;
- }
-
- // Allocate one large buffer with lots of extra space so that we can
- // guarantee that all possible alignments will fit.
- std::unique_ptr<uint8_t[]> buf(new uint8_t[3*MAX_TEST_SIZE]);
- uint8_t *buf_align;
- for (size_t i = 0; i < num_aligns; i++) {
- size_t incr = min_incr;
- for (size_t len = incr; len <= MAX_TEST_SIZE; len += incr) {
- incr = GetIncrement(len, min_incr);
-
- buf_align = reinterpret_cast<uint8_t*>(GetAlignedPtr(
- buf.get()+FENCEPOST_LENGTH, align[i][0], align[i][1]));
-
- SetFencepost(&buf_align[-FENCEPOST_LENGTH]);
- SetFencepost(&buf_align[len]);
-
- memset(buf_align, 0xff, len);
- if (test_type == MEMSET16) {
- android_memset16(reinterpret_cast<uint16_t*>(buf_align), value, len);
- } else {
- android_memset32(reinterpret_cast<uint32_t*>(buf_align), value, len);
- }
- ASSERT_EQ(0, memcmp(expected_buf.get(), buf_align, len))
- << "Failed size " << len << " align " << align[i][0] << " " << align[i][1] << "\n";
-
- VerifyFencepost(&buf_align[-FENCEPOST_LENGTH]);
- VerifyFencepost(&buf_align[len]);
- }
- }
-}
-
-TEST(libcutils, android_memset16_non_zero) {
- RunMemsetTests(MEMSET16, MEMSET16_PATTERN, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
-}
-
-TEST(libcutils, android_memset16_zero) {
- RunMemsetTests(MEMSET16, 0, g_memset16_aligns, sizeof(g_memset16_aligns)/sizeof(int[2]));
-}
-
-TEST(libcutils, android_memset32_non_zero) {
- RunMemsetTests(MEMSET32, MEMSET32_PATTERN, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
-}
-
-TEST(libcutils, android_memset32_zero) {
- RunMemsetTests(MEMSET32, 0, g_memset32_aligns, sizeof(g_memset32_aligns)/sizeof(int[2]));
-}
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 5a09a2d..1ab63dc 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -30,9 +30,9 @@
static void atrace_init_once()
{
- atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+ atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
if (atrace_marker_fd == -1) {
- atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+ atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
}
if (atrace_marker_fd == -1) {
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index 3ec98b3..6543426 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -198,7 +198,7 @@
}
#define WRITE_MSG(format_begin, format_end, name, value) { \
- char buf[ATRACE_MESSAGE_LENGTH]; \
+ char buf[ATRACE_MESSAGE_LENGTH] __attribute__((uninitialized)); \
int pid = getpid(); \
int len = snprintf(buf, sizeof(buf), format_begin "%s" format_end, pid, \
name, value); \
diff --git a/liblog b/liblog
new file mode 120000
index 0000000..71443ae
--- /dev/null
+++ b/liblog
@@ -0,0 +1 @@
+../logging/liblog
\ No newline at end of file
diff --git a/liblog/.clang-format b/liblog/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/liblog/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/liblog/Android.bp b/liblog/Android.bp
deleted file mode 100644
index 6051ac7..0000000
--- a/liblog/Android.bp
+++ /dev/null
@@ -1,154 +0,0 @@
-//
-// Copyright (C) 2008-2014 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.
-//
-
-liblog_sources = [
- "log_event_list.cpp",
- "log_event_write.cpp",
- "logger_name.cpp",
- "logger_read.cpp",
- "logger_write.cpp",
- "logprint.cpp",
- "properties.cpp",
-]
-liblog_target_sources = [
- "event_tag_map.cpp",
- "log_time.cpp",
- "pmsg_reader.cpp",
- "pmsg_writer.cpp",
- "logd_reader.cpp",
- "logd_writer.cpp",
-]
-
-cc_library_headers {
- name: "liblog_headers",
- host_supported: true,
- vendor_available: true,
- ramdisk_available: true,
- recovery_available: true,
- apex_available: [
- "//apex_available:platform",
- "//apex_available:anyapex",
- ],
- min_sdk_version: "29",
- native_bridge_supported: true,
- export_include_dirs: ["include"],
- system_shared_libs: [],
- stl: "none",
- target: {
- windows: {
- enabled: true,
- },
- linux_bionic: {
- enabled: true,
- },
- vendor: {
- override_export_include_dirs: ["include_vndk"],
- },
- },
-}
-
-// Shared and static library for host and device
-// ========================================================
-cc_library {
- name: "liblog",
- host_supported: true,
- ramdisk_available: true,
- recovery_available: true,
- native_bridge_supported: true,
- srcs: liblog_sources,
-
- target: {
- android: {
- version_script: "liblog.map.txt",
- srcs: liblog_target_sources,
- // AddressSanitizer runtime library depends on liblog.
- sanitize: {
- address: false,
- },
- },
- android_arm: {
- // TODO: This is to work around b/24465209. Remove after root cause is fixed
- pack_relocations: false,
- ldflags: ["-Wl,--hash-style=both"],
- },
- windows: {
- enabled: true,
- },
- not_windows: {
- srcs: ["event_tag_map.cpp"],
- },
- linux_bionic: {
- enabled: true,
- },
- },
-
- header_libs: [
- "libbase_headers",
- "liblog_headers",
- ],
- export_header_lib_headers: ["liblog_headers"],
-
- stubs: {
- symbol_file: "liblog.map.txt",
- versions: ["29", "30"],
- },
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- // This is what we want to do:
- // liblog_cflags := $(shell \
- // sed -n \
- // 's/^\([0-9]*\)[ \t]*liblog[ \t].*/-DLIBLOG_LOG_TAG=\1/p' \
- // $(LOCAL_PATH)/event.logtags)
- // so make sure we do not regret hard-coding it as follows:
- "-DLIBLOG_LOG_TAG=1006",
- "-DSNET_EVENT_LOG_TAG=1397638484",
- ],
- logtags: ["event.logtags"],
- compile_multilib: "both",
- apex_available: [
- "//apex_available:platform",
- // liblog is exceptionally available to the runtime APEX
- // because the dynamic linker has to use it statically.
- // See b/151051671
- "com.android.runtime",
- // DO NOT add more apex names here
- ],
-}
-
-ndk_headers {
- name: "liblog_ndk_headers",
- from: "include/android",
- to: "android",
- srcs: ["include/android/log.h"],
- license: "NOTICE",
-}
-
-ndk_library {
- name: "liblog",
- symbol_file: "liblog.map.txt",
- first_version: "9",
- unversioned_until: "current",
-}
-
-llndk_library {
- name: "liblog",
- native_bridge_supported: true,
- symbol_file: "liblog.map.txt",
- export_include_dirs: ["include_vndk"],
-}
diff --git a/liblog/NOTICE b/liblog/NOTICE
deleted file mode 100644
index 06a9081..0000000
--- a/liblog/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2014, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/liblog/OWNERS b/liblog/OWNERS
deleted file mode 100644
index babbe4d..0000000
--- a/liblog/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tomcherry@google.com
diff --git a/liblog/README.md b/liblog/README.md
deleted file mode 100644
index 74a2cd7..0000000
--- a/liblog/README.md
+++ /dev/null
@@ -1,161 +0,0 @@
-Android liblog
---------------
-
-Public Functions and Macros
----------------------------
-
- /*
- * Please limit to 24 characters for runtime is loggable,
- * 16 characters for persist is loggable, and logcat pretty
- * alignment with limit of 7 characters.
- */
- #define LOG_TAG "yourtag"
- #include <log/log.h>
-
- ALOG(android_priority, tag, format, ...)
- IF_ALOG(android_priority, tag)
- LOG_PRI(priority, tag, format, ...)
- LOG_PRI_VA(priority, tag, format, args)
- #define LOG_TAG NULL
- ALOGV(format, ...)
- SLOGV(format, ...)
- RLOGV(format, ...)
- ALOGV_IF(cond, format, ...)
- SLOGV_IF(cond, format, ...)
- RLOGV_IF(cond, format, ...)
- IF_ALOGC()
- ALOGD(format, ...)
- SLOGD(format, ...)
- RLOGD(format, ...)
- ALOGD_IF(cond, format, ...)
- SLOGD_IF(cond, format, ...)
- RLOGD_IF(cond, format, ...)
- IF_ALOGD()
- ALOGI(format, ...)
- SLOGI(format, ...)
- RLOGI(format, ...)
- ALOGI_IF(cond, format, ...)
- SLOGI_IF(cond, format, ...)
- RLOGI_IF(cond, format, ...)
- IF_ALOGI()
- ALOGW(format, ...)
- SLOGW(format, ...)
- RLOGW(format, ...)
- ALOGW_IF(cond, format, ...)
- SLOGW_IF(cond, format, ...)
- RLOGW_IF(cond, format, ...)
- IF_ALOGW()
- ALOGE(format, ...)
- SLOGE(format, ...)
- RLOGE(format, ...)
- ALOGE_IF(cond, format, ...)
- SLOGE_IF(cond, format, ...)
- RLOGE_IF(cond, format, ...)
- IF_ALOGE()
- LOG_FATAL(format, ...)
- LOG_ALWAYS_FATAL(format, ...)
- LOG_FATAL_IF(cond, format, ...)
- LOG_ALWAYS_FATAL_IF(cond, format, ...)
- ALOG_ASSERT(cond, format, ...)
- LOG_EVENT_INT(tag, value)
- LOG_EVENT_LONG(tag, value)
-
- log_id_t android_logger_get_id(struct logger *logger)
- int android_logger_clear(struct logger *logger)
- int android_logger_get_log_size(struct logger *logger)
- int android_logger_get_log_readable_size(struct logger *logger)
- int android_logger_get_log_version(struct logger *logger)
-
- struct logger_list *android_logger_list_alloc(int mode, unsigned int tail, pid_t pid)
- struct logger *android_logger_open(struct logger_list *logger_list, log_id_t id)
- struct logger_list *android_logger_list_open(log_id_t id, int mode, unsigned int tail, pid_t pid)
- int android_logger_list_read(struct logger_list *logger_list, struct log_msg *log_msg)
- void android_logger_list_free(struct logger_list *logger_list)
-
- log_id_t android_name_to_log_id(const char *logName)
- const char *android_log_id_to_name(log_id_t log_id)
-
- android_log_context create_android_logger(uint32_t tag)
-
- int android_log_write_list_begin(android_log_context ctx)
- int android_log_write_list_end(android_log_context ctx)
-
- int android_log_write_int32(android_log_context ctx, int32_t value)
- int android_log_write_int64(android_log_context ctx, int64_t value)
- int android_log_write_string8(android_log_context ctx, const char *value)
- int android_log_write_string8_len(android_log_context ctx, const char *value, size_t maxlen)
- int android_log_write_float32(android_log_context ctx, float value)
-
- int android_log_write_list(android_log_context ctx, log_id_t id = LOG_ID_EVENTS)
-
- android_log_context create_android_log_parser(const char *msg, size_t len)
- android_log_list_element android_log_read_next(android_log_context ctx)
- android_log_list_element android_log_peek_next(android_log_context ctx)
-
- int android_log_destroy(android_log_context *ctx)
-
-Description
------------
-
-liblog represents an interface to the volatile Android Logging system for NDK (Native) applications
-and libraries. Interfaces for either writing or reading logs. The log buffers are divided up in
-Main, System, Radio and Events sub-logs.
-
-The logging interfaces are a series of macros, all of which can be overridden individually in order
-to control the verbosity of the application or library. `[ASR]LOG[VDIWE]` calls are used to log to
-BAsic, System or Radio sub-logs in either the Verbose, Debug, Info, Warning or Error priorities.
-`[ASR]LOG[VDIWE]_IF` calls are used to perform thus based on a condition being true.
-`IF_ALOG[VDIWE]` calls are true if the current `LOG_TAG` is enabled at the specified priority.
-`LOG_ALWAYS_FATAL` is used to `ALOG` a message, then kill the process. `LOG_FATAL` call is a
-variant of `LOG_ALWAYS_FATAL`, only enabled in engineering, and not release builds. `ALOG_ASSERT`
-is used to `ALOG` a message if the condition is false; the condition is part of the logged message.
-`LOG_EVENT_(INT|LONG)` is used to drop binary content into the Events sub-log.
-
-The log reading interfaces permit opening the logs either singly or multiply, retrieving a log entry
-at a time in time sorted order, optionally limited to a specific pid and tail of the log(s) and
-finally a call closing the logs. A single log can be opened with `android_logger_list_open()`; or
-multiple logs can be opened with `android_logger_list_alloc()`, calling in turn the
-`android_logger_open()` for each log id. Each entry can be retrieved with
-`android_logger_list_read()`. The log(s) can be closed with `android_logger_list_free()`.
-`ANDROID_LOG_NONBLOCK` mode will report when the log reading is done with an `EAGAIN` error return
-code, otherwise the `android_logger_list_read()` call will block for new entries.
-
-The `ANDROID_LOG_WRAP` mode flag to the `android_logger_list_alloc_time()` signals logd to quiesce
-the reader until the buffer is about to prune at the start time then proceed to dumping content.
-
-The `ANDROID_LOG_PSTORE` mode flag to the `android_logger_open()` is used to switch from the active
-logs to the persistent logs from before the last reboot.
-
-The value returned by `android_logger_open()` can be used as a parameter to the
-`android_logger_clear()` function to empty the sub-log.
-
-The value returned by `android_logger_open()` can be used as a parameter to the
-`android_logger_get_log_(size|readable_size|version)` to retrieve the sub-log maximum size, readable
-size and log buffer format protocol version respectively. `android_logger_get_id()` returns the id
-that was used when opening the sub-log.
-
-Errors
-------
-
-If messages fail, a negative error code will be returned to the caller.
-
-The `-ENOTCONN` return code indicates that the logger daemon is stopped.
-
-The `-EBADF` return code indicates that the log access point can not be opened, or the log buffer id
-is out of range.
-
-For the `-EAGAIN` return code, this means that the logging message was temporarily backed-up either
-because of Denial Of Service (DOS) logging pressure from some chatty application or service in the
-Android system, or if too small of a value is set in /proc/sys/net/unix/max_dgram_qlen. To aid in
-diagnosing the occurence of this, a binary event from liblog will be sent to the log daemon once a
-new message can get through indicating how many messages were dropped as a result. Please take
-action to resolve the structural problems at the source.
-
-It is generally not advised for the caller to retry the `-EAGAIN` return code as this will only make
-the problem(s) worse and cause your application to temporarily drop to the logger daemon priority,
-BATCH scheduling policy and background task cgroup. If you require a group of messages to be passed
-atomically, merge them into one message with embedded newlines to the maximum length
-`LOGGER_ENTRY_MAX_PAYLOAD`.
-
-Other return codes from writing operation can be returned. Since the library retries on `EINTR`,
-`-EINTR` should never be returned.
diff --git a/liblog/README.protocol.md b/liblog/README.protocol.md
deleted file mode 100644
index f247b28..0000000
--- a/liblog/README.protocol.md
+++ /dev/null
@@ -1,92 +0,0 @@
-# liblog -> logd
-
-The data that liblog sends to logd is represented below.
-
- struct {
- android_log_header_t header;
- union {
- struct {
- char prio;
- char tag[...];
- char message[...];
- } string;
- struct {
- android_event_header_t event_header;
- android_event_*_t payload[...];
- } binary;
- };
- };
-
-where the embedded structs are defined as:
-
- struct android_log_header_t {
- uint8_t id;
- uint16_t tid;
- log_time realtime;
- };
-
- struct log_time {
- uint32_t tv_sec = 0;
- uint32_t tv_nsec = 0;
- }
-
- struct android_event_header_t {
- int32_t tag;
- };
-
- struct android_event_list_t {
- int8_t type; // EVENT_TYPE_LIST
- int8_t element_count;
- };
-
- struct android_event_float_t {
- int8_t type; // EVENT_TYPE_FLOAT
- float data;
- };
-
- struct android_event_int_t {
- int8_t type; // EVENT_TYPE_INT
- int32_t data;
- } android_event_int_t;
-
- struct android_event_long_t {
- int8_t type; // EVENT_TYPE_LONG
- int64_t data;
- };
-
- struct android_event_string_t {
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length;
- char data[];
- };
-
-The payload, excluding the header, has a max size of LOGGER_ENTRY_MAX_PAYLOAD.
-
-## header
-
-The header is added immediately before sending the log message to logd.
-
-## `string` payload
-
-The `string` part of the union is for normal buffers (main, system, radio, etc) and consists of a
-single character priority, followed by a variable length null terminated string for the tag, and
-finally a variable length null terminated string for the message.
-
-This payload is used for the `__android_log_buf_write()` family of functions.
-
-## `binary` payload
-
-The `binary` part of the union is for binary buffers (events, security, etc) and consists of an
-android_event_header_t struct followed by a variable number of android_event_*_t
-(android_event_list_t, android_event_int_t, etc) structs.
-
-If multiple android_event_*_t elements are present, then they must be in a list and the first
-element in payload must be an android_event_list_t.
-
-This payload is used for the `__android_log_bwrite()` family of functions. It is additionally used
-for `android_log_write_list()` and the related functions that manipulate event lists.
-
-# logd -> liblog
-
-logd sends a `logger_entry` struct to liblog followed by the payload. The payload is identical to
-the payloads defined above. The max size of the entire message from logd is LOGGER_ENTRY_MAX_LEN.
diff --git a/liblog/event.logtags b/liblog/event.logtags
deleted file mode 100644
index 0a3b650..0000000
--- a/liblog/event.logtags
+++ /dev/null
@@ -1,37 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace. Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-# (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# s: Number of seconds (monotonic time)
-# Default value for data of type int/long is 2 (bytes).
-#
-# TODO: generate ".java" and ".h" files with integer constants from this file.
-
-1006 liblog (dropped|1)
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
deleted file mode 100644
index 85556e8..0000000
--- a/liblog/event_tag_map.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2007-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-
-#include <functional>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-
-#include <log/event_tag_map.h>
-#include <private/android_logger.h>
-#include <utils/FastStrcmp.h>
-#include <utils/RWLock.h>
-
-#define OUT_TAG "EventTagMap"
-
-typedef std::pair<std::string_view, std::string_view> TagFmt;
-
-// Map
-struct EventTagMap {
-#define NUM_MAPS 2
- // memory-mapped source file; we get strings from here
- void* mapAddr[NUM_MAPS];
- size_t mapLen[NUM_MAPS];
-
- private:
- std::unordered_map<uint32_t, TagFmt> Idx2TagFmt;
- std::unordered_map<std::string_view, uint32_t> Tag2Idx;
- // protect unordered sets
- android::RWLock rwlock;
-
- public:
- EventTagMap() {
- memset(mapAddr, 0, sizeof(mapAddr));
- memset(mapLen, 0, sizeof(mapLen));
- }
-
- ~EventTagMap() {
- Idx2TagFmt.clear();
- Tag2Idx.clear();
- for (size_t which = 0; which < NUM_MAPS; ++which) {
- if (mapAddr[which]) {
- munmap(mapAddr[which], mapLen[which]);
- mapAddr[which] = 0;
- }
- }
- }
-
- bool emplaceUnique(uint32_t tag, const TagFmt& tagfmt, bool verbose = false);
- const TagFmt* find(uint32_t tag) const;
- int find(std::string_view tag) const;
-};
-
-bool EventTagMap::emplaceUnique(uint32_t tag, const TagFmt& tagfmt,
- bool verbose) {
- bool ret = true;
- static const char errorFormat[] =
- OUT_TAG ": duplicate tag entries %" PRIu32 ":%.*s:%.*s and %" PRIu32
- ":%.*s:%.*s)\n";
- android::RWLock::AutoWLock writeLock(rwlock);
- {
- auto it = Idx2TagFmt.find(tag);
- if (it != Idx2TagFmt.end()) {
- if (verbose) {
- fprintf(stderr, errorFormat, it->first, (int)it->second.first.length(),
- it->second.first.data(), (int)it->second.second.length(),
- it->second.second.data(), tag, (int)tagfmt.first.length(),
- tagfmt.first.data(), (int)tagfmt.second.length(),
- tagfmt.second.data());
- }
- ret = false;
- } else {
- Idx2TagFmt.emplace(std::make_pair(tag, tagfmt));
- }
- }
-
- {
- auto it = Tag2Idx.find(tagfmt.first);
- if (!tagfmt.second.length() && (it != Tag2Idx.end())) {
- Tag2Idx.erase(it);
- it = Tag2Idx.end();
- }
- if (it == Tag2Idx.end()) {
- Tag2Idx.emplace(std::make_pair(tagfmt.first, tag));
- }
- }
-
- return ret;
-}
-
-const TagFmt* EventTagMap::find(uint32_t tag) const {
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
- auto it = Idx2TagFmt.find(tag);
- if (it == Idx2TagFmt.end()) return NULL;
- return &(it->second);
-}
-
-int EventTagMap::find(std::string_view tag) const {
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
- auto it = Tag2Idx.find(std::move(tag));
- if (it == Tag2Idx.end()) return -1;
- return it->second;
-}
-
-// The position after the end of a valid section of the tag string,
-// caller makes sure delimited appropriately.
-static const char* endOfTag(const char* cp) {
- while (*cp && (isalnum(*cp) || strchr("_.-@,", *cp))) ++cp;
- return cp;
-}
-
-// Scan one tag line.
-//
-// "pData" should be pointing to the first digit in the tag number. On
-// successful return, it will be pointing to the last character in the
-// tag line (i.e. the character before the start of the next line).
-//
-// Returns 0 on success, nonzero on failure.
-static int scanTagLine(EventTagMap* map, const char*& pData, int line_num) {
- char* ep;
- unsigned long val = strtoul(pData, &ep, 10);
- const char* cp = ep;
- if (cp == pData) {
- fprintf(stderr, OUT_TAG ": malformed tag number on line %d\n", line_num);
- errno = EINVAL;
- return -1;
- }
-
- uint32_t tagIndex = val;
- if (tagIndex != val) {
- fprintf(stderr, OUT_TAG ": tag number too large on line %d\n", line_num);
- errno = ERANGE;
- return -1;
- }
-
- while ((*++cp != '\n') && isspace(*cp)) {
- }
-
- if (*cp == '\n') {
- fprintf(stderr, OUT_TAG ": missing tag string on line %d\n", line_num);
- errno = EINVAL;
- return -1;
- }
-
- const char* tag = cp;
- cp = endOfTag(cp);
- size_t tagLen = cp - tag;
-
- if (!isspace(*cp)) {
- fprintf(stderr, OUT_TAG ": invalid tag char %c on line %d\n", *cp, line_num);
- errno = EINVAL;
- return -1;
- }
-
- while (isspace(*cp) && (*cp != '\n')) ++cp;
- const char* fmt = NULL;
- size_t fmtLen = 0;
- if (*cp && (*cp != '#')) {
- fmt = cp;
- while (*cp && (*cp != '\n') && (*cp != '#')) ++cp;
- while ((cp > fmt) && isspace(*(cp - 1))) --cp;
- fmtLen = cp - fmt;
- }
-
- // KISS Only report identicals if they are global
- // Ideally we want to check if there are identicals
- // recorded for the same uid, but recording that
- // unused detail in our database is too burdensome.
- bool verbose = true;
- while (*cp && (*cp != '#') && (*cp != '\n')) ++cp;
- if (*cp == '#') {
- do {
- ++cp;
- } while (isspace(*cp) && (*cp != '\n'));
- verbose = !!fastcmp<strncmp>(cp, "uid=", strlen("uid="));
- }
-
- while (*cp && (*cp != '\n')) ++cp;
-#ifdef DEBUG
- fprintf(stderr, "%d: %p: %.*s\n", line_num, tag, (int)(cp - pData), pData);
-#endif
- pData = cp;
-
- if (map->emplaceUnique(
- tagIndex,
- TagFmt(std::make_pair(std::string_view(tag, tagLen), std::string_view(fmt, fmtLen))),
- verbose)) {
- return 0;
- }
- errno = EMLINK;
- return -1;
-}
-
-static const char* eventTagFiles[NUM_MAPS] = {
- EVENT_TAG_MAP_FILE, "/dev/event-log-tags",
-};
-
-// Parse the tags out of the file.
-static int parseMapLines(EventTagMap* map, size_t which) {
- const char* cp = static_cast<char*>(map->mapAddr[which]);
- size_t len = map->mapLen[which];
- const char* endp = cp + len;
-
- // insist on EOL at EOF; simplifies parsing and null-termination
- if (!len || (*(endp - 1) != '\n')) {
-#ifdef DEBUG
- fprintf(stderr, OUT_TAG ": map file %zu[%zu] missing EOL on last line\n",
- which, len);
-#endif
- if (which) { // do not propagate errors for other files
- return 0;
- }
- errno = EINVAL;
- return -1;
- }
-
- bool lineStart = true;
- int lineNum = 1;
- while (cp < endp) {
- if (*cp == '\n') {
- lineStart = true;
- lineNum++;
- } else if (lineStart) {
- if (*cp == '#') {
- // comment; just scan to end
- lineStart = false;
- } else if (isdigit(*cp)) {
- // looks like a tag; scan it out
- if (scanTagLine(map, cp, lineNum) != 0) {
- if (!which || (errno != EMLINK)) {
- return -1;
- }
- }
- lineNum++; // we eat the '\n'
- // leave lineStart==true
- } else if (isspace(*cp)) {
- // looks like leading whitespace; keep scanning
- } else {
- fprintf(stderr,
- OUT_TAG
- ": unexpected chars (0x%02x) in tag number on line %d\n",
- *cp, lineNum);
- errno = EINVAL;
- return -1;
- }
- } else {
- // this is a blank or comment line
- }
- cp++;
- }
-
- return 0;
-}
-
-// Open the map file and allocate a structure to manage it.
-//
-// We create a private mapping because we want to terminate the log tag
-// strings with '\0'.
-EventTagMap* android_openEventTagMap(const char* fileName) {
- EventTagMap* newTagMap;
- off_t end[NUM_MAPS];
- int save_errno, fd[NUM_MAPS];
- size_t which;
-
- memset(fd, -1, sizeof(fd));
- memset(end, 0, sizeof(end));
-
- for (which = 0; which < NUM_MAPS; ++which) {
- const char* tagfile = fileName ? fileName : eventTagFiles[which];
-
- fd[which] = open(tagfile, O_RDONLY | O_CLOEXEC);
- if (fd[which] < 0) {
- if (!which) {
- save_errno = errno;
- fprintf(stderr, OUT_TAG ": unable to open map '%s': %s\n", tagfile,
- strerror(save_errno));
- goto fail_errno;
- }
- continue;
- }
- end[which] = lseek(fd[which], 0L, SEEK_END);
- save_errno = errno;
- (void)lseek(fd[which], 0L, SEEK_SET);
- if (!which && (end[0] < 0)) {
- fprintf(stderr, OUT_TAG ": unable to seek map '%s' %s\n", tagfile,
- strerror(save_errno));
- goto fail_close;
- }
- if (fileName) break; // Only allow one as specified
- }
-
- newTagMap = new EventTagMap;
- if (newTagMap == NULL) {
- save_errno = errno;
- goto fail_close;
- }
-
- for (which = 0; which < NUM_MAPS; ++which) {
- if (fd[which] >= 0) {
- newTagMap->mapAddr[which] =
- mmap(NULL, end[which], which ? PROT_READ : PROT_READ | PROT_WRITE,
- which ? MAP_SHARED : MAP_PRIVATE, fd[which], 0);
- save_errno = errno;
- close(fd[which]); /* fd DONE */
- fd[which] = -1;
- if ((newTagMap->mapAddr[which] != MAP_FAILED) &&
- (newTagMap->mapAddr[which] != NULL)) {
- newTagMap->mapLen[which] = end[which];
- } else if (!which) {
- const char* tagfile = fileName ? fileName : eventTagFiles[which];
-
- fprintf(stderr, OUT_TAG ": mmap(%s) failed: %s\n", tagfile,
- strerror(save_errno));
- goto fail_unmap;
- }
- }
- }
-
- for (which = 0; which < NUM_MAPS; ++which) {
- if (parseMapLines(newTagMap, which) != 0) {
- delete newTagMap;
- return NULL;
- }
- /* See 'fd DONE' comments above and below, no need to clean up here */
- }
-
- return newTagMap;
-
-fail_unmap:
- save_errno = EINVAL;
- delete newTagMap;
-fail_close:
- for (which = 0; which < NUM_MAPS; ++which) close(fd[which]); /* fd DONE */
-fail_errno:
- errno = save_errno;
- return NULL;
-}
-
-// Close the map.
-void android_closeEventTagMap(EventTagMap* map) {
- if (map) delete map;
-}
-
-// Look up an entry in the map.
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len, unsigned int tag) {
- if (len) *len = 0;
- const TagFmt* str = map->find(tag);
- if (!str) return NULL;
- if (len) *len = str->first.length();
- return str->first.data();
-}
-
-// Look up an entry in the map.
-const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len, unsigned int tag) {
- if (len) *len = 0;
- const TagFmt* str = map->find(tag);
- if (!str) return NULL;
- if (len) *len = str->second.length();
- return str->second.data();
-}
-
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
deleted file mode 100644
index 8a0ebf2..0000000
--- a/liblog/include/android/log.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#pragma once
-
-/**
- * @addtogroup Logging
- * @{
- */
-
-/**
- * \file
- *
- * Support routines to send messages to the Android log buffer,
- * which can later be accessed through the `logcat` utility.
- *
- * Each log message must have
- * - a priority
- * - a log tag
- * - some text
- *
- * The tag normally corresponds to the component that emits the log message,
- * and should be reasonably small.
- *
- * Log message text may be truncated to less than an implementation-specific
- * limit (1023 bytes).
- *
- * Note that a newline character ("\n") will be appended automatically to your
- * log message, if not already there. It is not possible to send several
- * messages and have them appear on a single line in logcat.
- *
- * Please use logging in moderation:
- *
- * - Sending log messages eats CPU and slow down your application and the
- * system.
- *
- * - The circular log buffer is pretty small, so sending many messages
- * will hide other important log messages.
- *
- * - In release builds, only send log messages to account for exceptional
- * conditions.
- */
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/cdefs.h>
-
-#if !defined(__BIONIC__) && !defined(__INTRODUCED_IN)
-#define __INTRODUCED_IN(x)
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * Android log priority values, in increasing order of priority.
- */
-typedef enum android_LogPriority {
- /** For internal use only. */
- ANDROID_LOG_UNKNOWN = 0,
- /** The default priority, for internal use only. */
- ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
- /** Verbose logging. Should typically be disabled for a release apk. */
- ANDROID_LOG_VERBOSE,
- /** Debug logging. Should typically be disabled for a release apk. */
- ANDROID_LOG_DEBUG,
- /** Informational logging. Should typically be disabled for a release apk. */
- ANDROID_LOG_INFO,
- /** Warning logging. For use with recoverable failures. */
- ANDROID_LOG_WARN,
- /** Error logging. For use with unrecoverable failures. */
- ANDROID_LOG_ERROR,
- /** Fatal logging. For use when aborting. */
- ANDROID_LOG_FATAL,
- /** For internal use only. */
- ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
-} android_LogPriority;
-
-/**
- * Writes the constant string `text` to the log, with priority `prio` and tag
- * `tag`.
- */
-int __android_log_write(int prio, const char* tag, const char* text);
-
-/**
- * Writes a formatted string to the log, with priority `prio` and tag `tag`.
- * The details of formatting are the same as for
- * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
- */
-int __android_log_print(int prio, const char* tag, const char* fmt, ...)
- __attribute__((__format__(printf, 3, 4)));
-
-/**
- * Equivalent to `__android_log_print`, but taking a `va_list`.
- * (If `__android_log_print` is like `printf`, this is like `vprintf`.)
- */
-int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap)
- __attribute__((__format__(printf, 3, 0)));
-
-/**
- * Writes an assertion failure to the log (as `ANDROID_LOG_FATAL`) and to
- * stderr, before calling
- * [abort(3)](http://man7.org/linux/man-pages/man3/abort.3.html).
- *
- * If `fmt` is non-null, `cond` is unused. If `fmt` is null, the string
- * `Assertion failed: %s` is used with `cond` as the string argument.
- * If both `fmt` and `cond` are null, a default string is provided.
- *
- * Most callers should use
- * [assert(3)](http://man7.org/linux/man-pages/man3/assert.3.html) from
- * `<assert.h>` instead, or the `__assert` and `__assert2` functions
- * provided by bionic if more control is needed. They support automatically
- * including the source filename and line number more conveniently than this
- * function.
- */
-void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...)
- __attribute__((__noreturn__)) __attribute__((__format__(printf, 3, 4)));
-
-/**
- * Identifies a specific log buffer for __android_log_buf_write()
- * and __android_log_buf_print().
- */
-typedef enum log_id {
- LOG_ID_MIN = 0,
-
- /** The main log buffer. This is the only log buffer available to apps. */
- LOG_ID_MAIN = 0,
- /** The radio log buffer. */
- LOG_ID_RADIO = 1,
- /** The event log buffer. */
- LOG_ID_EVENTS = 2,
- /** The system log buffer. */
- LOG_ID_SYSTEM = 3,
- /** The crash log buffer. */
- LOG_ID_CRASH = 4,
- /** The statistics log buffer. */
- LOG_ID_STATS = 5,
- /** The security log buffer. */
- LOG_ID_SECURITY = 6,
- /** The kernel log buffer. */
- LOG_ID_KERNEL = 7,
-
- LOG_ID_MAX,
-
- /** Let the logging function choose the best log target. */
- LOG_ID_DEFAULT = 0x7FFFFFFF
-} log_id_t;
-
-/**
- * Writes the constant string `text` to the log buffer `id`,
- * with priority `prio` and tag `tag`.
- *
- * Apps should use __android_log_write() instead.
- */
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* text);
-
-/**
- * Writes a formatted string to log buffer `id`,
- * with priority `prio` and tag `tag`.
- * The details of formatting are the same as for
- * [printf(3)](http://man7.org/linux/man-pages/man3/printf.3.html).
- *
- * Apps should use __android_log_print() instead.
- */
-int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
- __attribute__((__format__(printf, 4, 5)));
-
-/**
- * Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
- * and sending log messages to user defined loggers specified in __android_log_set_logger().
- */
-struct __android_log_message {
- /** Must be set to sizeof(__android_log_message) and is used for versioning. */
- size_t struct_size;
-
- /** {@link log_id_t} values. */
- int32_t buffer_id;
-
- /** {@link android_LogPriority} values. */
- int32_t priority;
-
- /** The tag for the log message. */
- const char* tag;
-
- /** Optional file name, may be set to nullptr. */
- const char* file;
-
- /** Optional line number, ignore if file is nullptr. */
- uint32_t line;
-
- /** The log message itself. */
- const char* message;
-};
-
-/**
- * Prototype for the 'logger' function that is called for every log message.
- */
-typedef void (*__android_logger_function)(const struct __android_log_message* log_message);
-/**
- * Prototype for the 'abort' function that is called when liblog will abort due to
- * __android_log_assert() failures.
- */
-typedef void (*__android_aborter_function)(const char* abort_message);
-
-#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
-/**
- * Writes the log message specified by log_message. log_message includes additional file name and
- * line number information that a logger may use. log_message is versioned for backwards
- * compatibility.
- * This assumes that loggability has already been checked through __android_log_is_loggable().
- * Higher level logging libraries, such as libbase, first check loggability, then format their
- * buffers, then pass the message to liblog via this function, and therefore we do not want to
- * duplicate the loggability check here.
- *
- * @param log_message the log message itself, see __android_log_message.
- *
- * Available since API level 30.
- */
-void __android_log_write_log_message(struct __android_log_message* log_message) __INTRODUCED_IN(30);
-
-/**
- * Sets a user defined logger function. All log messages sent to liblog will be set to the
- * function pointer specified by logger for processing. It is not expected that log messages are
- * already terminated with a new line. This function should add new lines if required for line
- * separation.
- *
- * @param logger the new function that will handle log messages.
- *
- * Available since API level 30.
- */
-void __android_log_set_logger(__android_logger_function logger) __INTRODUCED_IN(30);
-
-/**
- * Writes the log message to logd. This is an __android_logger_function and can be provided to
- * __android_log_set_logger(). It is the default logger when running liblog on a device.
- *
- * @param log_message the log message to write, see __android_log_message.
- *
- * Available since API level 30.
- */
-void __android_log_logd_logger(const struct __android_log_message* log_message) __INTRODUCED_IN(30);
-
-/**
- * Writes the log message to stderr. This is an __android_logger_function and can be provided to
- * __android_log_set_logger(). It is the default logger when running liblog on host.
- *
- * @param log_message the log message to write, see __android_log_message.
- *
- * Available since API level 30.
- */
-void __android_log_stderr_logger(const struct __android_log_message* log_message)
- __INTRODUCED_IN(30);
-
-/**
- * Sets a user defined aborter function that is called for __android_log_assert() failures. This
- * user defined aborter function is highly recommended to abort and be noreturn, but is not strictly
- * required to.
- *
- * @param aborter the new aborter function, see __android_aborter_function.
- *
- * Available since API level 30.
- */
-void __android_log_set_aborter(__android_aborter_function aborter) __INTRODUCED_IN(30);
-
-/**
- * Calls the stored aborter function. This allows for other logging libraries to use the same
- * aborter function by calling this function in liblog.
- *
- * @param abort_message an additional message supplied when aborting, for example this is used to
- * call android_set_abort_message() in __android_log_default_aborter().
- *
- * Available since API level 30.
- */
-void __android_log_call_aborter(const char* abort_message) __INTRODUCED_IN(30);
-
-/**
- * Sets android_set_abort_message() on device then aborts(). This is the default aborter.
- *
- * @param abort_message an additional message supplied when aborting. This functions calls
- * android_set_abort_message() with its contents.
- *
- * Available since API level 30.
- */
-void __android_log_default_aborter(const char* abort_message) __attribute__((noreturn))
-__INTRODUCED_IN(30);
-
-/**
- * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
- * __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
- * be printed. A non-zero result indicates yes, zero indicates false.
- *
- * If both a priority for a tag and a minimum priority are set by
- * __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
- * minimum priority needed to log. If only one is set, then that value is used to determine the
- * minimum priority needed. If none are set, then default_priority is used.
- *
- * @param prio the priority to test, takes android_LogPriority values.
- * @param tag the tag to test.
- * @param default_prio the default priority to use if no properties or minimum priority are set.
- * @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
- *
- * Available since API level 30.
- */
-int __android_log_is_loggable(int prio, const char* tag, int default_prio) __INTRODUCED_IN(30);
-
-/**
- * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
- * __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
- * be printed. A non-zero result indicates yes, zero indicates false.
- *
- * If both a priority for a tag and a minimum priority are set by
- * __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
- * minimum priority needed to log. If only one is set, then that value is used to determine the
- * minimum priority needed. If none are set, then default_priority is used.
- *
- * @param prio the priority to test, takes android_LogPriority values.
- * @param tag the tag to test.
- * @param len the length of the tag.
- * @param default_prio the default priority to use if no properties or minimum priority are set.
- * @return an integer where 1 indicates that the message is loggable and 0 indicates that it is not.
- *
- * Available since API level 30.
- */
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio)
- __INTRODUCED_IN(30);
-
-/**
- * Sets the minimum priority that will be logged for this process.
- *
- * @param priority the new minimum priority to set, takes android_LogPriority values.
- * @return the previous set minimum priority as android_LogPriority values, or
- * ANDROID_LOG_DEFAULT if none was set.
- *
- * Available since API level 30.
- */
-int32_t __android_log_set_minimum_priority(int32_t priority) __INTRODUCED_IN(30);
-
-/**
- * Gets the minimum priority that will be logged for this process. If none has been set by a
- * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
- *
- * @return the current minimum priority as android_LogPriority values, or
- * ANDROID_LOG_DEFAULT if none is set.
- *
- * Available since API level 30.
- */
-int32_t __android_log_get_minimum_priority(void) __INTRODUCED_IN(30);
-
-/**
- * Sets the default tag if no tag is provided when writing a log message. Defaults to
- * getprogname(). This truncates tag to the maximum log message size, though appropriate tags
- * should be much smaller.
- *
- * @param tag the new log tag.
- *
- * Available since API level 30.
- */
-void __android_log_set_default_tag(const char* tag) __INTRODUCED_IN(30);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-/** @} */
diff --git a/liblog/include/log/event_tag_map.h b/liblog/include/log/event_tag_map.h
deleted file mode 100644
index de49fbf..0000000
--- a/liblog/include/log/event_tag_map.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#pragma once
-
-#include <stddef.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define EVENT_TAG_MAP_FILE "/system/etc/event-log-tags"
-
-struct EventTagMap;
-typedef struct EventTagMap EventTagMap;
-
-/*
- * Open the specified file as an event log tag map.
- *
- * Returns NULL on failure.
- */
-EventTagMap* android_openEventTagMap(const char* fileName);
-
-/*
- * Close the map.
- */
-void android_closeEventTagMap(EventTagMap* map);
-
-/*
- * Look up a tag by index. Returns the tag string & string length, or NULL if
- * not found. Returned string is not guaranteed to be nul terminated.
- */
-const char* android_lookupEventTag_len(const EventTagMap* map, size_t* len,
- unsigned int tag);
-
-/*
- * Look up a format by index. Returns the format string & string length,
- * or NULL if not found. Returned string is not guaranteed to be nul terminated.
- */
-const char* android_lookupEventFormat_len(const EventTagMap* map, size_t* len,
- unsigned int tag);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log.h b/liblog/include/log/log.h
deleted file mode 100644
index d7e9b7d..0000000
--- a/liblog/include/log/log.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2005-2014 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.
- */
-
-#pragma once
-
-/* Too many in the ecosystem assume these are included */
-#if !defined(_WIN32)
-#include <pthread.h>
-#endif
-#include <stdint.h> /* uint16_t, int32_t */
-#include <stdio.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <android/log.h>
-#include <log/log_id.h>
-#include <log/log_main.h>
-#include <log/log_radio.h>
-#include <log/log_safetynet.h>
-#include <log/log_system.h>
-#include <log/log_time.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * LOG_TAG is the local tag used for the following simplified
- * logging macros. You can change this preprocessor definition
- * before using the other macros to change the tag.
- */
-
-#ifndef LOG_TAG
-#define LOG_TAG NULL
-#endif
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/*
- * The maximum size of the log entry payload that can be
- * written to the logger. An attempt to write more than
- * this amount will result in a truncated log entry.
- */
-#define LOGGER_ENTRY_MAX_PAYLOAD 4068
-
-/*
- * Event logging.
- */
-
-/*
- * The following should not be used directly.
- */
-
-int __android_log_bwrite(int32_t tag, const void* payload, size_t len);
-int __android_log_btwrite(int32_t tag, char type, const void* payload,
- size_t len);
-int __android_log_bswrite(int32_t tag, const char* payload);
-
-int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len);
-
-#define android_bWriteLog(tag, payload, len) \
- __android_log_bwrite(tag, payload, len)
-#define android_btWriteLog(tag, type, payload, len) \
- __android_log_btwrite(tag, type, payload, len)
-
-/*
- * Event log entry types.
- */
-typedef enum {
- /* Special markers for android_log_list_element type */
- EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
- EVENT_TYPE_UNKNOWN = '?', /* protocol error */
-
- /* must match with declaration in java/android/android/util/EventLog.java */
- EVENT_TYPE_INT = 0, /* int32_t */
- EVENT_TYPE_LONG = 1, /* int64_t */
- EVENT_TYPE_STRING = 2,
- EVENT_TYPE_LIST = 3,
- EVENT_TYPE_FLOAT = 4,
-} AndroidEventLogType;
-
-#ifndef LOG_EVENT_INT
-#define LOG_EVENT_INT(_tag, _value) \
- { \
- int intBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_LONG
-#define LOG_EVENT_LONG(_tag, _value) \
- { \
- long long longBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_FLOAT
-#define LOG_EVENT_FLOAT(_tag, _value) \
- { \
- float floatBuf = _value; \
- (void)android_btWriteLog(_tag, EVENT_TYPE_FLOAT, &floatBuf, \
- sizeof(floatBuf)); \
- }
-#endif
-#ifndef LOG_EVENT_STRING
-#define LOG_EVENT_STRING(_tag, _value) \
- (void)__android_log_bswrite(_tag, _value);
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Release any logger resources (a new log write will immediately re-acquire)
- *
- * This is specifically meant to be used by Zygote to close open file descriptors after fork()
- * and before specialization. O_CLOEXEC is used on file descriptors, so they will be closed upon
- * exec() in normal use cases.
- *
- * Note that this is not safe to call from a multi-threaded program.
- */
-void __android_log_close(void);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_event_list.h b/liblog/include/log/log_event_list.h
deleted file mode 100644
index deadf20..0000000
--- a/liblog/include/log/log_event_list.h
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2005-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <errno.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-#include <string>
-#endif
-
-#include <log/log.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* For manipulating lists of events. */
-
-#define ANDROID_MAX_LIST_NEST_DEPTH 8
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-typedef struct android_log_context_internal* android_log_context;
-
-/*
- * Elements returned when reading a list of events.
- */
-typedef struct {
- AndroidEventLogType type;
- uint16_t complete;
- uint16_t len;
- union {
- int32_t int32;
- int64_t int64;
- char* string;
- float float32;
- } data;
-} android_log_list_element;
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- * elements, we will manufacturer a list to embrace it for your API
- * convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx, const char* value,
- size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/*
- * Creates a context from a raw buffer representing a list of events to be read.
- */
-android_log_context create_android_log_parser(const char* msg, size_t len);
-
-android_log_list_element android_log_read_next(android_log_context ctx);
-android_log_list_element android_log_peek_next(android_log_context ctx);
-
-/* Reset writer context */
-int android_log_reset(android_log_context ctx);
-
-/* Reset reader context */
-int android_log_parser_reset(android_log_context ctx,
- const char* msg, size_t len);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context* ctx);
-
-#ifdef __cplusplus
-/* android_log_list C++ helpers */
-extern "C++" {
-class android_log_event_list {
- private:
- android_log_context ctx;
- int ret;
-
- android_log_event_list(const android_log_event_list&) = delete;
- void operator=(const android_log_event_list&) = delete;
-
- public:
- explicit android_log_event_list(int tag) : ret(0) {
- ctx = create_android_logger(static_cast<uint32_t>(tag));
- }
- ~android_log_event_list() {
- android_log_destroy(&ctx);
- }
-
- int close() {
- int retval = android_log_destroy(&ctx);
- if (retval < 0) ret = retval;
- return retval;
- }
-
- /* To allow above C calls to use this class as parameter */
- operator android_log_context() const {
- return ctx;
- }
-
- /* return errors or transmit status */
- int status() const {
- return ret;
- }
-
- int begin() {
- int retval = android_log_write_list_begin(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
- int end() {
- int retval = android_log_write_list_end(ctx);
- if (retval < 0) ret = retval;
- return ret;
- }
-
- android_log_event_list& operator<<(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(uint32_t value) {
- int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(bool value) {
- int retval = android_log_write_int32(ctx, value ? 1 : 0);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(uint64_t value) {
- int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(const std::string& value) {
- int retval =
- android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) ret = retval;
- return *this;
- }
-
- android_log_event_list& operator<<(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return *this;
- }
-
- int write(log_id_t id = LOG_ID_EVENTS) {
- /* facilitate -EBUSY retry */
- if ((ret == -EBUSY) || (ret > 0)) ret = 0;
- int retval = android_log_write_list(ctx, id);
- /* existing errors trump transmission errors */
- if (!ret) ret = retval;
- return ret;
- }
-
- int operator<<(log_id_t id) {
- write(id);
- android_log_destroy(&ctx);
- return ret;
- }
-
- /*
- * Append<Type> methods removes any integer promotion
- * confusion, and adds access to string with length.
- * Append methods are also added for all types for
- * convenience.
- */
-
- bool AppendInt(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendLong(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendString(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendString(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- bool AppendString(const std::string& value) {
- int retval =
- android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) ret = retval;
- return ret;
- }
-
- bool Append(const std::string& value) {
- int retval =
- android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) ret = retval;
- return ret;
- }
-
- bool AppendFloat(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-
- template <typename Tvalue>
- bool Append(Tvalue value) {
- *this << value;
- return ret >= 0;
- }
-
- bool Append(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) ret = retval;
- return ret >= 0;
- }
-};
-}
-#endif
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_id.h b/liblog/include/log/log_id.h
deleted file mode 100644
index 8e4faeb..0000000
--- a/liblog/include/log/log_id.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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.
- */
-
-#pragma once
-
-#include <android/log.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * log_id_t helpers
- */
-log_id_t android_name_to_log_id(const char* logName);
-const char* android_log_id_to_name(log_id_t log_id);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_main.h b/liblog/include/log/log_main.h
deleted file mode 100644
index 1bd1c8a..0000000
--- a/liblog/include/log/log_main.h
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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.
- */
-
-#pragma once
-
-#include <stdbool.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-
-__BEGIN_DECLS
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * This file uses ", ## __VA_ARGS__" zero-argument token pasting to
- * work around issues with debug-only syntax errors in assertions
- * that are missing format strings. See commit
- * 19299904343daf191267564fe32e6cd5c165cd42
- */
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
-#endif
-
-/*
- * Use __VA_ARGS__ if running a static analyzer,
- * to avoid warnings of unused variables in __VA_ARGS__.
- * Use constexpr function in C++ mode, so these macros can be used
- * in other constexpr functions without warning.
- */
-#ifdef __clang_analyzer__
-#ifdef __cplusplus
-extern "C++" {
-template <typename... Ts>
-constexpr int __fake_use_va_args(Ts...) {
- return 0;
-}
-}
-#else
-extern int __fake_use_va_args(int, ...);
-#endif /* __cplusplus */
-#define __FAKE_USE_VA_ARGS(...) ((void)__fake_use_va_args(0, ##__VA_ARGS__))
-#else
-#define __FAKE_USE_VA_ARGS(...) ((void)(0))
-#endif /* __clang_analyzer__ */
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-#define android_writeLog(prio, tag, text) __android_log_write(prio, tag, text)
-
-#define android_printLog(prio, tag, ...) \
- __android_log_print(prio, tag, __VA_ARGS__)
-
-#define android_vprintLog(prio, cond, tag, ...) \
- __android_log_vprint(prio, tag, __VA_ARGS__)
-
-/*
- * Log macro that allows you to specify a number for the priority.
- */
-#ifndef LOG_PRI
-#define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Log macro that allows you to pass in a varargs ("args" is a va_list).
- */
-#ifndef LOG_PRI_VA
-#define LOG_PRI_VA(priority, tag, fmt, args) \
- android_vprintLog(priority, NULL, tag, fmt, args)
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/* XXX Macros to work around syntax errors in places where format string
- * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF
- * (happens only in debug builds).
- */
-
-/* Returns 2nd arg. Used to substitute default value if caller's vararg list
- * is empty.
- */
-#define __android_second(dummy, second, ...) second
-
-/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise
- * returns nothing.
- */
-#define __android_rest(first, ...) , ##__VA_ARGS__
-
-#define android_printAssert(cond, tag, ...) \
- __android_log_assert(cond, tag, \
- __android_second(0, ##__VA_ARGS__, NULL) \
- __android_rest(__VA_ARGS__))
-
-/*
- * Log a fatal error. If the given condition fails, this stops program
- * execution like a normal assertion, but also generating the given message.
- * It is NOT stripped from release builds. Note that the condition test
- * is -inverted- from the normal assert() semantics.
- */
-#ifndef LOG_ALWAYS_FATAL_IF
-#define LOG_ALWAYS_FATAL_IF(cond, ...) \
- ((__predict_false(cond)) ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), \
- ((void)android_printAssert(#cond, LOG_TAG, ##__VA_ARGS__))) \
- : ((void)0))
-#endif
-
-#ifndef LOG_ALWAYS_FATAL
-#define LOG_ALWAYS_FATAL(...) \
- (((void)android_printAssert(NULL, LOG_TAG, ##__VA_ARGS__)))
-#endif
-
-/*
- * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that
- * are stripped out of release builds.
- */
-
-#if LOG_NDEBUG
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
-#endif
-
-#else
-
-#ifndef LOG_FATAL_IF
-#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ##__VA_ARGS__)
-#endif
-#ifndef LOG_FATAL
-#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__)
-#endif
-
-#endif
-
-/*
- * Assertion that generates a log message when the assertion fails.
- * Stripped out of release builds. Uses the current LOG_TAG.
- */
-#ifndef ALOG_ASSERT
-#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ##__VA_ARGS__)
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * C/C++ logging functions. See the logging documentation for API details.
- *
- * We'd like these to be available from C code (in case we import some from
- * somewhere), so this has a C interface.
- *
- * The output will be correct when the log file is shared between multiple
- * threads and/or multiple processes so long as the operating system
- * supports O_APPEND. These calls have mutex-protected data structures
- * and so are NOT reentrant. Do not use LOG in a signal handler.
- */
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Simplified macro to send a verbose log message using the current LOG_TAG.
- */
-#ifndef ALOGV
-#define __ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
-#if LOG_NDEBUG
-#define ALOGV(...) \
- do { \
- __FAKE_USE_VA_ARGS(__VA_ARGS__); \
- if (false) { \
- __ALOGV(__VA_ARGS__); \
- } \
- } while (false)
-#else
-#define ALOGV(...) __ALOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef ALOGV_IF
-#if LOG_NDEBUG
-#define ALOGV_IF(cond, ...) __FAKE_USE_VA_ARGS(__VA_ARGS__)
-#else
-#define ALOGV_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug log message using the current LOG_TAG.
- */
-#ifndef ALOGD
-#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGD_IF
-#define ALOGD_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/*
- * Simplified macro to send an info log message using the current LOG_TAG.
- */
-#ifndef ALOGI
-#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGI_IF
-#define ALOGI_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/*
- * Simplified macro to send a warning log message using the current LOG_TAG.
- */
-#ifndef ALOGW
-#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGW_IF
-#define ALOGW_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/*
- * Simplified macro to send an error log message using the current LOG_TAG.
- */
-#ifndef ALOGE
-#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__))
-#endif
-
-#ifndef ALOGE_IF
-#define ALOGE_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? (__FAKE_USE_VA_ARGS(__VA_ARGS__), (void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \
- : ((void)0))
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * verbose priority.
- */
-#ifndef IF_ALOGV
-#if LOG_NDEBUG
-#define IF_ALOGV() if (false)
-#else
-#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG)
-#endif
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * debug priority.
- */
-#ifndef IF_ALOGD
-#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * info priority.
- */
-#ifndef IF_ALOGI
-#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * warn priority.
- */
-#ifndef IF_ALOGW
-#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG)
-#endif
-
-/*
- * Conditional based on whether the current LOG_TAG is enabled at
- * error priority.
- */
-#ifndef IF_ALOGE
-#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG)
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Basic log message macro.
- *
- * Example:
- * ALOG(LOG_WARN, NULL, "Failed with error %d", errno);
- *
- * The second argument may be NULL or "" to indicate the "global" tag.
- */
-#ifndef ALOG
-#define ALOG(priority, tag, ...) LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
-#endif
-
-/*
- * Conditional given a desired logging priority and tag.
- */
-#ifndef IF_ALOG
-#define IF_ALOG(priority, tag) if (android_testLog(ANDROID_##priority, tag))
-#endif
-
-/* --------------------------------------------------------------------- */
-
-/*
- * IF_ALOG uses android_testLog, but IF_ALOG can be overridden.
- * android_testLog will remain constant in its purpose as a wrapper
- * for Android logging filter policy, and can be subject to
- * change. It can be reused by the developers that override
- * IF_ALOG as a convenient means to reimplement their policy
- * over Android.
- */
-
-/*
- * Use the per-tag properties "log.tag.<tagname>" to generate a runtime
- * result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
- * ANDROID_LOG_FATAL. default_prio if no property. Undefined behavior if
- * any other value.
- */
-int __android_log_is_loggable(int prio, const char* tag, int default_prio);
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
-
-#if LOG_NDEBUG /* Production */
-#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
- ANDROID_LOG_DEBUG) != 0)
-#else
-#define android_testLog(prio, tag) \
- (__android_log_is_loggable_len(prio, tag, ((tag) && *(tag)) ? strlen(tag) : 0, \
- ANDROID_LOG_VERBOSE) != 0)
-#endif
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-__END_DECLS
diff --git a/liblog/include/log/log_properties.h b/liblog/include/log/log_properties.h
deleted file mode 100644
index 2a0230f..0000000
--- a/liblog/include/log/log_properties.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#pragma once
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Returns `1` if the device is debuggable or `0` if not. */
-int __android_log_is_debuggable();
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_radio.h b/liblog/include/log/log_radio.h
deleted file mode 100644
index f5525c1..0000000
--- a/liblog/include/log/log_radio.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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.
- */
-
-#pragma once
-
-#include <android/log.h>
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-/*
- * Simplified macro to send a verbose radio log message using current LOG_TAG.
- */
-#ifndef RLOGV
-#define __RLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, \
- __VA_ARGS__))
-#if LOG_NDEBUG
-#define RLOGV(...) \
- do { \
- if (0) { \
- __RLOGV(__VA_ARGS__); \
- } \
- } while (0)
-#else
-#define RLOGV(...) __RLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef RLOGV_IF
-#if LOG_NDEBUG
-#define RLOGV_IF(cond, ...) ((void)0)
-#else
-#define RLOGV_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug radio log message using current LOG_TAG.
- */
-#ifndef RLOGD
-#define RLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGD_IF
-#define RLOGD_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an info radio log message using current LOG_TAG.
- */
-#ifndef RLOGI
-#define RLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGI_IF
-#define RLOGI_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send a warning radio log message using current LOG_TAG.
- */
-#ifndef RLOGW
-#define RLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGW_IF
-#define RLOGW_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an error radio log message using current LOG_TAG.
- */
-#ifndef RLOGE
-#define RLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef RLOGE_IF
-#define RLOGE_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
diff --git a/liblog/include/log/log_read.h b/liblog/include/log/log_read.h
deleted file mode 100644
index 1736934..0000000
--- a/liblog/include/log/log_read.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-#include <log/log_time.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ANDROID_LOG_WRAP_DEFAULT_TIMEOUT 7200 /* 2 hour default */
-
-/*
- * Native log reading interface section. See logcat for sample code.
- *
- * The preferred API is an exec of logcat. Likely uses of this interface
- * are if native code suffers from exec or filtration being too costly,
- * access to raw information, or parsing is an issue.
- */
-
-struct logger_entry {
- uint16_t len; /* length of the payload */
- uint16_t hdr_size; /* sizeof(struct logger_entry) */
- int32_t pid; /* generating process's pid */
- uint32_t tid; /* generating process's tid */
- uint32_t sec; /* seconds since Epoch */
- uint32_t nsec; /* nanoseconds */
- uint32_t lid; /* log id of the payload, bottom 4 bits currently */
- uint32_t uid; /* generating process's uid */
-};
-
-/*
- * The maximum size of a log entry which can be read.
- * An attempt to read less than this amount may result
- * in read() returning EINVAL.
- */
-#define LOGGER_ENTRY_MAX_LEN (5 * 1024)
-
-struct log_msg {
- union {
- unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
- struct logger_entry entry;
- } __attribute__((aligned(4)));
-#ifdef __cplusplus
- uint64_t nsec() const {
- return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
- }
- log_id_t id() {
- return static_cast<log_id_t>(entry.lid);
- }
- char* msg() {
- unsigned short hdr_size = entry.hdr_size;
- if (hdr_size >= sizeof(struct log_msg) - sizeof(entry)) {
- return nullptr;
- }
- return reinterpret_cast<char*>(buf) + hdr_size;
- }
- unsigned int len() { return entry.hdr_size + entry.len; }
-#endif
-};
-
-struct logger;
-
-log_id_t android_logger_get_id(struct logger* logger);
-
-/* Clears the given log buffer. */
-int android_logger_clear(struct logger* logger);
-/* Return the allotted size for the given log buffer. */
-long android_logger_get_log_size(struct logger* logger);
-/* Set the allotted size for the given log buffer. */
-int android_logger_set_log_size(struct logger* logger, unsigned long size);
-/* Return the actual, uncompressed size that can be read from the given log buffer. */
-long android_logger_get_log_readable_size(struct logger* logger);
-/* Return the actual, compressed size that the given log buffer is consuming. */
-long android_logger_get_log_consumed_size(struct logger* logger);
-/* Deprecated. Always returns '4' regardless of input. */
-int android_logger_get_log_version(struct logger* logger);
-
-struct logger_list;
-
-ssize_t android_logger_get_statistics(struct logger_list* logger_list,
- char* buf, size_t len);
-ssize_t android_logger_get_prune_list(struct logger_list* logger_list,
- char* buf, size_t len);
-int android_logger_set_prune_list(struct logger_list* logger_list, const char* buf, size_t len);
-
-/* The below values are used for the `mode` argument of the below functions. */
-/* Note that 0x00000003 were previously used and should be considered reserved. */
-#define ANDROID_LOG_NONBLOCK 0x00000800
-#define ANDROID_LOG_WRAP 0x40000000 /* Block until buffer about to wrap */
-#define ANDROID_LOG_PSTORE 0x80000000
-
-struct logger_list* android_logger_list_alloc(int mode, unsigned int tail,
- pid_t pid);
-struct logger_list* android_logger_list_alloc_time(int mode, log_time start,
- pid_t pid);
-void android_logger_list_free(struct logger_list* logger_list);
-/* In the purest sense, the following two are orthogonal interfaces */
-int android_logger_list_read(struct logger_list* logger_list,
- struct log_msg* log_msg);
-
-/* Multiple log_id_t opens */
-struct logger* android_logger_open(struct logger_list* logger_list, log_id_t id);
-/* Single log_id_t open */
-struct logger_list* android_logger_list_open(log_id_t id, int mode,
- unsigned int tail, pid_t pid);
-#define android_logger_list_close android_logger_list_free
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_safetynet.h b/liblog/include/log/log_safetynet.h
deleted file mode 100644
index b2604b5..0000000
--- a/liblog/include/log/log_safetynet.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define android_errorWriteLog(tag, subTag) \
- __android_log_error_write(tag, subTag, -1, NULL, 0)
-
-#define android_errorWriteWithInfoLog(tag, subTag, uid, data, dataLen) \
- __android_log_error_write(tag, subTag, uid, data, dataLen)
-
-int __android_log_error_write(int tag, const char* subTag, int32_t uid,
- const char* data, uint32_t dataLen);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/log/log_system.h b/liblog/include/log/log_system.h
deleted file mode 100644
index 6f40515..0000000
--- a/liblog/include/log/log_system.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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.
- */
-
-#pragma once
-
-#include <android/log.h>
-
-/*
- * Normally we strip the effects of ALOGV (VERBOSE messages),
- * LOG_FATAL and LOG_FATAL_IF (FATAL assert messages) from the
- * release builds be defining NDEBUG. You can modify this (for
- * example with "#define LOG_NDEBUG 0" at the top of your source
- * file) to change that behavior.
- */
-
-#ifndef LOG_NDEBUG
-#ifdef NDEBUG
-#define LOG_NDEBUG 1
-#else
-#define LOG_NDEBUG 0
-#endif
-#endif
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-/*
- * Simplified macro to send a verbose system log message using current LOG_TAG.
- */
-#ifndef SLOGV
-#define __SLOGV(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, \
- __VA_ARGS__))
-#if LOG_NDEBUG
-#define SLOGV(...) \
- do { \
- if (0) { \
- __SLOGV(__VA_ARGS__); \
- } \
- } while (0)
-#else
-#define SLOGV(...) __SLOGV(__VA_ARGS__)
-#endif
-#endif
-
-#ifndef SLOGV_IF
-#if LOG_NDEBUG
-#define SLOGV_IF(cond, ...) ((void)0)
-#else
-#define SLOGV_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-#endif
-
-/*
- * Simplified macro to send a debug system log message using current LOG_TAG.
- */
-#ifndef SLOGD
-#define SLOGD(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGD_IF
-#define SLOGD_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an info system log message using current LOG_TAG.
- */
-#ifndef SLOGI
-#define SLOGI(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGI_IF
-#define SLOGI_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send a warning system log message using current LOG_TAG.
- */
-#ifndef SLOGW
-#define SLOGW(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGW_IF
-#define SLOGW_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
-
-/*
- * Simplified macro to send an error system log message using current LOG_TAG.
- */
-#ifndef SLOGE
-#define SLOGE(...) \
- ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, \
- __VA_ARGS__))
-#endif
-
-#ifndef SLOGE_IF
-#define SLOGE_IF(cond, ...) \
- ((__predict_false(cond)) \
- ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, \
- LOG_TAG, __VA_ARGS__)) \
- : (void)0)
-#endif
diff --git a/liblog/include/log/log_time.h b/liblog/include/log/log_time.h
deleted file mode 100644
index f50764d..0000000
--- a/liblog/include/log/log_time.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <time.h>
-
-/* struct log_time is a wire-format variant of struct timespec */
-#define NS_PER_SEC 1000000000ULL
-#define US_PER_SEC 1000000ULL
-#define MS_PER_SEC 1000ULL
-
-#define LOG_TIME_SEC(t) ((t)->tv_sec)
-/* next power of two after NS_PER_SEC */
-#define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2))
-
-#ifdef __cplusplus
-
-extern "C" {
-
-struct log_time {
- public:
- uint32_t tv_sec = 0; /* good to Feb 5 2106 */
- uint32_t tv_nsec = 0;
-
- static constexpr timespec EPOCH = {0, 0};
-
- log_time() {}
- explicit log_time(const timespec& T)
- : tv_sec(static_cast<uint32_t>(T.tv_sec)), tv_nsec(static_cast<uint32_t>(T.tv_nsec)) {}
- explicit log_time(uint32_t sec, uint32_t nsec = 0)
- : tv_sec(sec), tv_nsec(nsec) {
- }
-#ifdef __linux__
- explicit log_time(clockid_t id) {
- timespec T;
- clock_gettime(id, &T);
- tv_sec = static_cast<uint32_t>(T.tv_sec);
- tv_nsec = static_cast<uint32_t>(T.tv_nsec);
- }
-#endif
- /* timespec */
- bool operator==(const timespec& T) const {
- return (tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
- (tv_nsec == static_cast<uint32_t>(T.tv_nsec));
- }
- bool operator!=(const timespec& T) const {
- return !(*this == T);
- }
- bool operator<(const timespec& T) const {
- return (tv_sec < static_cast<uint32_t>(T.tv_sec)) ||
- ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
- (tv_nsec < static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator>=(const timespec& T) const {
- return !(*this < T);
- }
- bool operator>(const timespec& T) const {
- return (tv_sec > static_cast<uint32_t>(T.tv_sec)) ||
- ((tv_sec == static_cast<uint32_t>(T.tv_sec)) &&
- (tv_nsec > static_cast<uint32_t>(T.tv_nsec)));
- }
- bool operator<=(const timespec& T) const {
- return !(*this > T);
- }
-
- /* log_time */
- bool operator==(const log_time& T) const {
- return (tv_sec == T.tv_sec) && (tv_nsec == T.tv_nsec);
- }
- bool operator!=(const log_time& T) const {
- return !(*this == T);
- }
- bool operator<(const log_time& T) const {
- return (tv_sec < T.tv_sec) ||
- ((tv_sec == T.tv_sec) && (tv_nsec < T.tv_nsec));
- }
- bool operator>=(const log_time& T) const {
- return !(*this < T);
- }
- bool operator>(const log_time& T) const {
- return (tv_sec > T.tv_sec) ||
- ((tv_sec == T.tv_sec) && (tv_nsec > T.tv_nsec));
- }
- bool operator<=(const log_time& T) const {
- return !(*this > T);
- }
-
- log_time operator-=(const log_time& T) {
- // No concept of negative time, clamp to EPOCH
- if (*this <= T) {
- return *this = log_time(EPOCH);
- }
-
- if (this->tv_nsec < T.tv_nsec) {
- --this->tv_sec;
- this->tv_nsec = NS_PER_SEC + this->tv_nsec - T.tv_nsec;
- } else {
- this->tv_nsec -= T.tv_nsec;
- }
- this->tv_sec -= T.tv_sec;
-
- return *this;
- }
- log_time operator-(const log_time& T) const {
- log_time local(*this);
- return local -= T;
- }
- log_time operator+=(const log_time& T) {
- this->tv_nsec += T.tv_nsec;
- if (this->tv_nsec >= NS_PER_SEC) {
- this->tv_nsec -= NS_PER_SEC;
- ++this->tv_sec;
- }
- this->tv_sec += T.tv_sec;
-
- return *this;
- }
- log_time operator+(const log_time& T) const {
- log_time local(*this);
- return local += T;
- }
-
- uint64_t nsec() const {
- return static_cast<uint64_t>(tv_sec) * NS_PER_SEC + tv_nsec;
- }
- uint64_t usec() const {
- return static_cast<uint64_t>(tv_sec) * US_PER_SEC +
- tv_nsec / (NS_PER_SEC / US_PER_SEC);
- }
- uint64_t msec() const {
- return static_cast<uint64_t>(tv_sec) * MS_PER_SEC +
- tv_nsec / (NS_PER_SEC / MS_PER_SEC);
- }
-
- /* Add %#q for the fraction of a second to the standard library functions */
- char* strptime(const char* s, const char* format);
-} __attribute__((__packed__));
-}
-
-#else /* __cplusplus */
-
-typedef struct log_time {
- uint32_t tv_sec;
- uint32_t tv_nsec;
-} __attribute__((__packed__)) log_time;
-
-#endif /* __cplusplus */
diff --git a/liblog/include/log/logprint.h b/liblog/include/log/logprint.h
deleted file mode 100644
index 7dfd914..0000000
--- a/liblog/include/log/logprint.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-#include <log/event_tag_map.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- /* Verbs */
- FORMAT_OFF = 0,
- FORMAT_BRIEF,
- FORMAT_PROCESS,
- FORMAT_TAG,
- FORMAT_THREAD,
- FORMAT_RAW,
- FORMAT_TIME,
- FORMAT_THREADTIME,
- FORMAT_LONG,
- /* Adverbs. The following are modifiers to above format verbs */
- FORMAT_MODIFIER_COLOR, /* converts priority to color */
- FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
- FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
- FORMAT_MODIFIER_YEAR, /* Adds year to date */
- FORMAT_MODIFIER_ZONE, /* Adds zone to date, + UTC */
- FORMAT_MODIFIER_EPOCH, /* Print time as seconds since Jan 1 1970 */
- FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
- FORMAT_MODIFIER_UID, /* Adds uid */
- FORMAT_MODIFIER_DESCRIPT, /* Adds descriptive */
- /* private, undocumented */
- FORMAT_MODIFIER_TIME_NSEC, /* switches from msec to nsec time precision */
-} AndroidLogPrintFormat;
-
-typedef struct AndroidLogFormat_t AndroidLogFormat;
-
-typedef struct AndroidLogEntry_t {
- time_t tv_sec;
- long tv_nsec;
- android_LogPriority priority;
- int32_t uid;
- int32_t pid;
- int32_t tid;
- const char* tag;
- size_t tagLen;
- size_t messageLen;
- const char* message;
-} AndroidLogEntry;
-
-AndroidLogFormat* android_log_format_new();
-
-void android_log_format_free(AndroidLogFormat* p_format);
-
-/* currently returns 0 if format is a modifier, 1 if not */
-int android_log_setPrintFormat(AndroidLogFormat* p_format,
- AndroidLogPrintFormat format);
-
-/**
- * Returns FORMAT_OFF on invalid string
- */
-AndroidLogPrintFormat android_log_formatFromString(const char* s);
-
-/**
- * filterExpression: a single filter expression
- * eg "AT:d"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- *
- */
-
-int android_log_addFilterRule(AndroidLogFormat* p_format,
- const char* filterExpression);
-
-/**
- * filterString: a whitespace-separated set of filter expressions
- * eg "AT:d *:i"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- *
- */
-
-int android_log_addFilterString(AndroidLogFormat* p_format,
- const char* filterString);
-
-/**
- * returns 1 if this log line should be printed based on its priority
- * and tag, and 0 if it should not
- */
-int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
- android_LogPriority pri);
-
-/**
- * Splits a wire-format buffer into an AndroidLogEntry
- * entry allocated by caller. Pointers will point directly into buf
- *
- * Returns 0 on success and -1 on invalid wire format (entry will be
- * in unspecified state)
- */
-int android_log_processLogBuffer(struct logger_entry* buf,
- AndroidLogEntry* entry);
-
-/**
- * Like android_log_processLogBuffer, but for binary logs.
- *
- * If "map" is non-NULL, it will be used to convert the log tag number
- * into a string.
- */
-int android_log_processBinaryLogBuffer(struct logger_entry* buf,
- AndroidLogEntry* entry,
- const EventTagMap* map, char* messageBuf,
- int messageBufLen);
-
-/**
- * Formats a log message into a buffer
- *
- * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
- * If return value != defaultBuffer, caller must call free()
- * Returns NULL on malloc error
- */
-
-char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
- size_t defaultBufferSize,
- const AndroidLogEntry* p_line,
- size_t* p_outLength);
-
-/**
- * Either print or do not print log line, based on filter
- *
- * Assumes single threaded execution
- *
- */
-int android_log_printLogLine(AndroidLogFormat* p_format, int fd,
- const AndroidLogEntry* entry);
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h
deleted file mode 100644
index 166f387..0000000
--- a/liblog/include/private/android_logger.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-/* This file is used to define the internal protocol for the Android Logger */
-
-#pragma once
-
-/* Android private interfaces */
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#ifdef __cplusplus
-#include <string>
-#endif
-
-#include <log/log.h>
-#include <log/log_event_list.h>
-
-#define LOGGER_MAGIC 'l'
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-/* Header Structure to pstore */
-typedef struct __attribute__((__packed__)) {
- uint8_t magic;
- uint16_t len;
- uint16_t uid;
- uint16_t pid;
-} android_pmsg_log_header_t;
-
-/* Header Structure to logd, and second header for pstore */
-typedef struct __attribute__((__packed__)) {
- uint8_t id;
- uint16_t tid;
- log_time realtime;
-} android_log_header_t;
-
-/* Event Header Structure to logd */
-typedef struct __attribute__((__packed__)) {
- int32_t tag; // Little Endian Order
-} android_event_header_t;
-
-// Event payload EVENT_TYPE_LIST
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_LIST
- int8_t element_count;
-} android_event_list_t;
-
-// Event payload EVENT_TYPE_FLOAT
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_FLOAT
- float data;
-} android_event_float_t;
-
-/* Event payload EVENT_TYPE_INT */
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_INT
- int32_t data; // Little Endian Order
-} android_event_int_t;
-
-/* Event with single EVENT_TYPE_INT */
-typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- android_event_int_t payload;
-} android_log_event_int_t;
-
-/* Event payload EVENT_TYPE_LONG */
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_LONG
- int64_t data; // Little Endian Order
-} android_event_long_t;
-
-/* Event with single EVENT_TYPE_LONG */
-typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- android_event_long_t payload;
-} android_log_event_long_t;
-
-/*
- * Event payload EVENT_TYPE_STRING
- *
- * Danger: do not embed this structure into another structure.
- * This structure uses a flexible array member, and when
- * compiled using g++, __builtin_object_size(data, 1) returns
- * a bad value. This is possibly a g++ bug, or a bug due to
- * the fact that flexible array members are not supported
- * in C++.
- * http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c
- */
-
-typedef struct __attribute__((__packed__)) {
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length; // Little Endian Order
- char data[];
-} android_event_string_t;
-
-/* Event with single EVENT_TYPE_STRING */
-typedef struct __attribute__((__packed__)) {
- android_event_header_t header;
- int8_t type; // EVENT_TYPE_STRING;
- int32_t length; // Little Endian Order
- char data[];
-} android_log_event_string_t;
-
-#define ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE 256 /* 1MB file */
-#define ANDROID_LOG_PMSG_FILE_SEQUENCE 1000
-
-ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio,
- const char* filename, const char* buf,
- size_t len);
-
-#define LOG_ID_ANY ((log_id_t)-1)
-#define ANDROID_LOG_ANY ANDROID_LOG_UNKNOWN
-
-/* first 5 arguments match __android_log_msg_file_write, a cast is safe */
-typedef ssize_t (*__android_log_pmsg_file_read_fn)(log_id_t logId, char prio,
- const char* filename,
- const char* buf, size_t len,
- void* arg);
-
-ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio,
- const char* prefix,
- __android_log_pmsg_file_read_fn fn,
- void* arg);
-
-int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len);
-int __android_log_security_bswrite(int32_t tag, const char* payload);
-int __android_log_security(); /* Device Owner is present */
-
-/* Retrieve the composed event buffer */
-int android_log_write_list_buffer(android_log_context ctx, const char** msg);
-
-#if defined(__cplusplus)
-}
-#endif
diff --git a/liblog/include_vndk/android b/liblog/include_vndk/android
deleted file mode 120000
index a3c0320..0000000
--- a/liblog/include_vndk/android
+++ /dev/null
@@ -1 +0,0 @@
-../include/android
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log.h b/liblog/include_vndk/log/log.h
deleted file mode 100644
index ab4adc4..0000000
--- a/liblog/include_vndk/log/log.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*Special log.h file for VNDK linking modules*/
-
-#ifndef _LIBS_LOG_LOG_H
-#define _LIBS_LOG_LOG_H
-
-/* Historically vendors have depended on this header being included. */
-#include <fcntl.h>
-
-#include <android/log.h>
-#include <log/log_id.h>
-#include <log/log_main.h>
-#include <log/log_radio.h>
-#include <log/log_read.h>
-#include <log/log_safetynet.h>
-#include <log/log_system.h>
-#include <log/log_time.h>
-
-/*
- * LOG_TAG is the local tag used for the following simplified
- * logging macros. You can change this preprocessor definition
- * before using the other macros to change the tag.
- */
-
-#ifndef LOG_TAG
-#define LOG_TAG NULL
-#endif
-
-#endif /*_LIBS_LOG_LOG_H*/
diff --git a/liblog/include_vndk/log/log_event_list.h b/liblog/include_vndk/log/log_event_list.h
deleted file mode 100644
index 1f3dd37..0000000
--- a/liblog/include_vndk/log/log_event_list.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2005-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* Special log_event_list.h file for VNDK linking modules */
-
-#ifndef _LIBS_LOG_EVENT_LIST_H
-#define _LIBS_LOG_EVENT_LIST_H
-
-#include <stdint.h>
-
-#include <log/log_id.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * The opaque context used to manipulate lists of events.
- */
-#ifndef __android_log_context_defined
-#define __android_log_context_defined
-typedef struct android_log_context_internal* android_log_context;
-#endif
-
-/*
- * Creates a context associated with an event tag to write elements to
- * the list of events.
- */
-android_log_context create_android_logger(uint32_t tag);
-
-/* All lists must be braced by a begin and end call */
-/*
- * NB: If the first level braces are missing when specifying multiple
- * elements, we will manufacturer a list to embrace it for your API
- * convenience. For a single element, it will remain solitary.
- */
-int android_log_write_list_begin(android_log_context ctx);
-int android_log_write_list_end(android_log_context ctx);
-
-int android_log_write_int32(android_log_context ctx, int32_t value);
-int android_log_write_int64(android_log_context ctx, int64_t value);
-int android_log_write_string8(android_log_context ctx, const char* value);
-int android_log_write_string8_len(android_log_context ctx, const char* value,
- size_t maxlen);
-int android_log_write_float32(android_log_context ctx, float value);
-
-/* Submit the composed list context to the specified logger id */
-/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
-int android_log_write_list(android_log_context ctx, log_id_t id);
-
-/* Reset writer context */
-int android_log_reset(android_log_context ctx);
-
-/* Reset reader context */
-int android_log_parser_reset(android_log_context ctx,
- const char* msg, size_t len);
-
-/* Finished with reader or writer context */
-int android_log_destroy(android_log_context* ctx);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _LIBS_LOG_EVENT_LIST_H */
diff --git a/liblog/include_vndk/log/log_id.h b/liblog/include_vndk/log/log_id.h
deleted file mode 120000
index dce92b9..0000000
--- a/liblog/include_vndk/log/log_id.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_id.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_main.h b/liblog/include_vndk/log/log_main.h
deleted file mode 120000
index f2ec018..0000000
--- a/liblog/include_vndk/log/log_main.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_main.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_properties.h b/liblog/include_vndk/log/log_properties.h
deleted file mode 120000
index bbec426..0000000
--- a/liblog/include_vndk/log/log_properties.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_properties.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_radio.h b/liblog/include_vndk/log/log_radio.h
deleted file mode 120000
index 1e12b32..0000000
--- a/liblog/include_vndk/log/log_radio.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_radio.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_read.h b/liblog/include_vndk/log/log_read.h
deleted file mode 120000
index 01de8b9..0000000
--- a/liblog/include_vndk/log/log_read.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_read.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_safetynet.h b/liblog/include_vndk/log/log_safetynet.h
deleted file mode 120000
index a4614e7..0000000
--- a/liblog/include_vndk/log/log_safetynet.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_safetynet.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_system.h b/liblog/include_vndk/log/log_system.h
deleted file mode 120000
index d0d3904..0000000
--- a/liblog/include_vndk/log/log_system.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/log/log_system.h
\ No newline at end of file
diff --git a/liblog/include_vndk/log/log_time.h b/liblog/include_vndk/log/log_time.h
deleted file mode 100644
index 5a09959..0000000
--- a/liblog/include_vndk/log/log_time.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2005-2017 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 _LIBS_LOG_LOG_TIME_H
-#define _LIBS_LOG_LOG_TIME_H
-
-#include <stdint.h>
-
-/* struct log_time is a wire-format variant of struct timespec */
-#ifndef NS_PER_SEC
-#define NS_PER_SEC 1000000000ULL
-#endif
-#ifndef US_PER_SEC
-#define US_PER_SEC 1000000ULL
-#endif
-#ifndef MS_PER_SEC
-#define MS_PER_SEC 1000ULL
-#endif
-
-#ifndef __struct_log_time_defined
-#define __struct_log_time_defined
-
-#define LOG_TIME_SEC(t) ((t)->tv_sec)
-/* next power of two after NS_PER_SEC */
-#define LOG_TIME_NSEC(t) ((t)->tv_nsec & (UINT32_MAX >> 2))
-
-typedef struct log_time {
- uint32_t tv_sec;
- uint32_t tv_nsec;
-} __attribute__((__packed__)) log_time;
-
-#endif
-
-#endif /* _LIBS_LOG_LOG_TIME_H */
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
deleted file mode 100644
index f8d5ef0..0000000
--- a/liblog/liblog.map.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-LIBLOG {
- global:
- android_name_to_log_id; # apex llndk
- android_log_id_to_name; # llndk
- __android_log_assert;
- __android_log_buf_print;
- __android_log_buf_write;
- __android_log_print;
- __android_log_vprint;
- __android_log_write;
- local:
- *;
-};
-
-LIBLOG_L {
- global:
- android_logger_clear; # llndk
- android_logger_get_id; # llndk
- android_logger_get_log_readable_size; # llndk
- android_logger_get_log_version; # llndk
- android_logger_get_log_size; # llndk
- android_logger_list_alloc; # apex llndk
- android_logger_list_alloc_time; # apex llndk
- android_logger_list_free; # apex llndk
- android_logger_list_open; # apex llndk
- android_logger_list_read; # apex llndk
- android_logger_open; # apex llndk
- android_logger_set_log_size; # llndk
-};
-
-LIBLOG_M {
- global:
- android_logger_get_prune_list; # llndk
- android_logger_set_prune_list; # llndk
- android_logger_get_statistics; # llndk
- __android_log_error_write; # apex llndk
- __android_log_is_loggable;
- create_android_logger; # apex llndk
- android_log_destroy; # apex llndk
- android_log_write_list_begin; # apex llndk
- android_log_write_list_end; # apex llndk
- android_log_write_int32; # apex llndk
- android_log_write_int64; # apex llndk
- android_log_write_string8; # apex llndk
- android_log_write_string8_len; # apex llndk
- android_log_write_float32; # apex llndk
- android_log_write_list; # apex llndk
-
-};
-
-LIBLOG_O {
- global:
- __android_log_is_loggable_len;
- __android_log_is_debuggable; # apex llndk
-};
-
-LIBLOG_Q { # introduced=29
- global:
- __android_log_bswrite; # apex
- __android_log_btwrite; # apex
- __android_log_bwrite; # apex
- __android_log_close; # apex
- __android_log_security; # apex
- android_log_reset; # llndk
- android_log_parser_reset; # llndk
-};
-
-LIBLOG_R { # introduced=30
- global:
- __android_log_call_aborter;
- __android_log_default_aborter;
- __android_log_get_minimum_priority;
- __android_log_logd_logger;
- __android_log_security_bswrite; # apex
- __android_log_set_aborter;
- __android_log_set_default_tag;
- __android_log_set_logger;
- __android_log_set_minimum_priority;
- __android_log_stderr_logger;
- __android_log_write_log_message;
-};
-
-LIBLOG_PRIVATE {
- global:
- __android_log_pmsg_file_read;
- __android_log_pmsg_file_write;
- android_openEventTagMap;
- android_log_processBinaryLogBuffer;
- android_log_processLogBuffer;
- android_log_read_next;
- android_log_write_list_buffer;
- create_android_log_parser;
-};
diff --git a/liblog/log_event_list.cpp b/liblog/log_event_list.cpp
deleted file mode 100644
index cb70d48..0000000
--- a/liblog/log_event_list.cpp
+++ /dev/null
@@ -1,543 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <errno.h>
-#include <inttypes.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <log/log_event_list.h>
-#include <private/android_logger.h>
-
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
-enum ReadWriteFlag {
- kAndroidLoggerRead = 1,
- kAndroidLoggerWrite = 2,
-};
-
-struct android_log_context_internal {
- uint32_t tag;
- unsigned pos; /* Read/write position into buffer */
- unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
- unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
- unsigned list_nest_depth;
- unsigned len; /* Length or raw buffer. */
- bool overflow;
- bool list_stop; /* next call decrement list_nest_depth and issue a stop */
- ReadWriteFlag read_write_flag;
- uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
-};
-
-static void init_context(android_log_context_internal* context, uint32_t tag) {
- context->tag = tag;
- context->read_write_flag = kAndroidLoggerWrite;
- size_t needed = sizeof(android_event_list_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- }
- /* Everything is a list */
- context->storage[context->pos + 0] = EVENT_TYPE_LIST;
- context->list[0] = context->pos + 1;
- context->pos += needed;
-}
-
-static void init_parser_context(android_log_context_internal* context, const char* msg,
- size_t len) {
- len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
- context->len = len;
- memcpy(context->storage, msg, len);
- context->read_write_flag = kAndroidLoggerRead;
-}
-
-android_log_context create_android_logger(uint32_t tag) {
- android_log_context_internal* context;
-
- context =
- static_cast<android_log_context_internal*>(calloc(1, sizeof(android_log_context_internal)));
- if (!context) {
- return NULL;
- }
- init_context(context, tag);
-
- return (android_log_context)context;
-}
-
-android_log_context create_android_log_parser(const char* msg, size_t len) {
- android_log_context_internal* context;
-
- context =
- static_cast<android_log_context_internal*>(calloc(1, sizeof(android_log_context_internal)));
- if (!context) {
- return NULL;
- }
- init_parser_context(context, msg, len);
-
- return (android_log_context)context;
-}
-
-int android_log_destroy(android_log_context* ctx) {
- android_log_context_internal* context;
-
- context = (android_log_context_internal*)*ctx;
- if (!context) {
- return -EBADF;
- }
- memset(context, 0, sizeof(*context));
- free(context);
- *ctx = NULL;
- return 0;
-}
-
-int android_log_reset(android_log_context context) {
- uint32_t tag;
-
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
-
- tag = context->tag;
- memset(context, 0, sizeof(*context));
- init_context(context, tag);
-
- return 0;
-}
-
-int android_log_parser_reset(android_log_context context, const char* msg, size_t len) {
- if (!context || (kAndroidLoggerRead != context->read_write_flag)) {
- return -EBADF;
- }
-
- memset(context, 0, sizeof(*context));
- init_parser_context(context, msg, len);
-
- return 0;
-}
-
-int android_log_write_list_begin(android_log_context context) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- size_t needed = sizeof(android_event_list_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- context->list_nest_depth++;
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- if (context->overflow) {
- return -EIO;
- }
- auto* event_list = reinterpret_cast<android_event_list_t*>(&context->storage[context->pos]);
- event_list->type = EVENT_TYPE_LIST;
- event_list->element_count = 0;
- context->list[context->list_nest_depth] = context->pos + 1;
- context->count[context->list_nest_depth] = 0;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_int32(android_log_context context, int32_t value) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- size_t needed = sizeof(android_event_int_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- auto* event_int = reinterpret_cast<android_event_int_t*>(&context->storage[context->pos]);
- event_int->type = EVENT_TYPE_INT;
- event_int->data = value;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_int64(android_log_context context, int64_t value) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- size_t needed = sizeof(android_event_long_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- auto* event_long = reinterpret_cast<android_event_long_t*>(&context->storage[context->pos]);
- event_long->type = EVENT_TYPE_LONG;
- event_long->data = value;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_string8_len(android_log_context context, const char* value, size_t maxlen) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- if (!value) {
- value = "";
- }
- int32_t len = strnlen(value, maxlen);
- size_t needed = sizeof(android_event_string_t) + len;
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- /* Truncate string for delivery */
- len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
- if (len <= 0) {
- context->overflow = true;
- return -EIO;
- }
- }
- context->count[context->list_nest_depth]++;
- auto* event_string = reinterpret_cast<android_event_string_t*>(&context->storage[context->pos]);
- event_string->type = EVENT_TYPE_STRING;
- event_string->length = len;
- if (len) {
- memcpy(&event_string->data, value, len);
- }
- context->pos += needed;
- return len;
-}
-
-int android_log_write_string8(android_log_context ctx, const char* value) {
- return android_log_write_string8_len(ctx, value, MAX_EVENT_PAYLOAD);
-}
-
-int android_log_write_float32(android_log_context context, float value) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- size_t needed = sizeof(android_event_float_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- return -EIO;
- }
- context->count[context->list_nest_depth]++;
- auto* event_float = reinterpret_cast<android_event_float_t*>(&context->storage[context->pos]);
- event_float->type = EVENT_TYPE_FLOAT;
- event_float->data = value;
- context->pos += needed;
- return 0;
-}
-
-int android_log_write_list_end(android_log_context context) {
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
- context->overflow = true;
- context->list_nest_depth--;
- return -EOVERFLOW;
- }
- if (!context->list_nest_depth) {
- context->overflow = true;
- return -EOVERFLOW;
- }
- if (context->list[context->list_nest_depth] <= 0) {
- context->list_nest_depth--;
- context->overflow = true;
- return -EOVERFLOW;
- }
- context->storage[context->list[context->list_nest_depth]] =
- context->count[context->list_nest_depth];
- context->list_nest_depth--;
- return 0;
-}
-
-/*
- * Logs the list of elements to the event log.
- */
-int android_log_write_list(android_log_context context, log_id_t id) {
- const char* msg;
- ssize_t len;
-
- if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY) && (id != LOG_ID_STATS)) {
- return -EINVAL;
- }
-
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth) {
- return -EIO;
- }
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char*)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
- return (id == LOG_ID_EVENTS)
- ? __android_log_bwrite(context->tag, msg, len)
- : ((id == LOG_ID_STATS) ? __android_log_stats_bwrite(context->tag, msg, len)
- : __android_log_security_bwrite(context->tag, msg, len));
-}
-
-int android_log_write_list_buffer(android_log_context context, const char** buffer) {
- const char* msg;
- ssize_t len;
-
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->list_nest_depth) {
- return -EIO;
- }
- if (buffer == NULL) {
- return -EFAULT;
- }
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char*)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
- *buffer = msg;
- return len;
-}
-
-/*
- * Gets the next element. Parsing errors result in an EVENT_TYPE_UNKNOWN type.
- * If there is nothing to process, the complete field is set to non-zero. If
- * an EVENT_TYPE_UNKNOWN type is returned once, and the caller does not check
- * this and continues to call this function, the behavior is undefined
- * (although it won't crash).
- */
-static android_log_list_element android_log_read_next_internal(android_log_context context,
- int peek) {
- android_log_list_element elem;
- unsigned pos;
-
- memset(&elem, 0, sizeof(elem));
-
- /* Nothing to parse from this context, so return complete. */
- if (!context || (kAndroidLoggerRead != context->read_write_flag) ||
- (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) ||
- (context->count[context->list_nest_depth] >=
- (MAX_EVENT_PAYLOAD / (sizeof(uint8_t) + sizeof(uint8_t))))) {
- elem.type = EVENT_TYPE_UNKNOWN;
- if (context &&
- (context->list_stop || ((context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) &&
- !context->count[context->list_nest_depth]))) {
- elem.type = EVENT_TYPE_LIST_STOP;
- }
- elem.complete = true;
- return elem;
- }
-
- /*
- * Use a different variable to update the position in case this
- * operation is a "peek".
- */
- pos = context->pos;
- if (context->list_stop) {
- elem.type = EVENT_TYPE_LIST_STOP;
- elem.complete = !context->count[0] && (!context->list_nest_depth ||
- ((context->list_nest_depth == 1) && !context->count[1]));
- if (!peek) {
- /* Suck in superfluous stop */
- if (context->storage[pos] == EVENT_TYPE_LIST_STOP) {
- context->pos = pos + 1;
- }
- if (context->list_nest_depth) {
- --context->list_nest_depth;
- if (context->count[context->list_nest_depth]) {
- context->list_stop = false;
- }
- } else {
- context->list_stop = false;
- }
- }
- return elem;
- }
- if ((pos + 1) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
-
- elem.type = static_cast<AndroidEventLogType>(context->storage[pos]);
- switch ((int)elem.type) {
- case EVENT_TYPE_FLOAT:
- /* Rely on union to translate elem.data.int32 into elem.data.float32 */
- /* FALLTHRU */
- case EVENT_TYPE_INT: {
- elem.len = sizeof(int32_t);
- if ((pos + sizeof(android_event_int_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
-
- auto* event_int = reinterpret_cast<android_event_int_t*>(&context->storage[pos]);
- pos += sizeof(android_event_int_t);
- elem.data.int32 = event_int->data;
- /* common tangeable object suffix */
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
- return elem;
- }
-
- case EVENT_TYPE_LONG: {
- elem.len = sizeof(int64_t);
- if ((pos + sizeof(android_event_long_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
-
- auto* event_long = reinterpret_cast<android_event_long_t*>(&context->storage[pos]);
- pos += sizeof(android_event_long_t);
- elem.data.int64 = event_long->data;
- /* common tangeable object suffix */
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
- return elem;
- }
-
- case EVENT_TYPE_STRING: {
- if ((pos + sizeof(android_event_string_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
- auto* event_string = reinterpret_cast<android_event_string_t*>(&context->storage[pos]);
- pos += sizeof(android_event_string_t);
- // Wire format is int32_t, but elem.len is uint16_t...
- if (event_string->length >= UINT16_MAX) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
- elem.len = event_string->length;
- if ((pos + elem.len) > context->len) {
- elem.len = context->len - pos; /* truncate string */
- elem.complete = true;
- if (!elem.len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
- }
- elem.data.string = event_string->data;
- /* common tangeable object suffix */
- pos += elem.len;
- elem.complete = !context->list_nest_depth && !context->count[0];
- if (!peek) {
- if (!context->count[context->list_nest_depth] ||
- !--(context->count[context->list_nest_depth])) {
- context->list_stop = true;
- }
- context->pos = pos;
- }
- return elem;
- }
-
- case EVENT_TYPE_LIST: {
- if ((pos + sizeof(android_event_list_t)) > context->len) {
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = true;
- return elem;
- }
- auto* event_list = reinterpret_cast<android_event_list_t*>(&context->storage[pos]);
- pos += sizeof(android_event_list_t);
- elem.complete = context->list_nest_depth >= ANDROID_MAX_LIST_NEST_DEPTH;
- if (peek) {
- return elem;
- }
- if (context->count[context->list_nest_depth]) {
- context->count[context->list_nest_depth]--;
- }
- context->list_stop = event_list->element_count == 0;
- context->list_nest_depth++;
- if (context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) {
- context->count[context->list_nest_depth] = event_list->element_count;
- }
- context->pos = pos;
- return elem;
- }
-
- case EVENT_TYPE_LIST_STOP: /* Suprise Newline terminates lists. */
- pos++;
- if (!peek) {
- context->pos = pos;
- }
- elem.type = EVENT_TYPE_UNKNOWN;
- elem.complete = !context->list_nest_depth;
- if (context->list_nest_depth > 0) {
- elem.type = EVENT_TYPE_LIST_STOP;
- if (!peek) {
- context->list_nest_depth--;
- }
- }
- return elem;
-
- default:
- elem.type = EVENT_TYPE_UNKNOWN;
- return elem;
- }
-}
-
-android_log_list_element android_log_read_next(android_log_context ctx) {
- return android_log_read_next_internal(ctx, 0);
-}
-
-android_log_list_element android_log_peek_next(android_log_context ctx) {
- return android_log_read_next_internal(ctx, 1);
-}
diff --git a/liblog/log_event_write.cpp b/liblog/log_event_write.cpp
deleted file mode 100644
index 39afd0c..0000000
--- a/liblog/log_event_write.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2015 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 <errno.h>
-#include <stdint.h>
-
-#include <log/log.h>
-#include <log/log_event_list.h>
-
-#define MAX_SUBTAG_LEN 32
-
-int __android_log_error_write(int tag, const char* subTag, int32_t uid, const char* data,
- uint32_t dataLen) {
- int ret = -EINVAL;
-
- if (subTag && (data || !dataLen)) {
- android_log_context ctx = create_android_logger(tag);
-
- ret = -ENOMEM;
- if (ctx) {
- ret = android_log_write_string8_len(ctx, subTag, MAX_SUBTAG_LEN);
- if (ret >= 0) {
- ret = android_log_write_int32(ctx, uid);
- if (ret >= 0) {
- ret = android_log_write_string8_len(ctx, data, dataLen);
- if (ret >= 0) {
- ret = android_log_write_list(ctx, LOG_ID_EVENTS);
- }
- }
- }
- android_log_destroy(&ctx);
- }
- }
- return ret;
-}
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
deleted file mode 100644
index 14c408c..0000000
--- a/liblog/log_time.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2014 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 <ctype.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <private/android_logger.h>
-
-// Add %#q for fractional seconds to standard strptime function
-char* log_time::strptime(const char* s, const char* format) {
- time_t now;
-#ifdef __linux__
- *this = log_time(CLOCK_REALTIME);
- now = tv_sec;
-#else
- time(&now);
- tv_sec = now;
- tv_nsec = 0;
-#endif
-
- struct tm* ptm;
-#if !defined(_WIN32)
- struct tm tmBuf;
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&now);
-#endif
-
- char fmt[strlen(format) + 1];
- strcpy(fmt, format);
-
- char* ret = const_cast<char*>(s);
- char* cp;
- for (char* f = cp = fmt;; ++cp) {
- if (!*cp) {
- if (f != cp) {
- ret = ::strptime(ret, f, ptm);
- }
- break;
- }
- if (*cp != '%') {
- continue;
- }
- char* e = cp;
- ++e;
-#if (defined(__BIONIC__))
- if (*e == 's') {
- *cp = '\0';
- if (*f) {
- ret = ::strptime(ret, f, ptm);
- if (!ret) {
- break;
- }
- }
- tv_sec = 0;
- while (isdigit(*ret)) {
- tv_sec = tv_sec * 10 + *ret - '0';
- ++ret;
- }
- now = tv_sec;
-#if !defined(_WIN32)
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&now);
-#endif
- } else
-#endif
- {
- unsigned num = 0;
- while (isdigit(*e)) {
- num = num * 10 + *e - '0';
- ++e;
- }
- if (*e != 'q') {
- continue;
- }
- *cp = '\0';
- if (*f) {
- ret = ::strptime(ret, f, ptm);
- if (!ret) {
- break;
- }
- }
- unsigned long mul = NS_PER_SEC;
- if (num == 0) {
- num = INT_MAX;
- }
- tv_nsec = 0;
- while (isdigit(*ret) && num && (mul > 1)) {
- --num;
- mul /= 10;
- tv_nsec = tv_nsec + (*ret - '0') * mul;
- ++ret;
- }
- }
- f = cp = e;
- ++f;
- }
-
- if (ret) {
- tv_sec = mktime(ptm);
- return ret;
- }
-
-// Upon error, place a known value into the class, the current time.
-#ifdef __linux__
- *this = log_time(CLOCK_REALTIME);
-#else
- time(&now);
- tv_sec = now;
- tv_nsec = 0;
-#endif
- return ret;
-}
diff --git a/liblog/logd_reader.cpp b/liblog/logd_reader.cpp
deleted file mode 100644
index 611caed..0000000
--- a/liblog/logd_reader.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2007-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "logd_reader.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/parseint.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-
-// Connects to /dev/socket/<name> and returns the associated fd or returns -1 on error.
-// O_CLOEXEC is always set.
-static int socket_local_client(const std::string& name, int type, bool timeout) {
- sockaddr_un addr = {.sun_family = AF_LOCAL};
-
- std::string path = "/dev/socket/" + name;
- if (path.size() + 1 > sizeof(addr.sun_path)) {
- return -1;
- }
- strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
-
- int fd = socket(AF_LOCAL, type | SOCK_CLOEXEC, 0);
- if (fd == -1) {
- return -1;
- }
-
- if (timeout) {
- // Sending and receiving messages should be instantaneous, but we don't want to wait forever if
- // logd is hung, so we set a gracious 2s timeout.
- struct timeval t = {2, 0};
- if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &t, sizeof(t)) == -1) {
- return -1;
- }
- if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &t, sizeof(t)) == -1) {
- return -1;
- }
- }
-
- if (connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
- close(fd);
- return -1;
- }
-
- return fd;
-}
-
-/* worker for sending the command to the logger */
-ssize_t SendLogdControlMessage(char* buf, size_t buf_size) {
- ssize_t ret;
- size_t len;
- char* cp;
- int errno_save = 0;
- int sock = socket_local_client("logd", SOCK_STREAM, true);
- if (sock < 0) {
- return sock;
- }
-
- len = strlen(buf) + 1;
- ret = TEMP_FAILURE_RETRY(write(sock, buf, len));
- if (ret <= 0) {
- goto done;
- }
-
- len = buf_size;
- cp = buf;
- while ((ret = TEMP_FAILURE_RETRY(read(sock, cp, len))) > 0) {
- struct pollfd p;
-
- if (((size_t)ret == len) || (buf_size < PAGE_SIZE)) {
- break;
- }
-
- len -= ret;
- cp += ret;
-
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
-
- /* Give other side 20ms to refill pipe */
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 20));
-
- if (ret <= 0) {
- break;
- }
-
- if (!(p.revents & POLLIN)) {
- ret = 0;
- break;
- }
- }
-
- if (ret >= 0) {
- ret += buf_size - len;
- }
-
-done:
- if ((ret == -1) && errno) {
- errno_save = errno;
- }
- close(sock);
- if (errno_save) {
- errno = errno_save;
- }
- return ret;
-}
-
-static int check_log_success(char* buf, ssize_t ret) {
- if (ret < 0) {
- return ret;
- }
-
- if (strncmp(buf, "success", 7)) {
- errno = EINVAL;
- return -1;
- }
-
- return 0;
-}
-
-int android_logger_clear(struct logger* logger) {
- if (!android_logger_is_logd(logger)) {
- return -EINVAL;
- }
- uint32_t log_id = android_logger_get_id(logger);
- char buf[512];
- snprintf(buf, sizeof(buf), "clear %" PRIu32, log_id);
-
- return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
-}
-
-enum class LogSizeType : uint32_t {
- kAllotted = 0,
- kReadable,
- kConsumed,
-};
-
-static long GetLogSize(struct logger* logger, LogSizeType type) {
- if (!android_logger_is_logd(logger)) {
- return -EINVAL;
- }
-
- uint32_t log_id = android_logger_get_id(logger);
- char buf[512];
- switch (type) {
- case LogSizeType::kAllotted:
- snprintf(buf, sizeof(buf), "getLogSize %" PRIu32, log_id);
- break;
- case LogSizeType::kReadable:
- snprintf(buf, sizeof(buf), "getLogSizeReadable %" PRIu32, log_id);
- break;
- case LogSizeType::kConsumed:
- snprintf(buf, sizeof(buf), "getLogSizeUsed %" PRIu32, log_id);
- break;
- default:
- abort();
- }
-
- ssize_t ret = SendLogdControlMessage(buf, sizeof(buf));
- if (ret < 0) {
- return ret;
- }
-
- long size;
- if (!android::base::ParseInt(buf, &size)) {
- return -1;
- }
-
- return size;
-}
-
-long android_logger_get_log_size(struct logger* logger) {
- return GetLogSize(logger, LogSizeType::kAllotted);
-}
-
-long android_logger_get_log_readable_size(struct logger* logger) {
- return GetLogSize(logger, LogSizeType::kReadable);
-}
-
-long android_logger_get_log_consumed_size(struct logger* logger) {
- return GetLogSize(logger, LogSizeType::kConsumed);
-}
-
-int android_logger_set_log_size(struct logger* logger, unsigned long size) {
- if (!android_logger_is_logd(logger)) {
- return -EINVAL;
- }
-
- uint32_t log_id = android_logger_get_id(logger);
- char buf[512];
- snprintf(buf, sizeof(buf), "setLogSize %" PRIu32 " %lu", log_id, size);
-
- return check_log_success(buf, SendLogdControlMessage(buf, sizeof(buf)));
-}
-
-int android_logger_get_log_version(struct logger*) {
- return 4;
-}
-
-ssize_t android_logger_get_statistics(struct logger_list* logger_list, char* buf, size_t len) {
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- return -EINVAL;
- }
-
- char* cp = buf;
- size_t remaining = len;
- size_t n;
-
- n = snprintf(cp, remaining, "getStatistics");
- n = MIN(n, remaining);
- remaining -= n;
- cp += n;
-
- for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
- if ((1 << log_id) & logger_list->log_mask) {
- n = snprintf(cp, remaining, " %zu", log_id);
- n = MIN(n, remaining);
- remaining -= n;
- cp += n;
- }
- }
-
- if (logger_list->pid) {
- snprintf(cp, remaining, " pid=%u", logger_list->pid);
- }
-
- return SendLogdControlMessage(buf, len);
-}
-ssize_t android_logger_get_prune_list(struct logger_list* logger_list, char* buf, size_t len) {
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- return -EINVAL;
- }
-
- snprintf(buf, len, "getPruneList");
- return SendLogdControlMessage(buf, len);
-}
-
-int android_logger_set_prune_list(struct logger_list* logger_list, const char* buf, size_t len) {
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- return -EINVAL;
- }
-
- std::string cmd = "setPruneList " + std::string{buf, len};
-
- return check_log_success(cmd.data(), SendLogdControlMessage(cmd.data(), cmd.size()));
-}
-
-static int logdOpen(struct logger_list* logger_list) {
- char buffer[256], *cp, c;
- int ret, remaining, sock;
-
- sock = atomic_load(&logger_list->fd);
- if (sock > 0) {
- return sock;
- }
-
- sock = socket_local_client("logdr", SOCK_SEQPACKET, false);
- if (sock <= 0) {
- if ((sock == -1) && errno) {
- return -errno;
- }
- return sock;
- }
-
- strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
- cp = buffer + strlen(buffer);
-
- strcpy(cp, " lids");
- cp += 5;
- c = '=';
- remaining = sizeof(buffer) - (cp - buffer);
-
- for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
- if ((1 << log_id) & logger_list->log_mask) {
- ret = snprintf(cp, remaining, "%c%zu", c, log_id);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- c = ',';
- }
- }
-
- if (logger_list->tail) {
- ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
- if (logger_list->mode & ANDROID_LOG_WRAP) {
- // ToDo: alternate API to allow timeout to be adjusted.
- ret = snprintf(cp, remaining, " timeout=%u", ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
- ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32, logger_list->start.tv_sec,
- logger_list->start.tv_nsec);
- ret = MIN(ret, remaining);
- remaining -= ret;
- cp += ret;
- }
-
- if (logger_list->pid) {
- ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
- ret = MIN(ret, remaining);
- cp += ret;
- }
-
- ret = TEMP_FAILURE_RETRY(write(sock, buffer, cp - buffer));
- int write_errno = errno;
-
- if (ret <= 0) {
- close(sock);
- if (ret == -1) {
- return -write_errno;
- }
- if (ret == 0) {
- return -EIO;
- }
- return ret;
- }
-
- ret = atomic_exchange(&logger_list->fd, sock);
- if ((ret > 0) && (ret != sock)) {
- close(ret);
- }
- return sock;
-}
-
-/* Read from the selected logs */
-int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg) {
- int ret = logdOpen(logger_list);
- if (ret < 0) {
- return ret;
- }
-
- /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
- ret = TEMP_FAILURE_RETRY(recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0));
- if ((logger_list->mode & ANDROID_LOG_NONBLOCK) && ret == 0) {
- return -EAGAIN;
- }
-
- if (ret == -1) {
- return -errno;
- }
- return ret;
-}
-
-/* Close all the logs */
-void LogdClose(struct logger_list* logger_list) {
- int sock = atomic_exchange(&logger_list->fd, -1);
- if (sock > 0) {
- close(sock);
- }
-}
diff --git a/liblog/logd_reader.h b/liblog/logd_reader.h
deleted file mode 100644
index 68eef02..0000000
--- a/liblog/logd_reader.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <sys/cdefs.h>
-#include <unistd.h>
-
-#include "log/log_read.h"
-
-__BEGIN_DECLS
-
-int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg);
-void LogdClose(struct logger_list* logger_list);
-
-ssize_t SendLogdControlMessage(char* buf, size_t buf_size);
-
-__END_DECLS
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
deleted file mode 100644
index f5d19ca..0000000
--- a/liblog/logd_writer.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2007-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "logd_writer.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <stdarg.h>
-#include <stdatomic.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-#include "uio.h"
-
-static atomic_int logd_socket;
-
-// Note that it is safe to call connect() multiple times on DGRAM Unix domain sockets, so this
-// function is used to reconnect to logd without requiring a new socket.
-static void LogdConnect() {
- sockaddr_un un = {};
- un.sun_family = AF_UNIX;
- strcpy(un.sun_path, "/dev/socket/logdw");
- TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)));
-}
-
-// logd_socket should only be opened once. If we see that logd_socket is uninitialized, we create a
-// new socket and attempt to exchange it into the atomic logd_socket. If the compare/exchange was
-// successful, then that will be the socket used for the duration of the program, otherwise a
-// different thread has already opened and written the socket to the atomic, so close the new socket
-// and return.
-static void GetSocket() {
- if (logd_socket != 0) {
- return;
- }
-
- int new_socket = TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0));
- if (new_socket <= 0) {
- return;
- }
-
- int uninitialized_value = 0;
- if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) {
- close(new_socket);
- return;
- }
-
- LogdConnect();
-}
-
-// This is the one exception to the above. Zygote uses this to clean up open FD's after fork() and
-// before specialization. It is single threaded at this point and therefore this function is
-// explicitly not thread safe. It sets logd_socket to 0, so future logs will be safely initialized
-// whenever they happen.
-void LogdClose() {
- if (logd_socket > 0) {
- close(logd_socket);
- }
- logd_socket = 0;
-}
-
-int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
- ssize_t ret;
- static const unsigned headerLength = 1;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- size_t i, payloadSize;
-
- GetSocket();
-
- if (logd_socket <= 0) {
- return -EBADF;
- }
-
- /* logd, after initialization and priv drop */
- if (getuid() == AID_LOGD) {
- /*
- * ignore log messages we send to ourself (logd).
- * Such log messages are often generated by libraries we depend on
- * which use standard Android logging.
- */
- return 0;
- }
-
- header.id = logId;
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
-
- newVec[0].iov_base = (unsigned char*)&header;
- newVec[0].iov_len = sizeof(header);
-
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- break;
- }
- }
-
- ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
- if (ret < 0) {
- LogdConnect();
-
- ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
- }
-
- if (ret < 0) {
- ret = -errno;
- }
-
- return ret;
-}
diff --git a/liblog/logd_writer.h b/liblog/logd_writer.h
deleted file mode 100644
index 41197b5..0000000
--- a/liblog/logd_writer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <stddef.h>
-
-#include <android/log.h>
-
-int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-void LogdClose();
diff --git a/liblog/logger.h b/liblog/logger.h
deleted file mode 100644
index ddff19d..0000000
--- a/liblog/logger.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <stdatomic.h>
-#include <sys/cdefs.h>
-
-#include <log/log.h>
-
-#include "uio.h"
-
-__BEGIN_DECLS
-
-struct logger_list {
- atomic_int fd;
- int mode;
- unsigned int tail;
- log_time start;
- pid_t pid;
- uint32_t log_mask;
-};
-
-// Format for a 'logger' entry: uintptr_t where only the bottom 32 bits are used.
-// bit 31: Set if this 'logger' is for logd.
-// bit 30: Set if this 'logger' is for pmsg
-// bits 0-2: the decimal value of the log buffer.
-// Other bits are unused.
-
-#define LOGGER_LOGD (1U << 31)
-#define LOGGER_PMSG (1U << 30)
-#define LOGGER_LOG_ID_MASK ((1U << 3) - 1)
-
-inline bool android_logger_is_logd(struct logger* logger) {
- return reinterpret_cast<uintptr_t>(logger) & LOGGER_LOGD;
-}
-
-__END_DECLS
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
deleted file mode 100644
index e72290e..0000000
--- a/liblog/logger_name.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-** Copyright 2013-2014, 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 <string.h>
-#include <type_traits>
-
-#include <log/log.h>
-
-/* In the future, we would like to make this list extensible */
-static const char* LOG_NAME[LOG_ID_MAX] = {
- /* clang-format off */
- [LOG_ID_MAIN] = "main",
- [LOG_ID_RADIO] = "radio",
- [LOG_ID_EVENTS] = "events",
- [LOG_ID_SYSTEM] = "system",
- [LOG_ID_CRASH] = "crash",
- [LOG_ID_STATS] = "stats",
- [LOG_ID_SECURITY] = "security",
- [LOG_ID_KERNEL] = "kernel",
- /* clang-format on */
-};
-
-const char* android_log_id_to_name(log_id_t log_id) {
- if (log_id >= LOG_ID_MAX) {
- log_id = LOG_ID_MAIN;
- }
- return LOG_NAME[log_id];
-}
-
-static_assert(std::is_same<std::underlying_type<log_id_t>::type, uint32_t>::value,
- "log_id_t must be an uint32_t");
-
-static_assert(std::is_same<std::underlying_type<android_LogPriority>::type, uint32_t>::value,
- "log_id_t must be an uint32_t");
-
-log_id_t android_name_to_log_id(const char* logName) {
- const char* b;
- unsigned int ret;
-
- if (!logName) {
- return static_cast<log_id_t>(LOG_ID_MAX);
- }
-
- b = strrchr(logName, '/');
- if (!b) {
- b = logName;
- } else {
- ++b;
- }
-
- for (ret = LOG_ID_MIN; ret < LOG_ID_MAX; ++ret) {
- const char* l = LOG_NAME[ret];
- if (l && !strcmp(b, l)) {
- return static_cast<log_id_t>(ret);
- }
- }
-
- return static_cast<log_id_t>(LOG_ID_MAX);
-}
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
deleted file mode 100644
index 4937042..0000000
--- a/liblog/logger_read.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
-** Copyright 2013-2014, 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 "log/log_read.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <sched.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <android/log.h>
-
-#include "logd_reader.h"
-#include "logger.h"
-#include "pmsg_reader.h"
-
-/* method for getting the associated sublog id */
-log_id_t android_logger_get_id(struct logger* logger) {
- return static_cast<log_id_t>(reinterpret_cast<uintptr_t>(logger) & LOGGER_LOG_ID_MASK);
-}
-
-static struct logger_list* android_logger_list_alloc_internal(int mode, unsigned int tail,
- log_time start, pid_t pid) {
- auto* logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(struct logger_list)));
- if (!logger_list) {
- return nullptr;
- }
-
- logger_list->mode = mode;
- logger_list->start = start;
- logger_list->tail = tail;
- logger_list->pid = pid;
-
- return logger_list;
-}
-
-struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
- return android_logger_list_alloc_internal(mode, tail, log_time(0, 0), pid);
-}
-
-struct logger_list* android_logger_list_alloc_time(int mode, log_time start, pid_t pid) {
- return android_logger_list_alloc_internal(mode, 0, start, pid);
-}
-
-/* Open the named log and add it to the logger list */
-struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) {
- if (!logger_list || (logId >= LOG_ID_MAX)) {
- return nullptr;
- }
-
- logger_list->log_mask |= 1 << logId;
-
- uintptr_t logger = logId;
- logger |= (logger_list->mode & ANDROID_LOG_PSTORE) ? LOGGER_PMSG : LOGGER_LOGD;
- return reinterpret_cast<struct logger*>(logger);
-}
-
-/* Open the single named log and make it part of a new logger list */
-struct logger_list* android_logger_list_open(log_id_t logId, int mode, unsigned int tail,
- pid_t pid) {
- struct logger_list* logger_list = android_logger_list_alloc(mode, tail, pid);
-
- if (!logger_list) {
- return NULL;
- }
-
- if (!android_logger_open(logger_list, logId)) {
- android_logger_list_free(logger_list);
- return NULL;
- }
-
- return logger_list;
-}
-
-int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
- if (logger_list == nullptr || logger_list->log_mask == 0) {
- return -EINVAL;
- }
-
- int ret = 0;
-
-#ifdef __ANDROID__
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- ret = PmsgRead(logger_list, log_msg);
- } else {
- ret = LogdRead(logger_list, log_msg);
- }
-#endif
-
- if (ret <= 0) {
- return ret;
- }
-
- if (ret > LOGGER_ENTRY_MAX_LEN) {
- ret = LOGGER_ENTRY_MAX_LEN;
- }
-
- if (ret < static_cast<int>(sizeof(log_msg->entry))) {
- return -EINVAL;
- }
-
- if (log_msg->entry.hdr_size < sizeof(log_msg->entry) ||
- log_msg->entry.hdr_size >= LOGGER_ENTRY_MAX_LEN - sizeof(log_msg->entry)) {
- return -EINVAL;
- }
-
- if (log_msg->entry.len > ret - log_msg->entry.hdr_size) {
- return -EINVAL;
- }
-
- log_msg->buf[log_msg->entry.len + log_msg->entry.hdr_size] = '\0';
-
- return ret;
-}
-
-/* Close all the logs */
-void android_logger_list_free(struct logger_list* logger_list) {
- if (logger_list == NULL) {
- return;
- }
-
-#ifdef __ANDROID__
- if (logger_list->mode & ANDROID_LOG_PSTORE) {
- PmsgClose(logger_list);
- } else {
- LogdClose(logger_list);
- }
-#endif
-
- free(logger_list);
-}
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
deleted file mode 100644
index 22c7eca..0000000
--- a/liblog/logger_write.cpp
+++ /dev/null
@@ -1,519 +0,0 @@
-/*
- * Copyright (C) 2007-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "logger_write.h"
-
-#include <errno.h>
-#include <inttypes.h>
-#include <libgen.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-
-#ifdef __BIONIC__
-#include <android/set_abort_message.h>
-#endif
-
-#include <atomic>
-
-#include <android-base/errno_restorer.h>
-#include <android-base/macros.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "android/log.h"
-#include "log/log_read.h"
-#include "logger.h"
-#include "uio.h"
-
-#ifdef __ANDROID__
-#include "logd_writer.h"
-#include "pmsg_writer.h"
-#endif
-
-#if defined(__APPLE__)
-#include <pthread.h>
-#elif defined(__linux__) && !defined(__ANDROID__)
-#include <syscall.h>
-#elif defined(_WIN32)
-#include <windows.h>
-#endif
-
-using android::base::ErrnoRestorer;
-
-#define LOG_BUF_SIZE 1024
-
-#if defined(__ANDROID__)
-static int check_log_uid_permissions() {
- uid_t uid = getuid();
-
- /* Matches clientHasLogCredentials() in logd */
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- uid = geteuid();
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG)) {
- gid_t gid = getgid();
- if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- gid = getegid();
- if ((gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- int num_groups;
- gid_t* groups;
-
- num_groups = getgroups(0, NULL);
- if (num_groups <= 0) {
- return -EPERM;
- }
- groups = static_cast<gid_t*>(calloc(num_groups, sizeof(gid_t)));
- if (!groups) {
- return -ENOMEM;
- }
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- free(groups);
- if (num_groups <= 0) {
- return -EPERM;
- }
- }
- }
- }
- }
- return 0;
-}
-#endif
-
-/*
- * Release any logger resources. A new log write will immediately re-acquire.
- */
-void __android_log_close() {
-#ifdef __ANDROID__
- LogdClose();
- PmsgClose();
-#endif
-}
-
-#if defined(__GLIBC__) || defined(_WIN32)
-static const char* getprogname() {
-#if defined(__GLIBC__)
- return program_invocation_short_name;
-#elif defined(_WIN32)
- static bool first = true;
- static char progname[MAX_PATH] = {};
-
- if (first) {
- char path[PATH_MAX + 1];
- DWORD result = GetModuleFileName(nullptr, path, sizeof(path) - 1);
- if (result == 0 || result == sizeof(path) - 1) return "";
- path[PATH_MAX - 1] = 0;
-
- char* path_basename = basename(path);
-
- snprintf(progname, sizeof(progname), "%s", path_basename);
- first = false;
- }
-
- return progname;
-#endif
-}
-#endif
-
-// It's possible for logging to happen during static initialization before our globals are
-// initialized, so we place this std::string in a function such that it is initialized on the first
-// call.
-std::string& GetDefaultTag() {
- static std::string default_tag = getprogname();
- return default_tag;
-}
-
-void __android_log_set_default_tag(const char* tag) {
- GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD);
-}
-
-static std::atomic_int32_t minimum_log_priority = ANDROID_LOG_DEFAULT;
-int32_t __android_log_set_minimum_priority(int32_t priority) {
- return minimum_log_priority.exchange(priority, std::memory_order_relaxed);
-}
-
-int32_t __android_log_get_minimum_priority() {
- return minimum_log_priority;
-}
-
-#ifdef __ANDROID__
-static __android_logger_function logger_function = __android_log_logd_logger;
-#else
-static __android_logger_function logger_function = __android_log_stderr_logger;
-#endif
-
-void __android_log_set_logger(__android_logger_function logger) {
- logger_function = logger;
-}
-
-void __android_log_default_aborter(const char* abort_message) {
-#ifdef __ANDROID__
- android_set_abort_message(abort_message);
-#else
- UNUSED(abort_message);
-#endif
- abort();
-}
-
-static __android_aborter_function aborter_function = __android_log_default_aborter;
-
-void __android_log_set_aborter(__android_aborter_function aborter) {
- aborter_function = aborter;
-}
-
-void __android_log_call_aborter(const char* abort_message) {
- aborter_function(abort_message);
-}
-
-#ifdef __ANDROID__
-static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
- int ret;
- struct timespec ts;
-
- if (log_id == LOG_ID_KERNEL) {
- return -EINVAL;
- }
-
- clock_gettime(CLOCK_REALTIME, &ts);
-
- if (log_id == LOG_ID_SECURITY) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
-
- ret = check_log_uid_permissions();
- if (ret < 0) {
- return ret;
- }
- if (!__android_log_security()) {
- /* If only we could reset downstream logd counter */
- return -EPERM;
- }
- } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
- }
-
- ret = LogdWrite(log_id, &ts, vec, nr);
- PmsgWrite(log_id, &ts, vec, nr);
-
- return ret;
-}
-#else
-static int write_to_log(log_id_t, struct iovec*, size_t) {
- // Non-Android text logs should go to __android_log_stderr_logger, not here.
- // Non-Android binary logs are always dropped.
- return 1;
-}
-#endif
-
-// Copied from base/threads.cpp
-static uint64_t GetThreadId() {
-#if defined(__BIONIC__)
- return gettid();
-#elif defined(__APPLE__)
- uint64_t tid;
- pthread_threadid_np(NULL, &tid);
- return tid;
-#elif defined(__linux__)
- return syscall(__NR_gettid);
-#elif defined(_WIN32)
- return GetCurrentThreadId();
-#endif
-}
-
-void __android_log_stderr_logger(const struct __android_log_message* log_message) {
- struct tm now;
- time_t t = time(nullptr);
-
-#if defined(_WIN32)
- localtime_s(&now, &t);
-#else
- localtime_r(&t, &now);
-#endif
-
- char timestamp[32];
- strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
-
- static const char log_characters[] = "XXVDIWEF";
- static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
- "Mismatch in size of log_characters and values in android_LogPriority");
- int32_t priority =
- log_message->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : log_message->priority;
- char priority_char = log_characters[priority];
- uint64_t tid = GetThreadId();
-
- if (log_message->file != nullptr) {
- fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
- log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
- tid, log_message->file, log_message->line, log_message->message);
- } else {
- fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n",
- log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
- tid, log_message->message);
- }
-}
-
-void __android_log_logd_logger(const struct __android_log_message* log_message) {
- int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;
-
- struct iovec vec[3];
- vec[0].iov_base =
- const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
- vec[0].iov_len = 1;
- vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
- vec[1].iov_len = strlen(log_message->tag) + 1;
- vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
- vec[2].iov_len = strlen(log_message->message) + 1;
-
- write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
-}
-
-int __android_log_write(int prio, const char* tag, const char* msg) {
- return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
-}
-
-void __android_log_write_log_message(__android_log_message* log_message) {
- ErrnoRestorer errno_restorer;
-
- if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
- log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
- log_message->buffer_id != LOG_ID_CRASH) {
- return;
- }
-
- if (log_message->tag == nullptr) {
- log_message->tag = GetDefaultTag().c_str();
- }
-
-#if __BIONIC__
- if (log_message->priority == ANDROID_LOG_FATAL) {
- android_set_abort_message(log_message->message);
- }
-#endif
-
- logger_function(log_message);
-}
-
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- __android_log_message log_message = {
- sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, msg};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
-
- __android_log_message log_message = {
- sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- va_list ap;
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
-
- __android_log_message log_message = {
- sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...) {
- ErrnoRestorer errno_restorer;
-
- if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
- return -EPERM;
- }
-
- va_list ap;
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
-
- __android_log_message log_message = {
- sizeof(__android_log_message), bufID, prio, tag, nullptr, 0, buf};
- __android_log_write_log_message(&log_message);
- return 1;
-}
-
-void __android_log_assert(const char* cond, const char* tag, const char* fmt, ...) {
- __attribute__((uninitialized)) char buf[LOG_BUF_SIZE];
-
- if (fmt) {
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
- va_end(ap);
- } else {
- /* Msg not provided, log condition. N.B. Do not use cond directly as
- * format string as it could contain spurious '%' syntax (e.g.
- * "%d" in "blocks%devs == 0").
- */
- if (cond)
- snprintf(buf, LOG_BUF_SIZE, "Assertion failed: %s", cond);
- else
- strcpy(buf, "Unspecified assertion failed");
- }
-
- // Log assertion failures to stderr for the benefit of "adb shell" users
- // and gtests (http://b/23675822).
- TEMP_FAILURE_RETRY(write(2, buf, strlen(buf)));
- TEMP_FAILURE_RETRY(write(2, "\n", 1));
-
- __android_log_write(ANDROID_LOG_FATAL, tag, buf);
- __android_log_call_aborter(buf);
- abort();
-}
-
-int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 2);
-}
-
-int __android_log_stats_bwrite(int32_t tag, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_STATS, vec, 2);
-}
-
-int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[2];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = (void*)payload;
- vec[1].iov_len = len;
-
- return write_to_log(LOG_ID_SECURITY, vec, 2);
-}
-
-/*
- * Like __android_log_bwrite, but takes the type as well. Doesn't work
- * for the general case where we're generating lists of stuff, but very
- * handy if we just want to dump an integer into the log.
- */
-int __android_log_btwrite(int32_t tag, char type, const void* payload, size_t len) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[3];
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = (void*)payload;
- vec[2].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 3);
-}
-
-/*
- * Like __android_log_bwrite, but used for writing strings to the
- * event log.
- */
-int __android_log_bswrite(int32_t tag, const char* payload) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
-
- return write_to_log(LOG_ID_EVENTS, vec, 4);
-}
-
-/*
- * Like __android_log_security_bwrite, but used for writing strings to the
- * security log.
- */
-int __android_log_security_bswrite(int32_t tag, const char* payload) {
- ErrnoRestorer errno_restorer;
-
- struct iovec vec[4];
- char type = EVENT_TYPE_STRING;
- uint32_t len = strlen(payload);
-
- vec[0].iov_base = &tag;
- vec[0].iov_len = sizeof(tag);
- vec[1].iov_base = &type;
- vec[1].iov_len = sizeof(type);
- vec[2].iov_base = &len;
- vec[2].iov_len = sizeof(len);
- vec[3].iov_base = (void*)payload;
- vec[3].iov_len = len;
-
- return write_to_log(LOG_ID_SECURITY, vec, 4);
-}
diff --git a/liblog/logger_write.h b/liblog/logger_write.h
deleted file mode 100644
index eee2778..0000000
--- a/liblog/logger_write.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <string>
-
-std::string& GetDefaultTag();
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
deleted file mode 100644
index a5c5edd..0000000
--- a/liblog/logprint.cpp
+++ /dev/null
@@ -1,1748 +0,0 @@
-/*
-**
-** Copyright 2006-2014, 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 __MINGW32__
-#define HAVE_STRSEP
-#endif
-
-#include <log/logprint.h>
-
-#include <assert.h>
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#ifndef __MINGW32__
-#include <pwd.h>
-#endif
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <wchar.h>
-
-#include <cutils/list.h>
-
-#include <log/log.h>
-#include <log/log_read.h>
-#include <private/android_logger.h>
-
-#define MS_PER_NSEC 1000000
-#define US_PER_NSEC 1000
-
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-typedef struct FilterInfo_t {
- char* mTag;
- android_LogPriority mPri;
- struct FilterInfo_t* p_next;
-} FilterInfo;
-
-struct AndroidLogFormat_t {
- android_LogPriority global_pri;
- FilterInfo* filters;
- AndroidLogPrintFormat format;
- bool colored_output;
- bool usec_time_output;
- bool nsec_time_output;
- bool printable_output;
- bool year_output;
- bool zone_output;
- bool epoch_output;
- bool monotonic_output;
- bool uid_output;
- bool descriptive_output;
-};
-
-/*
- * API issues prevent us from exposing "descriptive" in AndroidLogFormat_t
- * during android_log_processBinaryLogBuffer(), so we break layering.
- */
-static bool descriptive_output = false;
-
-/*
- * 8-bit color tags. See ECMA-48 Set Graphics Rendition in
- * [console_codes(4)](https://man7.org/linux/man-pages/man4/console_codes.4.html).
- *
- * The text manipulation character stream is defined as:
- * ESC [ <parameter #> m
- *
- * We use "set <color> foreground" escape sequences instead of
- * "256/24-bit foreground color". This allows colors to render
- * according to user preferences in terminal emulator settings
- */
-#define ANDROID_COLOR_BLUE 34
-#define ANDROID_COLOR_DEFAULT 39
-#define ANDROID_COLOR_GREEN 32
-#define ANDROID_COLOR_RED 31
-#define ANDROID_COLOR_YELLOW 33
-
-static FilterInfo* filterinfo_new(const char* tag, android_LogPriority pri) {
- FilterInfo* p_ret;
-
- p_ret = (FilterInfo*)calloc(1, sizeof(FilterInfo));
- p_ret->mTag = strdup(tag);
- p_ret->mPri = pri;
-
- return p_ret;
-}
-
-/* balance to above, filterinfo_free left unimplemented */
-
-/*
- * Note: also accepts 0-9 priorities
- * returns ANDROID_LOG_UNKNOWN if the character is unrecognized
- */
-static android_LogPriority filterCharToPri(char c) {
- android_LogPriority pri;
-
- c = tolower(c);
-
- if (c >= '0' && c <= '9') {
- if (c >= ('0' + ANDROID_LOG_SILENT)) {
- pri = ANDROID_LOG_VERBOSE;
- } else {
- pri = (android_LogPriority)(c - '0');
- }
- } else if (c == 'v') {
- pri = ANDROID_LOG_VERBOSE;
- } else if (c == 'd') {
- pri = ANDROID_LOG_DEBUG;
- } else if (c == 'i') {
- pri = ANDROID_LOG_INFO;
- } else if (c == 'w') {
- pri = ANDROID_LOG_WARN;
- } else if (c == 'e') {
- pri = ANDROID_LOG_ERROR;
- } else if (c == 'f') {
- pri = ANDROID_LOG_FATAL;
- } else if (c == 's') {
- pri = ANDROID_LOG_SILENT;
- } else if (c == '*') {
- pri = ANDROID_LOG_DEFAULT;
- } else {
- pri = ANDROID_LOG_UNKNOWN;
- }
-
- return pri;
-}
-
-static char filterPriToChar(android_LogPriority pri) {
- switch (pri) {
- /* clang-format off */
- case ANDROID_LOG_VERBOSE: return 'V';
- case ANDROID_LOG_DEBUG: return 'D';
- case ANDROID_LOG_INFO: return 'I';
- case ANDROID_LOG_WARN: return 'W';
- case ANDROID_LOG_ERROR: return 'E';
- case ANDROID_LOG_FATAL: return 'F';
- case ANDROID_LOG_SILENT: return 'S';
-
- case ANDROID_LOG_DEFAULT:
- case ANDROID_LOG_UNKNOWN:
- default: return '?';
- /* clang-format on */
- }
-}
-
-static int colorFromPri(android_LogPriority pri) {
- switch (pri) {
- /* clang-format off */
- case ANDROID_LOG_VERBOSE: return ANDROID_COLOR_DEFAULT;
- case ANDROID_LOG_DEBUG: return ANDROID_COLOR_BLUE;
- case ANDROID_LOG_INFO: return ANDROID_COLOR_GREEN;
- case ANDROID_LOG_WARN: return ANDROID_COLOR_YELLOW;
- case ANDROID_LOG_ERROR: return ANDROID_COLOR_RED;
- case ANDROID_LOG_FATAL: return ANDROID_COLOR_RED;
- case ANDROID_LOG_SILENT: return ANDROID_COLOR_DEFAULT;
-
- case ANDROID_LOG_DEFAULT:
- case ANDROID_LOG_UNKNOWN:
- default: return ANDROID_COLOR_DEFAULT;
- /* clang-format on */
- }
-}
-
-static android_LogPriority filterPriForTag(AndroidLogFormat* p_format, const char* tag) {
- FilterInfo* p_curFilter;
-
- for (p_curFilter = p_format->filters; p_curFilter != NULL; p_curFilter = p_curFilter->p_next) {
- if (0 == strcmp(tag, p_curFilter->mTag)) {
- if (p_curFilter->mPri == ANDROID_LOG_DEFAULT) {
- return p_format->global_pri;
- } else {
- return p_curFilter->mPri;
- }
- }
- }
-
- return p_format->global_pri;
-}
-
-/**
- * returns 1 if this log line should be printed based on its priority
- * and tag, and 0 if it should not
- */
-int android_log_shouldPrintLine(AndroidLogFormat* p_format, const char* tag,
- android_LogPriority pri) {
- return pri >= filterPriForTag(p_format, tag);
-}
-
-AndroidLogFormat* android_log_format_new() {
- AndroidLogFormat* p_ret;
-
- p_ret = static_cast<AndroidLogFormat*>(calloc(1, sizeof(AndroidLogFormat)));
-
- p_ret->global_pri = ANDROID_LOG_VERBOSE;
- p_ret->format = FORMAT_BRIEF;
- p_ret->colored_output = false;
- p_ret->usec_time_output = false;
- p_ret->nsec_time_output = false;
- p_ret->printable_output = false;
- p_ret->year_output = false;
- p_ret->zone_output = false;
- p_ret->epoch_output = false;
- p_ret->monotonic_output = false;
- p_ret->uid_output = false;
- p_ret->descriptive_output = false;
- descriptive_output = false;
-
- return p_ret;
-}
-
-static list_declare(convertHead);
-
-void android_log_format_free(AndroidLogFormat* p_format) {
- FilterInfo *p_info, *p_info_old;
-
- p_info = p_format->filters;
-
- while (p_info != NULL) {
- p_info_old = p_info;
- p_info = p_info->p_next;
-
- free(p_info_old);
- }
-
- free(p_format);
-
- /* Free conversion resource, can always be reconstructed */
- while (!list_empty(&convertHead)) {
- struct listnode* node = list_head(&convertHead);
- list_remove(node);
- LOG_ALWAYS_FATAL_IF(node == list_head(&convertHead), "corrupted list");
- free(node);
- }
-}
-
-int android_log_setPrintFormat(AndroidLogFormat* p_format, AndroidLogPrintFormat format) {
- switch (format) {
- case FORMAT_MODIFIER_COLOR:
- p_format->colored_output = true;
- return 0;
- case FORMAT_MODIFIER_TIME_USEC:
- p_format->usec_time_output = true;
- return 0;
- case FORMAT_MODIFIER_TIME_NSEC:
- p_format->nsec_time_output = true;
- return 0;
- case FORMAT_MODIFIER_PRINTABLE:
- p_format->printable_output = true;
- return 0;
- case FORMAT_MODIFIER_YEAR:
- p_format->year_output = true;
- return 0;
- case FORMAT_MODIFIER_ZONE:
- p_format->zone_output = !p_format->zone_output;
- return 0;
- case FORMAT_MODIFIER_EPOCH:
- p_format->epoch_output = true;
- return 0;
- case FORMAT_MODIFIER_MONOTONIC:
- p_format->monotonic_output = true;
- return 0;
- case FORMAT_MODIFIER_UID:
- p_format->uid_output = true;
- return 0;
- case FORMAT_MODIFIER_DESCRIPT:
- p_format->descriptive_output = true;
- descriptive_output = true;
- return 0;
- default:
- break;
- }
- p_format->format = format;
- return 1;
-}
-
-#ifndef __MINGW32__
-static const char tz[] = "TZ";
-static const char utc[] = "UTC";
-#endif
-
-/**
- * Returns FORMAT_OFF on invalid string
- */
-AndroidLogPrintFormat android_log_formatFromString(const char* formatString) {
- static AndroidLogPrintFormat format;
-
- /* clang-format off */
- if (!strcmp(formatString, "brief")) format = FORMAT_BRIEF;
- else if (!strcmp(formatString, "process")) format = FORMAT_PROCESS;
- else if (!strcmp(formatString, "tag")) format = FORMAT_TAG;
- else if (!strcmp(formatString, "thread")) format = FORMAT_THREAD;
- else if (!strcmp(formatString, "raw")) format = FORMAT_RAW;
- else if (!strcmp(formatString, "time")) format = FORMAT_TIME;
- else if (!strcmp(formatString, "threadtime")) format = FORMAT_THREADTIME;
- else if (!strcmp(formatString, "long")) format = FORMAT_LONG;
- else if (!strcmp(formatString, "color")) format = FORMAT_MODIFIER_COLOR;
- else if (!strcmp(formatString, "colour")) format = FORMAT_MODIFIER_COLOR;
- else if (!strcmp(formatString, "usec")) format = FORMAT_MODIFIER_TIME_USEC;
- else if (!strcmp(formatString, "nsec")) format = FORMAT_MODIFIER_TIME_NSEC;
- else if (!strcmp(formatString, "printable")) format = FORMAT_MODIFIER_PRINTABLE;
- else if (!strcmp(formatString, "year")) format = FORMAT_MODIFIER_YEAR;
- else if (!strcmp(formatString, "zone")) format = FORMAT_MODIFIER_ZONE;
- else if (!strcmp(formatString, "epoch")) format = FORMAT_MODIFIER_EPOCH;
- else if (!strcmp(formatString, "monotonic")) format = FORMAT_MODIFIER_MONOTONIC;
- else if (!strcmp(formatString, "uid")) format = FORMAT_MODIFIER_UID;
- else if (!strcmp(formatString, "descriptive")) format = FORMAT_MODIFIER_DESCRIPT;
- /* clang-format on */
-
-#ifndef __MINGW32__
- else {
- extern char* tzname[2];
- static const char gmt[] = "GMT";
- char* cp = getenv(tz);
- if (cp) {
- cp = strdup(cp);
- }
- setenv(tz, formatString, 1);
- /*
- * Run tzset here to determine if the timezone is legitimate. If the
- * zone is GMT, check if that is what was asked for, if not then
- * did not match any on the system; report an error to caller.
- */
- tzset();
- if (!tzname[0] ||
- ((!strcmp(tzname[0], utc) || !strcmp(tzname[0], gmt)) /* error? */
- && strcasecmp(formatString, utc) && strcasecmp(formatString, gmt))) { /* ok */
- if (cp) {
- setenv(tz, cp, 1);
- } else {
- unsetenv(tz);
- }
- tzset();
- format = FORMAT_OFF;
- } else {
- format = FORMAT_MODIFIER_ZONE;
- }
- free(cp);
- }
-#endif
-
- return format;
-}
-
-/**
- * filterExpression: a single filter expression
- * eg "AT:d"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- */
-
-int android_log_addFilterRule(AndroidLogFormat* p_format, const char* filterExpression) {
- size_t tagNameLength;
- android_LogPriority pri = ANDROID_LOG_DEFAULT;
-
- tagNameLength = strcspn(filterExpression, ":");
-
- if (tagNameLength == 0) {
- goto error;
- }
-
- if (filterExpression[tagNameLength] == ':') {
- pri = filterCharToPri(filterExpression[tagNameLength + 1]);
-
- if (pri == ANDROID_LOG_UNKNOWN) {
- goto error;
- }
- }
-
- if (0 == strncmp("*", filterExpression, tagNameLength)) {
- /*
- * This filter expression refers to the global filter
- * The default level for this is DEBUG if the priority
- * is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_DEBUG;
- }
-
- p_format->global_pri = pri;
- } else {
- /*
- * for filter expressions that don't refer to the global
- * filter, the default is verbose if the priority is unspecified
- */
- if (pri == ANDROID_LOG_DEFAULT) {
- pri = ANDROID_LOG_VERBOSE;
- }
-
- char* tagName;
-
-/*
- * Presently HAVE_STRNDUP is never defined, so the second case is always taken
- * Darwin doesn't have strndup, everything else does
- */
-#ifdef HAVE_STRNDUP
- tagName = strndup(filterExpression, tagNameLength);
-#else
- /* a few extra bytes copied... */
- tagName = strdup(filterExpression);
- tagName[tagNameLength] = '\0';
-#endif /*HAVE_STRNDUP*/
-
- FilterInfo* p_fi = filterinfo_new(tagName, pri);
- free(tagName);
-
- p_fi->p_next = p_format->filters;
- p_format->filters = p_fi;
- }
-
- return 0;
-error:
- return -1;
-}
-
-#ifndef HAVE_STRSEP
-/* KISS replacement helper for below */
-static char* strsep(char** stringp, const char* delim) {
- char* token;
- char* ret = *stringp;
-
- if (!ret || !*ret) {
- return NULL;
- }
- token = strpbrk(ret, delim);
- if (token) {
- *token = '\0';
- ++token;
- } else {
- token = ret + strlen(ret);
- }
- *stringp = token;
- return ret;
-}
-#endif
-
-/**
- * filterString: a comma/whitespace-separated set of filter expressions
- *
- * eg "AT:d *:i"
- *
- * returns 0 on success and -1 on invalid expression
- *
- * Assumes single threaded execution
- *
- */
-int android_log_addFilterString(AndroidLogFormat* p_format, const char* filterString) {
- char* filterStringCopy = strdup(filterString);
- char* p_cur = filterStringCopy;
- char* p_ret;
- int err;
-
- /* Yes, I'm using strsep */
- while (NULL != (p_ret = strsep(&p_cur, " \t,"))) {
- /* ignore whitespace-only entries */
- if (p_ret[0] != '\0') {
- err = android_log_addFilterRule(p_format, p_ret);
-
- if (err < 0) {
- goto error;
- }
- }
- }
-
- free(filterStringCopy);
- return 0;
-error:
- free(filterStringCopy);
- return -1;
-}
-
-/**
- * Splits a wire-format buffer into an AndroidLogEntry
- * entry allocated by caller. Pointers will point directly into buf
- *
- * Returns 0 on success and -1 on invalid wire format (entry will be
- * in unspecified state)
- */
-int android_log_processLogBuffer(struct logger_entry* buf, AndroidLogEntry* entry) {
- entry->message = NULL;
- entry->messageLen = 0;
-
- entry->tv_sec = buf->sec;
- entry->tv_nsec = buf->nsec;
- entry->uid = -1;
- entry->pid = buf->pid;
- entry->tid = buf->tid;
-
- /*
- * format: <priority:1><tag:N>\0<message:N>\0
- *
- * tag str
- * starts at buf + buf->hdr_size + 1
- * msg
- * starts at buf + buf->hdr_size + 1 + len(tag) + 1
- *
- * The message may have been truncated. When that happens, we must null-terminate the message
- * ourselves.
- */
- if (buf->len < 3) {
- /*
- * An well-formed entry must consist of at least a priority
- * and two null characters
- */
- fprintf(stderr, "+++ LOG: entry too small\n");
- return -1;
- }
-
- int msgStart = -1;
- int msgEnd = -1;
-
- int i;
- if (buf->hdr_size < sizeof(logger_entry)) {
- fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entry\n");
- return -1;
- }
- char* msg = reinterpret_cast<char*>(buf) + buf->hdr_size;
- entry->uid = buf->uid;
-
- for (i = 1; i < buf->len; i++) {
- if (msg[i] == '\0') {
- if (msgStart == -1) {
- msgStart = i + 1;
- } else {
- msgEnd = i;
- break;
- }
- }
- }
-
- if (msgStart == -1) {
- /* +++ LOG: malformed log message, DYB */
- for (i = 1; i < buf->len; i++) {
- /* odd characters in tag? */
- if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
- msg[i] = '\0';
- msgStart = i + 1;
- break;
- }
- }
- if (msgStart == -1) {
- msgStart = buf->len - 1; /* All tag, no message, print truncates */
- }
- }
- if (msgEnd == -1) {
- /* incoming message not null-terminated; force it */
- msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */
- msg[msgEnd] = '\0';
- }
-
- entry->priority = static_cast<android_LogPriority>(msg[0]);
- entry->tag = msg + 1;
- entry->tagLen = msgStart - 1;
- entry->message = msg + msgStart;
- entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);
-
- return 0;
-}
-
-static bool findChar(const char** cp, size_t* len, int c) {
- while ((*len) && isspace(*(*cp))) {
- ++(*cp);
- --(*len);
- }
- if (c == INT_MAX) return *len;
- if ((*len) && (*(*cp) == c)) {
- ++(*cp);
- --(*len);
- return true;
- }
- return false;
-}
-
-/*
- * Recursively convert binary log data to printable form.
- *
- * This needs to be recursive because you can have lists of lists.
- *
- * If we run out of room, we stop processing immediately. It's important
- * for us to check for space on every output element to avoid producing
- * garbled output.
- *
- * Returns 0 on success, 1 on buffer full, -1 on failure.
- */
-enum objectType {
- TYPE_OBJECTS = '1',
- TYPE_BYTES = '2',
- TYPE_MILLISECONDS = '3',
- TYPE_ALLOCATIONS = '4',
- TYPE_ID = '5',
- TYPE_PERCENT = '6',
- TYPE_MONOTONIC = 's'
-};
-
-static int android_log_printBinaryEvent(const unsigned char** pEventData, size_t* pEventDataLen,
- char** pOutBuf, size_t* pOutBufLen, const char** fmtStr,
- size_t* fmtLen) {
- const unsigned char* eventData = *pEventData;
- size_t eventDataLen = *pEventDataLen;
- char* outBuf = *pOutBuf;
- char* outBufSave = outBuf;
- size_t outBufLen = *pOutBufLen;
- size_t outBufLenSave = outBufLen;
- unsigned char type;
- size_t outCount = 0;
- int result = 0;
- const char* cp;
- size_t len;
- int64_t lval;
-
- if (eventDataLen < 1) return -1;
-
- type = *eventData;
-
- cp = NULL;
- len = 0;
- if (fmtStr && *fmtStr && fmtLen && *fmtLen && **fmtStr) {
- cp = *fmtStr;
- len = *fmtLen;
- }
- /*
- * event.logtag format specification:
- *
- * Optionally, after the tag names can be put a description for the value(s)
- * of the tag. Description are in the format
- * (<name>|data type[|data unit])
- * Multiple values are separated by commas.
- *
- * The data type is a number from the following values:
- * 1: int
- * 2: long
- * 3: string
- * 4: list
- * 5: float
- *
- * The data unit is a number taken from the following list:
- * 1: Number of objects
- * 2: Number of bytes
- * 3: Number of milliseconds
- * 4: Number of allocations
- * 5: Id
- * 6: Percent
- * s: Number of seconds (monotonic time)
- * Default value for data of type int/long is 2 (bytes).
- */
- if (!cp || !findChar(&cp, &len, '(')) {
- len = 0;
- } else {
- char* outBufLastSpace = NULL;
-
- findChar(&cp, &len, INT_MAX);
- while (len && *cp && (*cp != '|') && (*cp != ')')) {
- if (outBufLen <= 0) {
- /* halt output */
- goto no_room;
- }
- outBufLastSpace = isspace(*cp) ? outBuf : NULL;
- *outBuf = *cp;
- ++outBuf;
- ++cp;
- --outBufLen;
- --len;
- }
- if (outBufLastSpace) {
- outBufLen += outBuf - outBufLastSpace;
- outBuf = outBufLastSpace;
- }
- if (outBufLen <= 0) {
- /* halt output */
- goto no_room;
- }
- if (outBufSave != outBuf) {
- *outBuf = '=';
- ++outBuf;
- --outBufLen;
- }
-
- if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
- static const unsigned char typeTable[] = {EVENT_TYPE_INT, EVENT_TYPE_LONG, EVENT_TYPE_STRING,
- EVENT_TYPE_LIST, EVENT_TYPE_FLOAT};
-
- if ((*cp >= '1') && (*cp < (char)('1' + (sizeof(typeTable) / sizeof(typeTable[0])))) &&
- (type != typeTable[(size_t)(*cp - '1')]))
- len = 0;
-
- if (len) {
- ++cp;
- --len;
- } else {
- /* reset the format */
- outBuf = outBufSave;
- outBufLen = outBufLenSave;
- }
- }
- }
- outCount = 0;
- lval = 0;
- switch (type) {
- case EVENT_TYPE_INT:
- /* 32-bit signed int */
- {
- if (eventDataLen < sizeof(android_event_int_t)) return -1;
- auto* event_int = reinterpret_cast<const android_event_int_t*>(eventData);
- lval = event_int->data;
- eventData += sizeof(android_event_int_t);
- eventDataLen -= sizeof(android_event_int_t);
- }
- goto pr_lval;
- case EVENT_TYPE_LONG:
- /* 64-bit signed long */
- if (eventDataLen < sizeof(android_event_long_t)) {
- return -1;
- }
- {
- auto* event_long = reinterpret_cast<const android_event_long_t*>(eventData);
- lval = event_long->data;
- }
- eventData += sizeof(android_event_long_t);
- eventDataLen -= sizeof(android_event_long_t);
- pr_lval:
- outCount = snprintf(outBuf, outBufLen, "%" PRId64, lval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
- break;
- case EVENT_TYPE_FLOAT:
- /* float */
- {
- if (eventDataLen < sizeof(android_event_float_t)) return -1;
- auto* event_float = reinterpret_cast<const android_event_float_t*>(eventData);
- float fval = event_float->data;
- eventData += sizeof(android_event_int_t);
- eventDataLen -= sizeof(android_event_int_t);
-
- outCount = snprintf(outBuf, outBufLen, "%f", fval);
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else {
- /* halt output */
- goto no_room;
- }
- }
- break;
- case EVENT_TYPE_STRING:
- /* UTF-8 chars, not NULL-terminated */
- {
- if (eventDataLen < sizeof(android_event_string_t)) return -1;
- auto* event_string = reinterpret_cast<const android_event_string_t*>(eventData);
- unsigned int strLen = event_string->length;
- eventData += sizeof(android_event_string_t);
- eventDataLen -= sizeof(android_event_string_t);
-
- if (eventDataLen < strLen) {
- result = -1; /* mark truncated */
- strLen = eventDataLen;
- }
-
- if (cp && (strLen == 0)) {
- /* reset the format if no content */
- outBuf = outBufSave;
- outBufLen = outBufLenSave;
- }
- if (strLen < outBufLen) {
- memcpy(outBuf, eventData, strLen);
- outBuf += strLen;
- outBufLen -= strLen;
- } else {
- if (outBufLen > 0) {
- /* copy what we can */
- memcpy(outBuf, eventData, outBufLen);
- outBuf += outBufLen;
- outBufLen -= outBufLen;
- }
- if (!result) result = 1; /* if not truncated, return no room */
- }
- eventData += strLen;
- eventDataLen -= strLen;
- if (result != 0) goto bail;
- break;
- }
- case EVENT_TYPE_LIST:
- /* N items, all different types */
- {
- if (eventDataLen < sizeof(android_event_list_t)) return -1;
- auto* event_list = reinterpret_cast<const android_event_list_t*>(eventData);
-
- int8_t count = event_list->element_count;
- eventData += sizeof(android_event_list_t);
- eventDataLen -= sizeof(android_event_list_t);
-
- if (outBufLen <= 0) goto no_room;
-
- *outBuf++ = '[';
- outBufLen--;
-
- for (int i = 0; i < count; i++) {
- result = android_log_printBinaryEvent(&eventData, &eventDataLen, &outBuf, &outBufLen,
- fmtStr, fmtLen);
- if (result != 0) goto bail;
-
- if (i < (count - 1)) {
- if (outBufLen <= 0) goto no_room;
- *outBuf++ = ',';
- outBufLen--;
- }
- }
-
- if (outBufLen <= 0) goto no_room;
-
- *outBuf++ = ']';
- outBufLen--;
- }
- break;
- default:
- fprintf(stderr, "Unknown binary event type %d\n", type);
- return -1;
- }
- if (cp && len) {
- if (findChar(&cp, &len, '|') && findChar(&cp, &len, INT_MAX)) {
- switch (*cp) {
- case TYPE_OBJECTS:
- outCount = 0;
- /* outCount = snprintf(outBuf, outBufLen, " objects"); */
- break;
- case TYPE_BYTES:
- if ((lval != 0) && ((lval % 1024) == 0)) {
- /* repaint with multiplier */
- static const char suffixTable[] = {'K', 'M', 'G', 'T'};
- size_t idx = 0;
- outBuf -= outCount;
- outBufLen += outCount;
- do {
- lval /= 1024;
- if ((lval % 1024) != 0) break;
- } while (++idx < ((sizeof(suffixTable) / sizeof(suffixTable[0])) - 1));
- outCount = snprintf(outBuf, outBufLen, "%" PRId64 "%cB", lval, suffixTable[idx]);
- } else {
- outCount = snprintf(outBuf, outBufLen, "B");
- }
- break;
- case TYPE_MILLISECONDS:
- if (((lval <= -1000) || (1000 <= lval)) && (outBufLen || (outBuf[-1] == '0'))) {
- /* repaint as (fractional) seconds, possibly saving space */
- if (outBufLen) outBuf[0] = outBuf[-1];
- outBuf[-1] = outBuf[-2];
- outBuf[-2] = outBuf[-3];
- outBuf[-3] = '.';
- while ((outBufLen == 0) || (*outBuf == '0')) {
- --outBuf;
- ++outBufLen;
- }
- if (*outBuf != '.') {
- ++outBuf;
- --outBufLen;
- }
- outCount = snprintf(outBuf, outBufLen, "s");
- } else {
- outCount = snprintf(outBuf, outBufLen, "ms");
- }
- break;
- case TYPE_MONOTONIC: {
- static const uint64_t minute = 60;
- static const uint64_t hour = 60 * minute;
- static const uint64_t day = 24 * hour;
-
- /* Repaint as unsigned seconds, minutes, hours ... */
- outBuf -= outCount;
- outBufLen += outCount;
- uint64_t val = lval;
- if (val >= day) {
- outCount = snprintf(outBuf, outBufLen, "%" PRIu64 "d ", val / day);
- if (outCount >= outBufLen) break;
- outBuf += outCount;
- outBufLen -= outCount;
- val = (val % day) + day;
- }
- if (val >= minute) {
- if (val >= hour) {
- outCount = snprintf(outBuf, outBufLen, "%" PRIu64 ":", (val / hour) % (day / hour));
- if (outCount >= outBufLen) break;
- outBuf += outCount;
- outBufLen -= outCount;
- }
- outCount =
- snprintf(outBuf, outBufLen, (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
- (val / minute) % (hour / minute));
- if (outCount >= outBufLen) break;
- outBuf += outCount;
- outBufLen -= outCount;
- }
- outCount = snprintf(outBuf, outBufLen, (val >= minute) ? "%02" PRIu64 : "%" PRIu64 "s",
- val % minute);
- } break;
- case TYPE_ALLOCATIONS:
- outCount = 0;
- /* outCount = snprintf(outBuf, outBufLen, " allocations"); */
- break;
- case TYPE_ID:
- outCount = 0;
- break;
- case TYPE_PERCENT:
- outCount = snprintf(outBuf, outBufLen, "%%");
- break;
- default: /* ? */
- outCount = 0;
- break;
- }
- ++cp;
- --len;
- if (outCount < outBufLen) {
- outBuf += outCount;
- outBufLen -= outCount;
- } else if (outCount) {
- /* halt output */
- goto no_room;
- }
- }
- if (!findChar(&cp, &len, ')')) len = 0;
- if (!findChar(&cp, &len, ',')) len = 0;
- }
-
-bail:
- *pEventData = eventData;
- *pEventDataLen = eventDataLen;
- *pOutBuf = outBuf;
- *pOutBufLen = outBufLen;
- if (cp) {
- *fmtStr = cp;
- *fmtLen = len;
- }
- return result;
-
-no_room:
- result = 1;
- goto bail;
-}
-
-/**
- * Convert a binary log entry to ASCII form.
- *
- * For convenience we mimic the processLogBuffer API. There is no
- * pre-defined output length for the binary data, since we're free to format
- * it however we choose, which means we can't really use a fixed-size buffer
- * here.
- */
-int android_log_processBinaryLogBuffer(
- struct logger_entry* buf, AndroidLogEntry* entry,
- [[maybe_unused]] const EventTagMap* map, /* only on !__ANDROID__ */
- char* messageBuf, int messageBufLen) {
- size_t inCount;
- uint32_t tagIndex;
- const unsigned char* eventData;
-
- entry->message = NULL;
- entry->messageLen = 0;
-
- entry->tv_sec = buf->sec;
- entry->tv_nsec = buf->nsec;
- entry->priority = ANDROID_LOG_INFO;
- entry->uid = -1;
- entry->pid = buf->pid;
- entry->tid = buf->tid;
-
- if (buf->hdr_size < sizeof(logger_entry)) {
- fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entry\n");
- return -1;
- }
- eventData = reinterpret_cast<unsigned char*>(buf) + buf->hdr_size;
- if (buf->lid == LOG_ID_SECURITY) {
- entry->priority = ANDROID_LOG_WARN;
- }
- entry->uid = buf->uid;
- inCount = buf->len;
- if (inCount < sizeof(android_event_header_t)) return -1;
- auto* event_header = reinterpret_cast<const android_event_header_t*>(eventData);
- tagIndex = event_header->tag;
- eventData += sizeof(android_event_header_t);
- inCount -= sizeof(android_event_header_t);
-
- entry->tagLen = 0;
- entry->tag = NULL;
-#ifdef __ANDROID__
- if (map != NULL) {
- entry->tag = android_lookupEventTag_len(map, &entry->tagLen, tagIndex);
- }
-#endif
-
- /*
- * If we don't have a map, or didn't find the tag number in the map,
- * stuff a generated tag value into the start of the output buffer and
- * shift the buffer pointers down.
- */
- if (entry->tag == NULL) {
- size_t tagLen;
-
- tagLen = snprintf(messageBuf, messageBufLen, "[%" PRIu32 "]", tagIndex);
- if (tagLen >= (size_t)messageBufLen) {
- tagLen = messageBufLen - 1;
- }
- entry->tag = messageBuf;
- entry->tagLen = tagLen;
- messageBuf += tagLen + 1;
- messageBufLen -= tagLen + 1;
- }
-
- /*
- * Format the event log data into the buffer.
- */
- const char* fmtStr = NULL;
- size_t fmtLen = 0;
-#ifdef __ANDROID__
- if (descriptive_output && map) {
- fmtStr = android_lookupEventFormat_len(map, &fmtLen, tagIndex);
- }
-#endif
-
- char* outBuf = messageBuf;
- size_t outRemaining = messageBufLen - 1; /* leave one for nul byte */
- int result = 0;
-
- if ((inCount > 0) || fmtLen) {
- result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf, &outRemaining, &fmtStr,
- &fmtLen);
- }
- if ((result == 1) && fmtStr) {
- /* We overflowed :-(, let's repaint the line w/o format dressings */
- eventData = reinterpret_cast<unsigned char*>(buf) + buf->hdr_size;
- eventData += 4;
- outBuf = messageBuf;
- outRemaining = messageBufLen - 1;
- result = android_log_printBinaryEvent(&eventData, &inCount, &outBuf, &outRemaining, NULL, NULL);
- }
- if (result < 0) {
- fprintf(stderr, "Binary log entry conversion failed\n");
- }
- if (result) {
- if (!outRemaining) {
- /* make space to leave an indicator */
- --outBuf;
- ++outRemaining;
- }
- *outBuf++ = (result < 0) ? '!' : '^'; /* Error or Truncation? */
- outRemaining--;
- /* pretend we ate all the data to prevent log stutter */
- inCount = 0;
- if (result > 0) result = 0;
- }
-
- /* eat the silly terminating '\n' */
- if (inCount == 1 && *eventData == '\n') {
- eventData++;
- inCount--;
- }
-
- if (inCount != 0) {
- fprintf(stderr, "Warning: leftover binary log data (%zu bytes)\n", inCount);
- }
-
- /*
- * Terminate the buffer. The NUL byte does not count as part of
- * entry->messageLen.
- */
- *outBuf = '\0';
- entry->messageLen = outBuf - messageBuf;
- assert(entry->messageLen == (messageBufLen - 1) - outRemaining);
-
- entry->message = messageBuf;
-
- return result;
-}
-
-/*
- * Convert to printable from message to p buffer, return string length. If p is
- * NULL, do not copy, but still return the expected string length.
- */
-size_t convertPrintable(char* p, const char* message, size_t messageLen) {
- char* begin = p;
- bool print = p != NULL;
- mbstate_t mb_state = {};
-
- while (messageLen) {
- char buf[6];
- ssize_t len = sizeof(buf) - 1;
- if ((size_t)len > messageLen) {
- len = messageLen;
- }
- len = mbrtowc(nullptr, message, len, &mb_state);
-
- if (len < 0) {
- snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(*message));
- len = 1;
- } else {
- buf[0] = '\0';
- if (len == 1) {
- if (*message == '\a') {
- strcpy(buf, "\\a");
- } else if (*message == '\b') {
- strcpy(buf, "\\b");
- } else if (*message == '\t') {
- strcpy(buf, "\t"); /* Do not escape tabs */
- } else if (*message == '\v') {
- strcpy(buf, "\\v");
- } else if (*message == '\f') {
- strcpy(buf, "\\f");
- } else if (*message == '\r') {
- strcpy(buf, "\\r");
- } else if (*message == '\\') {
- strcpy(buf, "\\\\");
- } else if ((*message < ' ') || (*message & 0x80)) {
- snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(*message));
- }
- }
- if (!buf[0]) {
- strncpy(buf, message, len);
- buf[len] = '\0';
- }
- }
- if (print) {
- strcpy(p, buf);
- }
- p += strlen(buf);
- message += len;
- messageLen -= len;
- }
- return p - begin;
-}
-
-#ifdef __ANDROID__
-static char* readSeconds(char* e, struct timespec* t) {
- unsigned long multiplier;
- char* p;
- t->tv_sec = strtoul(e, &p, 10);
- if (*p != '.') {
- return NULL;
- }
- t->tv_nsec = 0;
- multiplier = NS_PER_SEC;
- while (isdigit(*++p) && (multiplier /= 10)) {
- t->tv_nsec += (*p - '0') * multiplier;
- }
- return p;
-}
-
-static struct timespec* sumTimespec(struct timespec* left, struct timespec* right) {
- left->tv_nsec += right->tv_nsec;
- left->tv_sec += right->tv_sec;
- if (left->tv_nsec >= (long)NS_PER_SEC) {
- left->tv_nsec -= NS_PER_SEC;
- left->tv_sec += 1;
- }
- return left;
-}
-
-static struct timespec* subTimespec(struct timespec* result, struct timespec* left,
- struct timespec* right) {
- result->tv_nsec = left->tv_nsec - right->tv_nsec;
- result->tv_sec = left->tv_sec - right->tv_sec;
- if (result->tv_nsec < 0) {
- result->tv_nsec += NS_PER_SEC;
- result->tv_sec -= 1;
- }
- return result;
-}
-
-static long long nsecTimespec(struct timespec* now) {
- return (long long)now->tv_sec * NS_PER_SEC + now->tv_nsec;
-}
-
-static void convertMonotonic(struct timespec* result, const AndroidLogEntry* entry) {
- struct listnode* node;
- struct conversionList {
- struct listnode node; /* first */
- struct timespec time;
- struct timespec convert;
- } * list, *next;
- struct timespec time, convert;
-
- /* If we do not have a conversion list, build one up */
- if (list_empty(&convertHead)) {
- bool suspended_pending = false;
- struct timespec suspended_monotonic = {0, 0};
- struct timespec suspended_diff = {0, 0};
-
- /*
- * Read dmesg for _some_ synchronization markers and insert
- * Anything in the Android Logger before the dmesg logging span will
- * be highly suspect regarding the monotonic time calculations.
- */
- FILE* p = popen("/system/bin/dmesg", "re");
- if (p) {
- char* line = NULL;
- size_t len = 0;
- while (getline(&line, &len, p) > 0) {
- static const char suspend[] = "PM: suspend entry ";
- static const char resume[] = "PM: suspend exit ";
- static const char healthd[] = "healthd";
- static const char battery[] = ": battery ";
- static const char suspended[] = "Suspended for ";
- struct timespec monotonic;
- struct tm tm;
- char *cp, *e = line;
- bool add_entry = true;
-
- if (*e == '<') {
- while (*e && (*e != '>')) {
- ++e;
- }
- if (*e != '>') {
- continue;
- }
- }
- if (*e != '[') {
- continue;
- }
- while (*++e == ' ') {
- ;
- }
- e = readSeconds(e, &monotonic);
- if (!e || (*e != ']')) {
- continue;
- }
-
- if ((e = strstr(e, suspend))) {
- e += sizeof(suspend) - 1;
- } else if ((e = strstr(line, resume))) {
- e += sizeof(resume) - 1;
- } else if (((e = strstr(line, healthd))) &&
- ((e = strstr(e + sizeof(healthd) - 1, battery)))) {
- /* NB: healthd is roughly 150us late, worth the price to
- * deal with ntp-induced or hardware clock drift. */
- e += sizeof(battery) - 1;
- } else if ((e = strstr(line, suspended))) {
- e += sizeof(suspended) - 1;
- e = readSeconds(e, &time);
- if (!e) {
- continue;
- }
- add_entry = false;
- suspended_pending = true;
- suspended_monotonic = monotonic;
- suspended_diff = time;
- } else {
- continue;
- }
- if (add_entry) {
- /* look for "????-??-?? ??:??:??.????????? UTC" */
- cp = strstr(e, " UTC");
- if (!cp || ((cp - e) < 29) || (cp[-10] != '.')) {
- continue;
- }
- e = cp - 29;
- cp = readSeconds(cp - 10, &time);
- if (!cp) {
- continue;
- }
- cp = strptime(e, "%Y-%m-%d %H:%M:%S.", &tm);
- if (!cp) {
- continue;
- }
- cp = getenv(tz);
- if (cp) {
- cp = strdup(cp);
- }
- setenv(tz, utc, 1);
- time.tv_sec = mktime(&tm);
- if (cp) {
- setenv(tz, cp, 1);
- free(cp);
- } else {
- unsetenv(tz);
- }
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- subTimespec(&list->convert, &time, &monotonic);
- list_add_tail(&convertHead, &list->node);
- }
- if (suspended_pending && !list_empty(&convertHead)) {
- list = node_to_item(list_tail(&convertHead), struct conversionList, node);
- if (subTimespec(&time, subTimespec(&time, &list->time, &list->convert),
- &suspended_monotonic)
- ->tv_sec > 0) {
- /* resume, what is convert factor before? */
- subTimespec(&convert, &list->convert, &suspended_diff);
- } else {
- /* suspend */
- convert = list->convert;
- }
- time = suspended_monotonic;
- sumTimespec(&time, &convert);
- /* breakpoint just before sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- list->convert = convert;
- list_add_tail(&convertHead, &list->node);
- /* breakpoint just after sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- sumTimespec(&list->time, &suspended_diff);
- list->convert = convert;
- sumTimespec(&list->convert, &suspended_diff);
- list_add_tail(&convertHead, &list->node);
- suspended_pending = false;
- }
- }
- pclose(p);
- }
- /* last entry is our current time conversion */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- clock_gettime(CLOCK_REALTIME, &list->time);
- clock_gettime(CLOCK_MONOTONIC, &convert);
- clock_gettime(CLOCK_MONOTONIC, &time);
- /* Correct for instant clock_gettime latency (syscall or ~30ns) */
- subTimespec(&time, &convert, subTimespec(&time, &time, &convert));
- /* Calculate conversion factor */
- subTimespec(&list->convert, &list->time, &time);
- list_add_tail(&convertHead, &list->node);
- if (suspended_pending) {
- /* manufacture a suspend @ point before */
- subTimespec(&convert, &list->convert, &suspended_diff);
- time = suspended_monotonic;
- sumTimespec(&time, &convert);
- /* breakpoint just after sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- sumTimespec(&list->time, &suspended_diff);
- list->convert = convert;
- sumTimespec(&list->convert, &suspended_diff);
- list_add_head(&convertHead, &list->node);
- /* breakpoint just before sleep */
- list = static_cast<conversionList*>(calloc(1, sizeof(conversionList)));
- list_init(&list->node);
- list->time = time;
- list->convert = convert;
- list_add_head(&convertHead, &list->node);
- }
- }
-
- /* Find the breakpoint in the conversion list */
- list = node_to_item(list_head(&convertHead), struct conversionList, node);
- next = NULL;
- list_for_each(node, &convertHead) {
- next = node_to_item(node, struct conversionList, node);
- if (entry->tv_sec < next->time.tv_sec) {
- break;
- } else if (entry->tv_sec == next->time.tv_sec) {
- if (entry->tv_nsec < next->time.tv_nsec) {
- break;
- }
- }
- list = next;
- }
-
- /* blend time from one breakpoint to the next */
- convert = list->convert;
- if (next) {
- unsigned long long total, run;
-
- total = nsecTimespec(subTimespec(&time, &next->time, &list->time));
- time.tv_sec = entry->tv_sec;
- time.tv_nsec = entry->tv_nsec;
- run = nsecTimespec(subTimespec(&time, &time, &list->time));
- if (run < total) {
- long long crun;
-
- float f = nsecTimespec(subTimespec(&time, &next->convert, &convert));
- f *= run;
- f /= total;
- crun = f;
- convert.tv_sec += crun / (long long)NS_PER_SEC;
- if (crun < 0) {
- convert.tv_nsec -= (-crun) % NS_PER_SEC;
- if (convert.tv_nsec < 0) {
- convert.tv_nsec += NS_PER_SEC;
- convert.tv_sec -= 1;
- }
- } else {
- convert.tv_nsec += crun % NS_PER_SEC;
- if (convert.tv_nsec >= (long)NS_PER_SEC) {
- convert.tv_nsec -= NS_PER_SEC;
- convert.tv_sec += 1;
- }
- }
- }
- }
-
- /* Apply the correction factor */
- result->tv_sec = entry->tv_sec;
- result->tv_nsec = entry->tv_nsec;
- subTimespec(result, result, &convert);
-}
-#endif
-
-/**
- * Formats a log message into a buffer
- *
- * Uses defaultBuffer if it can, otherwise malloc()'s a new buffer
- * If return value != defaultBuffer, caller must call free()
- * Returns NULL on malloc error
- */
-
-char* android_log_formatLogLine(AndroidLogFormat* p_format, char* defaultBuffer,
- size_t defaultBufferSize, const AndroidLogEntry* entry,
- size_t* p_outLength) {
-#if !defined(_WIN32)
- struct tm tmBuf;
-#endif
- struct tm* ptm;
- /* good margin, 23+nul for msec, 26+nul for usec, 29+nul to nsec */
- char timeBuf[64];
- char prefixBuf[128], suffixBuf[128];
- char priChar;
- int prefixSuffixIsHeaderFooter = 0;
- char* ret;
- time_t now;
- unsigned long nsec;
-
- priChar = filterPriToChar(entry->priority);
- size_t prefixLen = 0, suffixLen = 0;
- size_t len;
-
- /*
- * Get the current date/time in pretty form
- *
- * It's often useful when examining a log with "less" to jump to
- * a specific point in the file by searching for the date/time stamp.
- * For this reason it's very annoying to have regexp meta characters
- * in the time stamp. Don't use forward slashes, parenthesis,
- * brackets, asterisks, or other special chars here.
- *
- * The caller may have affected the timezone environment, this is
- * expected to be sensitive to that.
- */
- now = entry->tv_sec;
- nsec = entry->tv_nsec;
-#if __ANDROID__
- if (p_format->monotonic_output) {
- struct timespec time;
- convertMonotonic(&time, entry);
- now = time.tv_sec;
- nsec = time.tv_nsec;
- }
-#endif
- if (now < 0) {
- nsec = NS_PER_SEC - nsec;
- }
- if (p_format->epoch_output || p_format->monotonic_output) {
- ptm = NULL;
- snprintf(timeBuf, sizeof(timeBuf), p_format->monotonic_output ? "%6lld" : "%19lld",
- (long long)now);
- } else {
-#if !defined(_WIN32)
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&now);
-#endif
- strftime(timeBuf, sizeof(timeBuf), &"%Y-%m-%d %H:%M:%S"[p_format->year_output ? 0 : 3], ptm);
- }
- len = strlen(timeBuf);
- if (p_format->nsec_time_output) {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%09ld", nsec);
- } else if (p_format->usec_time_output) {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%06ld", nsec / US_PER_NSEC);
- } else {
- len += snprintf(timeBuf + len, sizeof(timeBuf) - len, ".%03ld", nsec / MS_PER_NSEC);
- }
- if (p_format->zone_output && ptm) {
- strftime(timeBuf + len, sizeof(timeBuf) - len, " %z", ptm);
- }
-
- /*
- * Construct a buffer containing the log header and log message.
- */
- if (p_format->colored_output) {
- prefixLen =
- snprintf(prefixBuf, sizeof(prefixBuf), "\x1B[%dm", colorFromPri(entry->priority));
- prefixLen = MIN(prefixLen, sizeof(prefixBuf));
-
- const char suffixContents[] = "\x1B[0m";
- strcpy(suffixBuf, suffixContents);
- suffixLen = strlen(suffixContents);
- }
-
- char uid[16];
- uid[0] = '\0';
- if (p_format->uid_output) {
- if (entry->uid >= 0) {
-/*
- * This code is Android specific, bionic guarantees that
- * calls to non-reentrant getpwuid() are thread safe.
- */
-#ifdef __ANDROID__
- struct passwd* pwd = getpwuid(entry->uid);
- if (pwd && (strlen(pwd->pw_name) <= 5)) {
- snprintf(uid, sizeof(uid), "%5s:", pwd->pw_name);
- } else
-#endif
- {
- /* Not worth parsing package list, names all longer than 5 */
- snprintf(uid, sizeof(uid), "%5d:", entry->uid);
- }
- } else {
- snprintf(uid, sizeof(uid), " ");
- }
- }
-
- switch (p_format->format) {
- case FORMAT_TAG:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c/%-8.*s: ", priChar,
- (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_PROCESS:
- len = snprintf(suffixBuf + suffixLen, sizeof(suffixBuf) - suffixLen, " (%.*s)\n",
- (int)entry->tagLen, entry->tag);
- suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%s%5d) ", priChar,
- uid, entry->pid);
- break;
- case FORMAT_THREAD:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen, "%c(%s%5d:%5d) ",
- priChar, uid, entry->pid, entry->tid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_RAW:
- prefixBuf[prefixLen] = 0;
- len = 0;
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_TIME:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s %c/%-8.*s(%s%5d): ", timeBuf, priChar, (int)entry->tagLen, entry->tag, uid,
- entry->pid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_THREADTIME:
- ret = strchr(uid, ':');
- if (ret) {
- *ret = ' ';
- }
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%s %s%5d %5d %c %-8.*s: ", timeBuf, uid, entry->pid, entry->tid, priChar,
- (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- case FORMAT_LONG:
- len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "[ %s %s%5d:%5d %c/%-8.*s ]\n", timeBuf, uid, entry->pid, entry->tid, priChar,
- (int)entry->tagLen, entry->tag);
- strcpy(suffixBuf + suffixLen, "\n\n");
- suffixLen += 2;
- prefixSuffixIsHeaderFooter = 1;
- break;
- case FORMAT_BRIEF:
- default:
- len =
- snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
- "%c/%-8.*s(%s%5d): ", priChar, (int)entry->tagLen, entry->tag, uid, entry->pid);
- strcpy(suffixBuf + suffixLen, "\n");
- ++suffixLen;
- break;
- }
-
- /* snprintf has a weird return value. It returns what would have been
- * written given a large enough buffer. In the case that the prefix is
- * longer then our buffer(128), it messes up the calculations below
- * possibly causing heap corruption. To avoid this we double check and
- * set the length at the maximum (size minus null byte)
- */
- prefixLen += len;
- if (prefixLen >= sizeof(prefixBuf)) {
- prefixLen = sizeof(prefixBuf) - 1;
- prefixBuf[sizeof(prefixBuf) - 1] = '\0';
- }
- if (suffixLen >= sizeof(suffixBuf)) {
- suffixLen = sizeof(suffixBuf) - 1;
- suffixBuf[sizeof(suffixBuf) - 2] = '\n';
- suffixBuf[sizeof(suffixBuf) - 1] = '\0';
- }
-
- /* the following code is tragically unreadable */
-
- size_t numLines;
- char* p;
- size_t bufferSize;
- const char* pm;
-
- if (prefixSuffixIsHeaderFooter) {
- /* we're just wrapping message with a header/footer */
- numLines = 1;
- } else {
- pm = entry->message;
- numLines = 0;
-
- /*
- * The line-end finding here must match the line-end finding
- * in for ( ... numLines...) loop below
- */
- while (pm < (entry->message + entry->messageLen)) {
- if (*pm++ == '\n') numLines++;
- }
- /* plus one line for anything not newline-terminated at the end */
- if (pm > entry->message && *(pm - 1) != '\n') numLines++;
- }
-
- /*
- * this is an upper bound--newlines in message may be counted
- * extraneously
- */
- bufferSize = (numLines * (prefixLen + suffixLen)) + 1;
- if (p_format->printable_output) {
- /* Calculate extra length to convert non-printable to printable */
- bufferSize += convertPrintable(NULL, entry->message, entry->messageLen);
- } else {
- bufferSize += entry->messageLen;
- }
-
- if (defaultBufferSize >= bufferSize) {
- ret = defaultBuffer;
- } else {
- ret = (char*)malloc(bufferSize);
-
- if (ret == NULL) {
- return ret;
- }
- }
-
- ret[0] = '\0'; /* to start strcat off */
-
- p = ret;
- pm = entry->message;
-
- if (prefixSuffixIsHeaderFooter) {
- strcat(p, prefixBuf);
- p += prefixLen;
- if (p_format->printable_output) {
- p += convertPrintable(p, entry->message, entry->messageLen);
- } else {
- strncat(p, entry->message, entry->messageLen);
- p += entry->messageLen;
- }
- strcat(p, suffixBuf);
- p += suffixLen;
- } else {
- do {
- const char* lineStart;
- size_t lineLen;
- lineStart = pm;
-
- /* Find the next end-of-line in message */
- while (pm < (entry->message + entry->messageLen) && *pm != '\n') pm++;
- lineLen = pm - lineStart;
-
- strcat(p, prefixBuf);
- p += prefixLen;
- if (p_format->printable_output) {
- p += convertPrintable(p, lineStart, lineLen);
- } else {
- strncat(p, lineStart, lineLen);
- p += lineLen;
- }
- strcat(p, suffixBuf);
- p += suffixLen;
-
- if (*pm == '\n') pm++;
- } while (pm < (entry->message + entry->messageLen));
- }
-
- if (p_outLength != NULL) {
- *p_outLength = p - ret;
- }
-
- return ret;
-}
-
-/**
- * Either print or do not print log line, based on filter
- *
- * Returns count bytes written
- */
-
-int android_log_printLogLine(AndroidLogFormat* p_format, int fd, const AndroidLogEntry* entry) {
- int ret;
- char defaultBuffer[512];
- char* outBuffer = NULL;
- size_t totalLen;
-
- outBuffer =
- android_log_formatLogLine(p_format, defaultBuffer, sizeof(defaultBuffer), entry, &totalLen);
-
- if (!outBuffer) return -1;
-
- do {
- ret = write(fd, outBuffer, totalLen);
- } while (ret < 0 && errno == EINTR);
-
- if (ret < 0) {
- fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
- ret = 0;
- goto done;
- }
-
- if (((size_t)ret) < totalLen) {
- fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret, (int)totalLen);
- goto done;
- }
-
-done:
- if (outBuffer != defaultBuffer) {
- free(outBuffer);
- }
-
- return ret;
-}
diff --git a/liblog/pmsg_reader.cpp b/liblog/pmsg_reader.cpp
deleted file mode 100644
index 5640900..0000000
--- a/liblog/pmsg_reader.cpp
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- * Copyright (C) 2007-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "pmsg_reader.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <cutils/list.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-
-int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg) {
- ssize_t ret;
- off_t current, next;
- struct __attribute__((__packed__)) {
- android_pmsg_log_header_t p;
- android_log_header_t l;
- uint8_t prio;
- } buf;
- static uint8_t preread_count;
-
- memset(log_msg, 0, sizeof(*log_msg));
-
- if (atomic_load(&logger_list->fd) <= 0) {
- int i, fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
-
- if (fd < 0) {
- return -errno;
- }
- if (fd == 0) { /* Argggg */
- fd = open("/sys/fs/pstore/pmsg-ramoops-0", O_RDONLY | O_CLOEXEC);
- close(0);
- if (fd < 0) {
- return -errno;
- }
- }
- i = atomic_exchange(&logger_list->fd, fd);
- if ((i > 0) && (i != fd)) {
- close(i);
- }
- preread_count = 0;
- }
-
- while (1) {
- int fd;
-
- if (preread_count < sizeof(buf)) {
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- ret = TEMP_FAILURE_RETRY(read(fd, &buf.p.magic + preread_count, sizeof(buf) - preread_count));
- if (ret < 0) {
- return -errno;
- }
- preread_count += ret;
- }
- if (preread_count != sizeof(buf)) {
- return preread_count ? -EIO : -EAGAIN;
- }
- if ((buf.p.magic != LOGGER_MAGIC) || (buf.p.len <= sizeof(buf)) ||
- (buf.p.len > (sizeof(buf) + LOGGER_ENTRY_MAX_PAYLOAD)) || (buf.l.id >= LOG_ID_MAX) ||
- (buf.l.realtime.tv_nsec >= NS_PER_SEC) ||
- ((buf.l.id != LOG_ID_EVENTS) && (buf.l.id != LOG_ID_SECURITY) &&
- ((buf.prio == ANDROID_LOG_UNKNOWN) || (buf.prio == ANDROID_LOG_DEFAULT) ||
- (buf.prio >= ANDROID_LOG_SILENT)))) {
- do {
- memmove(&buf.p.magic, &buf.p.magic + 1, --preread_count);
- } while (preread_count && (buf.p.magic != LOGGER_MAGIC));
- continue;
- }
- preread_count = 0;
-
- if ((logger_list->log_mask & (1 << buf.l.id)) &&
- ((!logger_list->start.tv_sec && !logger_list->start.tv_nsec) ||
- ((logger_list->start.tv_sec <= buf.l.realtime.tv_sec) &&
- ((logger_list->start.tv_sec != buf.l.realtime.tv_sec) ||
- (logger_list->start.tv_nsec <= buf.l.realtime.tv_nsec)))) &&
- (!logger_list->pid || (logger_list->pid == buf.p.pid))) {
- char* msg = reinterpret_cast<char*>(&log_msg->entry) + sizeof(log_msg->entry);
- *msg = buf.prio;
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- ret = TEMP_FAILURE_RETRY(read(fd, msg + sizeof(buf.prio), buf.p.len - sizeof(buf)));
- if (ret < 0) {
- return -errno;
- }
- if (ret != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
-
- log_msg->entry.len = buf.p.len - sizeof(buf) + sizeof(buf.prio);
- log_msg->entry.hdr_size = sizeof(log_msg->entry);
- log_msg->entry.pid = buf.p.pid;
- log_msg->entry.tid = buf.l.tid;
- log_msg->entry.sec = buf.l.realtime.tv_sec;
- log_msg->entry.nsec = buf.l.realtime.tv_nsec;
- log_msg->entry.lid = buf.l.id;
- log_msg->entry.uid = buf.p.uid;
-
- return ret + sizeof(buf.prio) + log_msg->entry.hdr_size;
- }
-
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- current = TEMP_FAILURE_RETRY(lseek(fd, (off_t)0, SEEK_CUR));
- if (current < 0) {
- return -errno;
- }
- fd = atomic_load(&logger_list->fd);
- if (fd <= 0) {
- return -EBADF;
- }
- next = TEMP_FAILURE_RETRY(lseek(fd, (off_t)(buf.p.len - sizeof(buf)), SEEK_CUR));
- if (next < 0) {
- return -errno;
- }
- if ((next - current) != (ssize_t)(buf.p.len - sizeof(buf))) {
- return -EIO;
- }
- }
-}
-
-void PmsgClose(struct logger_list* logger_list) {
- int fd = atomic_exchange(&logger_list->fd, 0);
- if (fd > 0) {
- close(fd);
- }
-}
-
-static void* realloc_or_free(void* ptr, size_t new_size) {
- void* result = realloc(ptr, new_size);
- if (!result) {
- free(ptr);
- }
- return result;
-}
-
-ssize_t __android_log_pmsg_file_read(log_id_t logId, char prio, const char* prefix,
- __android_log_pmsg_file_read_fn fn, void* arg) {
- ssize_t ret;
- struct logger_list logger_list;
- struct content {
- struct listnode node;
- struct logger_entry entry;
- } * content;
- struct names {
- struct listnode node;
- struct listnode content;
- log_id_t id;
- char prio;
- char name[];
- } * names;
- struct listnode name_list;
- struct listnode *node, *n;
- size_t len, prefix_len;
-
- if (!fn) {
- return -EINVAL;
- }
-
- /* Add just enough clues in logger_list and transp to make API function */
- memset(&logger_list, 0, sizeof(logger_list));
-
- logger_list.mode = ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
- logger_list.log_mask = (unsigned)-1;
- if (logId != LOG_ID_ANY) {
- logger_list.log_mask = (1 << logId);
- }
- logger_list.log_mask &= ~((1 << LOG_ID_KERNEL) | (1 << LOG_ID_EVENTS) | (1 << LOG_ID_SECURITY));
- if (!logger_list.log_mask) {
- return -EINVAL;
- }
-
- /* Initialize name list */
- list_init(&name_list);
-
- ret = SSIZE_MAX;
-
- /* Validate incoming prefix, shift until it contains only 0 or 1 : or / */
- prefix_len = 0;
- if (prefix) {
- const char *prev = NULL, *last = NULL, *cp = prefix;
- while ((cp = strpbrk(cp, "/:"))) {
- prev = last;
- last = cp;
- cp = cp + 1;
- }
- if (prev) {
- prefix = prev + 1;
- }
- prefix_len = strlen(prefix);
- }
-
- /* Read the file content */
- log_msg log_msg;
- while (PmsgRead(&logger_list, &log_msg) > 0) {
- const char* cp;
- size_t hdr_size = log_msg.entry.hdr_size;
-
- char* msg = (char*)&log_msg + hdr_size;
- const char* split = NULL;
-
- if (hdr_size != sizeof(log_msg.entry)) {
- continue;
- }
- /* Check for invalid sequence number */
- if (log_msg.entry.nsec % ANDROID_LOG_PMSG_FILE_SEQUENCE ||
- (log_msg.entry.nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >=
- ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
- continue;
- }
-
- /* Determine if it has <dirbase>:<filebase> format for tag */
- len = log_msg.entry.len - sizeof(prio);
- for (cp = msg + sizeof(prio); *cp && isprint(*cp) && !isspace(*cp) && --len; ++cp) {
- if (*cp == ':') {
- if (split) {
- break;
- }
- split = cp;
- }
- }
- if (*cp || !split) {
- continue;
- }
-
- /* Filters */
- if (prefix_len && strncmp(msg + sizeof(prio), prefix, prefix_len)) {
- size_t offset;
- /*
- * Allow : to be a synonym for /
- * Things we do dealing with const char * and do not alloc
- */
- split = strchr(prefix, ':');
- if (split) {
- continue;
- }
- split = strchr(prefix, '/');
- if (!split) {
- continue;
- }
- offset = split - prefix;
- if ((msg[offset + sizeof(prio)] != ':') || strncmp(msg + sizeof(prio), prefix, offset)) {
- continue;
- }
- ++offset;
- if ((prefix_len > offset) &&
- strncmp(&msg[offset + sizeof(prio)], split + 1, prefix_len - offset)) {
- continue;
- }
- }
-
- if ((prio != ANDROID_LOG_ANY) && (*msg < prio)) {
- continue;
- }
-
- /* check if there is an existing entry */
- list_for_each(node, &name_list) {
- names = node_to_item(node, struct names, node);
- if (!strcmp(names->name, msg + sizeof(prio)) && names->id == log_msg.entry.lid &&
- names->prio == *msg) {
- break;
- }
- }
-
- /* We do not have an existing entry, create and add one */
- if (node == &name_list) {
- static const char numbers[] = "0123456789";
- unsigned long long nl;
-
- len = strlen(msg + sizeof(prio)) + 1;
- names = static_cast<struct names*>(calloc(1, sizeof(*names) + len));
- if (!names) {
- ret = -ENOMEM;
- break;
- }
- strcpy(names->name, msg + sizeof(prio));
- names->id = static_cast<log_id_t>(log_msg.entry.lid);
- names->prio = *msg;
- list_init(&names->content);
- /*
- * Insert in reverse numeric _then_ alpha sorted order as
- * representative of log rotation:
- *
- * log.10
- * klog.10
- * . . .
- * log.2
- * klog.2
- * log.1
- * klog.1
- * log
- * klog
- *
- * thus when we present the content, we are provided the oldest
- * first, which when 'refreshed' could spill off the end of the
- * pmsg FIFO but retaining the newest data for last with best
- * chances to survive.
- */
- nl = 0;
- cp = strpbrk(names->name, numbers);
- if (cp) {
- nl = strtoull(cp, NULL, 10);
- }
- list_for_each_reverse(node, &name_list) {
- struct names* a_name = node_to_item(node, struct names, node);
- const char* r = a_name->name;
- int compare = 0;
-
- unsigned long long nr = 0;
- cp = strpbrk(r, numbers);
- if (cp) {
- nr = strtoull(cp, NULL, 10);
- }
- if (nr != nl) {
- compare = (nl > nr) ? 1 : -1;
- }
- if (compare == 0) {
- compare = strcmp(names->name, r);
- }
- if (compare <= 0) {
- break;
- }
- }
- list_add_head(node, &names->node);
- }
-
- /* Remove any file fragments that match our sequence number */
- list_for_each_safe(node, n, &names->content) {
- content = node_to_item(node, struct content, node);
- if (log_msg.entry.nsec == content->entry.nsec) {
- list_remove(&content->node);
- free(content);
- }
- }
-
- /* Add content */
- content = static_cast<struct content*>(
- calloc(1, sizeof(content->node) + hdr_size + log_msg.entry.len));
- if (!content) {
- ret = -ENOMEM;
- break;
- }
- memcpy(&content->entry, &log_msg.entry, hdr_size + log_msg.entry.len);
-
- /* Insert in sequence number sorted order, to ease reconstruction */
- list_for_each_reverse(node, &names->content) {
- if ((node_to_item(node, struct content, node))->entry.nsec < log_msg.entry.nsec) {
- break;
- }
- }
- list_add_head(node, &content->node);
- }
- PmsgClose(&logger_list);
-
- /* Progress through all the collected files */
- list_for_each_safe(node, n, &name_list) {
- struct listnode *content_node, *m;
- char* buf;
- size_t sequence, tag_len;
-
- names = node_to_item(node, struct names, node);
-
- /* Construct content into a linear buffer */
- buf = NULL;
- len = 0;
- sequence = 0;
- tag_len = strlen(names->name) + sizeof(char); /* tag + nul */
- list_for_each_safe(content_node, m, &names->content) {
- ssize_t add_len;
-
- content = node_to_item(content_node, struct content, node);
- add_len = content->entry.len - tag_len - sizeof(prio);
- if (add_len <= 0) {
- list_remove(content_node);
- free(content);
- continue;
- }
-
- if (!buf) {
- buf = static_cast<char*>(malloc(sizeof(char)));
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- *buf = '\0';
- }
-
- /* Missing sequence numbers */
- while (sequence < content->entry.nsec) {
- /* plus space for enforced nul */
- buf = static_cast<char*>(realloc_or_free(buf, len + sizeof(char) + sizeof(char)));
- if (!buf) {
- break;
- }
- buf[len] = '\f'; /* Mark missing content with a form feed */
- buf[++len] = '\0';
- sequence += ANDROID_LOG_PMSG_FILE_SEQUENCE;
- }
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- /* plus space for enforced nul */
- buf = static_cast<char*>(realloc_or_free(buf, len + add_len + sizeof(char)));
- if (!buf) {
- ret = -ENOMEM;
- list_remove(content_node);
- free(content);
- continue;
- }
- memcpy(buf + len, (char*)&content->entry + content->entry.hdr_size + tag_len + sizeof(prio),
- add_len);
- len += add_len;
- buf[len] = '\0'; /* enforce trailing hidden nul */
- sequence = content->entry.nsec + ANDROID_LOG_PMSG_FILE_SEQUENCE;
-
- list_remove(content_node);
- free(content);
- }
- if (buf) {
- if (len) {
- /* Buffer contains enforced trailing nul just beyond length */
- ssize_t r;
- *strchr(names->name, ':') = '/'; /* Convert back to filename */
- r = (*fn)(names->id, names->prio, names->name, buf, len, arg);
- if ((ret >= 0) && (r > 0)) {
- if (ret == SSIZE_MAX) {
- ret = r;
- } else {
- ret += r;
- }
- } else if (r < ret) {
- ret = r;
- }
- }
- free(buf);
- }
- list_remove(node);
- free(names);
- }
- return (ret == SSIZE_MAX) ? -ENOENT : ret;
-}
diff --git a/liblog/pmsg_reader.h b/liblog/pmsg_reader.h
deleted file mode 100644
index b784f9f..0000000
--- a/liblog/pmsg_reader.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#pragma once
-
-#include <sys/cdefs.h>
-#include <unistd.h>
-
-#include "log/log_read.h"
-
-__BEGIN_DECLS
-
-int PmsgRead(struct logger_list* logger_list, struct log_msg* log_msg);
-void PmsgClose(struct logger_list* logger_list);
-
-__END_DECLS
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
deleted file mode 100644
index 8e676bd..0000000
--- a/liblog/pmsg_writer.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2007-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "pmsg_writer.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <log/log_properties.h>
-#include <private/android_logger.h>
-
-#include "logger.h"
-#include "uio.h"
-
-static atomic_int pmsg_fd;
-
-// pmsg_fd should only beopened once. If we see that pmsg_fd is uninitialized, we open "/dev/pmsg0"
-// then attempt to compare/exchange it into pmsg_fd. If the compare/exchange was successful, then
-// that will be the fd used for the duration of the program, otherwise a different thread has
-// already opened and written the fd to the atomic, so close the new fd and return.
-static void GetPmsgFd() {
- if (pmsg_fd != 0) {
- return;
- }
-
- int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (new_fd <= 0) {
- return;
- }
-
- int uninitialized_value = 0;
- if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) {
- close(new_fd);
- return;
- }
-}
-
-void PmsgClose() {
- if (pmsg_fd > 0) {
- close(pmsg_fd);
- }
- pmsg_fd = 0;
-}
-
-int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
- static const unsigned headerLength = 2;
- struct iovec newVec[nr + headerLength];
- android_log_header_t header;
- android_pmsg_log_header_t pmsgHeader;
- size_t i, payloadSize;
- ssize_t ret;
-
- if (!__android_log_is_debuggable()) {
- if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
- return -1;
- }
-
- if (logId == LOG_ID_EVENTS) {
- if (vec[0].iov_len < 4) {
- return -EINVAL;
- }
-
- if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
- return -EPERM;
- }
- }
- }
-
- GetPmsgFd();
-
- if (pmsg_fd <= 0) {
- return -EBADF;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsgHeader;
- * // what we provide to file
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- pmsgHeader.magic = LOGGER_MAGIC;
- pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
- pmsgHeader.uid = getuid();
- pmsgHeader.pid = getpid();
-
- header.id = logId;
- header.tid = gettid();
- header.realtime.tv_sec = ts->tv_sec;
- header.realtime.tv_nsec = ts->tv_nsec;
-
- newVec[0].iov_base = (unsigned char*)&pmsgHeader;
- newVec[0].iov_len = sizeof(pmsgHeader);
- newVec[1].iov_base = (unsigned char*)&header;
- newVec[1].iov_len = sizeof(header);
-
- for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
- newVec[i].iov_base = vec[i - headerLength].iov_base;
- payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;
-
- if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
- newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
- if (newVec[i].iov_len) {
- ++i;
- }
- payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
- break;
- }
- }
- pmsgHeader.len += payloadSize;
-
- ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
- if (ret < 0) {
- ret = errno ? -errno : -ENOTCONN;
- }
-
- if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
- ret -= sizeof(header) - sizeof(pmsgHeader);
- }
-
- return ret;
-}
-
-/*
- * Virtual pmsg filesystem
- *
- * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a
- * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the
- * file.
- *
- * Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
- */
-
-static inline const char* strnrchr(const char* buf, size_t len, char c) {
- const char* cp = buf + len;
- while ((--cp > buf) && (*cp != c))
- ;
- if (cp <= buf) {
- return buf + len;
- }
- return cp;
-}
-
-/* Write a buffer as filename references (tag = <basedir>:<basename>) */
-ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
- const char* buf, size_t len) {
- size_t length, packet_len;
- const char* tag;
- char *cp, *slash;
- struct timespec ts;
- struct iovec vec[3];
-
- /* Make sure the logId value is not a bad idea */
- if ((logId == LOG_ID_KERNEL) || /* Verbotten */
- (logId == LOG_ID_EVENTS) || /* Do not support binary content */
- (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
- ((unsigned)logId >= 32)) { /* fit within logMask on arch32 */
- return -EINVAL;
- }
-
- clock_gettime(CLOCK_REALTIME, &ts);
-
- cp = strdup(filename);
- if (!cp) {
- return -ENOMEM;
- }
-
- tag = cp;
- slash = strrchr(cp, '/');
- if (slash) {
- *slash = ':';
- slash = strrchr(cp, '/');
- if (slash) {
- tag = slash + 1;
- }
- }
-
- length = strlen(tag) + 1;
- packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;
-
- vec[0].iov_base = &prio;
- vec[0].iov_len = sizeof(char);
- vec[1].iov_base = (unsigned char*)tag;
- vec[1].iov_len = length;
-
- for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
- ssize_t ret;
- size_t transfer;
-
- if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
- len -= length;
- break;
- }
-
- transfer = length;
- if (transfer > packet_len) {
- transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
- if ((transfer < length) && (buf[transfer] == '\n')) {
- ++transfer;
- }
- }
-
- vec[2].iov_base = (unsigned char*)buf;
- vec[2].iov_len = transfer;
-
- ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));
-
- if (ret <= 0) {
- free(cp);
- return ret ? ret : (len - length);
- }
- length -= transfer;
- buf += transfer;
- }
- free(cp);
- return len;
-}
diff --git a/liblog/pmsg_writer.h b/liblog/pmsg_writer.h
deleted file mode 100644
index d5e1a1c..0000000
--- a/liblog/pmsg_writer.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <stddef.h>
-
-#include <android/log.h>
-
-int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr);
-void PmsgClose();
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
deleted file mode 100644
index 88f0bf1..0000000
--- a/liblog/properties.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
-** Copyright 2014, 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 <log/log_properties.h>
-
-#include <ctype.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-#include <private/android_logger.h>
-
-#include "logger_write.h"
-
-#ifdef __ANDROID__
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
-
-static int lock() {
- /*
- * If we trigger a signal handler in the middle of locked activity and the
- * signal handler logs a message, we could get into a deadlock state.
- */
- /*
- * Any contention, and we can turn around and use the non-cached method
- * in less time than the system call associated with a mutex to deal with
- * the contention.
- */
- return pthread_mutex_trylock(&lock_loggable);
-}
-
-static void unlock() {
- pthread_mutex_unlock(&lock_loggable);
-}
-
-struct cache {
- const prop_info* pinfo;
- uint32_t serial;
-};
-
-struct cache_char {
- struct cache cache;
- unsigned char c;
-};
-
-static int check_cache(struct cache* cache) {
- return cache->pinfo && __system_property_serial(cache->pinfo) != cache->serial;
-}
-
-#define BOOLEAN_TRUE 0xFF
-#define BOOLEAN_FALSE 0xFE
-
-static void refresh_cache(struct cache_char* cache, const char* key) {
- char buf[PROP_VALUE_MAX];
-
- if (!cache->cache.pinfo) {
- cache->cache.pinfo = __system_property_find(key);
- if (!cache->cache.pinfo) {
- return;
- }
- }
- cache->cache.serial = __system_property_serial(cache->cache.pinfo);
- __system_property_read(cache->cache.pinfo, 0, buf);
- switch (buf[0]) {
- case 't':
- case 'T':
- cache->c = strcasecmp(buf + 1, "rue") ? buf[0] : BOOLEAN_TRUE;
- break;
- case 'f':
- case 'F':
- cache->c = strcasecmp(buf + 1, "alse") ? buf[0] : BOOLEAN_FALSE;
- break;
- default:
- cache->c = buf[0];
- }
-}
-
-static int __android_log_level(const char* tag, size_t len) {
- /* sizeof() is used on this array below */
- static const char log_namespace[] = "persist.log.tag.";
- static const size_t base_offset = 8; /* skip "persist." */
-
- if (tag == nullptr || len == 0) {
- auto& tag_string = GetDefaultTag();
- tag = tag_string.c_str();
- len = tag_string.size();
- }
-
- /* sizeof(log_namespace) = strlen(log_namespace) + 1 */
- char key[sizeof(log_namespace) + len];
- char* kp;
- size_t i;
- char c = 0;
- /*
- * Single layer cache of four properties. Priorities are:
- * log.tag.<tag>
- * persist.log.tag.<tag>
- * log.tag
- * persist.log.tag
- * Where the missing tag matches all tags and becomes the
- * system global default. We do not support ro.log.tag* .
- */
- static char* last_tag;
- static size_t last_tag_len;
- static uint32_t global_serial;
- /* some compilers erroneously see uninitialized use. !not_locked */
- uint32_t current_global_serial = 0;
- static struct cache_char tag_cache[2];
- static struct cache_char global_cache[2];
- int change_detected;
- int global_change_detected;
- int not_locked;
-
- strcpy(key, log_namespace);
-
- global_change_detected = change_detected = not_locked = lock();
-
- if (!not_locked) {
- /*
- * check all known serial numbers to changes.
- */
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- if (check_cache(&tag_cache[i].cache)) {
- change_detected = 1;
- }
- }
- for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- if (check_cache(&global_cache[i].cache)) {
- global_change_detected = 1;
- }
- }
-
- current_global_serial = __system_property_area_serial();
- if (current_global_serial != global_serial) {
- change_detected = 1;
- global_change_detected = 1;
- }
- }
-
- if (len) {
- int local_change_detected = change_detected;
- if (!not_locked) {
- if (!last_tag || !last_tag[0] || (last_tag[0] != tag[0]) ||
- strncmp(last_tag + 1, tag + 1, last_tag_len - 1)) {
- /* invalidate log.tag.<tag> cache */
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- tag_cache[i].cache.pinfo = NULL;
- tag_cache[i].c = '\0';
- }
- if (last_tag) last_tag[0] = '\0';
- local_change_detected = 1;
- }
- if (!last_tag || !last_tag[0]) {
- if (!last_tag) {
- last_tag = static_cast<char*>(calloc(1, len + 1));
- last_tag_len = 0;
- if (last_tag) last_tag_len = len + 1;
- } else if (len >= last_tag_len) {
- last_tag = static_cast<char*>(realloc(last_tag, len + 1));
- last_tag_len = 0;
- if (last_tag) last_tag_len = len + 1;
- }
- if (last_tag) {
- strncpy(last_tag, tag, len);
- last_tag[len] = '\0';
- }
- }
- }
- strncpy(key + sizeof(log_namespace) - 1, tag, len);
- key[sizeof(log_namespace) - 1 + len] = '\0';
-
- kp = key;
- for (i = 0; i < (sizeof(tag_cache) / sizeof(tag_cache[0])); ++i) {
- struct cache_char* cache = &tag_cache[i];
- struct cache_char temp_cache;
-
- if (not_locked) {
- temp_cache.cache.pinfo = NULL;
- temp_cache.c = '\0';
- cache = &temp_cache;
- }
- if (local_change_detected) {
- refresh_cache(cache, kp);
- }
-
- if (cache->c) {
- c = cache->c;
- break;
- }
-
- kp = key + base_offset;
- }
- }
-
- switch (toupper(c)) { /* if invalid, resort to global */
- case 'V':
- case 'D':
- case 'I':
- case 'W':
- case 'E':
- case 'F': /* Not officially supported */
- case 'A':
- case 'S':
- case BOOLEAN_FALSE: /* Not officially supported */
- break;
- default:
- /* clear '.' after log.tag */
- key[sizeof(log_namespace) - 2] = '\0';
-
- kp = key;
- for (i = 0; i < (sizeof(global_cache) / sizeof(global_cache[0])); ++i) {
- struct cache_char* cache = &global_cache[i];
- struct cache_char temp_cache;
-
- if (not_locked) {
- temp_cache = *cache;
- if (temp_cache.cache.pinfo != cache->cache.pinfo) { /* check atomic */
- temp_cache.cache.pinfo = NULL;
- temp_cache.c = '\0';
- }
- cache = &temp_cache;
- }
- if (global_change_detected) {
- refresh_cache(cache, kp);
- }
-
- if (cache->c) {
- c = cache->c;
- break;
- }
-
- kp = key + base_offset;
- }
- break;
- }
-
- if (!not_locked) {
- global_serial = current_global_serial;
- unlock();
- }
-
- switch (toupper(c)) {
- /* clang-format off */
- case 'V': return ANDROID_LOG_VERBOSE;
- case 'D': return ANDROID_LOG_DEBUG;
- case 'I': return ANDROID_LOG_INFO;
- case 'W': return ANDROID_LOG_WARN;
- case 'E': return ANDROID_LOG_ERROR;
- case 'F': /* FALLTHRU */ /* Not officially supported */
- case 'A': return ANDROID_LOG_FATAL;
- case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
- case 'S': return ANDROID_LOG_SILENT;
- /* clang-format on */
- }
- return -1;
-}
-
-int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
- int minimum_log_priority = __android_log_get_minimum_priority();
- int property_log_level = __android_log_level(tag, len);
-
- if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
- return prio >= std::min(property_log_level, minimum_log_priority);
- } else if (property_log_level >= 0) {
- return prio >= property_log_level;
- } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
- return prio >= minimum_log_priority;
- } else {
- return prio >= default_prio;
- }
-}
-
-int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
- auto len = tag ? strlen(tag) : 0;
- return __android_log_is_loggable_len(prio, tag, len, default_prio);
-}
-
-int __android_log_is_debuggable() {
- static int is_debuggable = [] {
- char value[PROP_VALUE_MAX] = {};
- return __system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1");
- }();
-
- return is_debuggable;
-}
-
-/*
- * For properties that are read often, but generally remain constant.
- * Since a change is rare, we will accept a trylock failure gracefully.
- * Use a separate lock from is_loggable to keep contention down b/25563384.
- */
-struct cache2_char {
- pthread_mutex_t lock;
- uint32_t serial;
- const char* key_persist;
- struct cache_char cache_persist;
- const char* key_ro;
- struct cache_char cache_ro;
- unsigned char (*const evaluate)(const struct cache2_char* self);
-};
-
-static inline unsigned char do_cache2_char(struct cache2_char* self) {
- uint32_t current_serial;
- int change_detected;
- unsigned char c;
-
- if (pthread_mutex_trylock(&self->lock)) {
- /* We are willing to accept some race in this context */
- return self->evaluate(self);
- }
-
- change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache);
- current_serial = __system_property_area_serial();
- if (current_serial != self->serial) {
- change_detected = 1;
- }
- if (change_detected) {
- refresh_cache(&self->cache_persist, self->key_persist);
- refresh_cache(&self->cache_ro, self->key_ro);
- self->serial = current_serial;
- }
- c = self->evaluate(self);
-
- pthread_mutex_unlock(&self->lock);
-
- return c;
-}
-
-/*
- * Security state generally remains constant, but the DO must be able
- * to turn off logging should it become spammy after an attack is detected.
- */
-static unsigned char evaluate_security(const struct cache2_char* self) {
- unsigned char c = self->cache_ro.c;
-
- return (c != BOOLEAN_FALSE) && c && (self->cache_persist.c == BOOLEAN_TRUE);
-}
-
-int __android_log_security() {
- static struct cache2_char security = {
- PTHREAD_MUTEX_INITIALIZER, 0,
- "persist.logd.security", {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
- "ro.organization_owned", {{NULL, 0xFFFFFFFF}, BOOLEAN_FALSE},
- evaluate_security};
-
- return do_cache2_char(&security);
-}
-
-#else
-
-int __android_log_is_loggable(int prio, const char*, int) {
- int minimum_priority = __android_log_get_minimum_priority();
- if (minimum_priority == ANDROID_LOG_DEFAULT) {
- minimum_priority = ANDROID_LOG_INFO;
- }
- return prio >= minimum_priority;
-}
-
-int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
- return __android_log_is_loggable(prio, nullptr, def);
-}
-
-int __android_log_is_debuggable() {
- return 1;
-}
-
-#endif
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
deleted file mode 100644
index a17d90c..0000000
--- a/liblog/tests/Android.bp
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-// Copyright (C) 2013-2014 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.
-//
-
-// -----------------------------------------------------------------------------
-// Benchmarks.
-// -----------------------------------------------------------------------------
-
-// Build benchmarks for the device. Run with:
-// adb shell liblog-benchmarks
-cc_benchmark {
- name: "liblog-benchmarks",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ],
- shared_libs: [
- "libm",
- "libbase",
- "libcutils",
- ],
- static_libs: ["liblog"],
- srcs: ["liblog_benchmark.cpp"],
-}
-
-// -----------------------------------------------------------------------------
-// Unit tests.
-// -----------------------------------------------------------------------------
-
-cc_defaults {
- name: "liblog-tests-defaults",
-
- cflags: [
- "-fstack-protector-all",
- "-g",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ],
- srcs: [
- "libc_test.cpp",
- "liblog_default_tag.cpp",
- "liblog_global_state.cpp",
- "liblog_test.cpp",
- "log_id_test.cpp",
- "log_radio_test.cpp",
- "log_read_test.cpp",
- "log_system_test.cpp",
- "log_time_test.cpp",
- "log_wrap_test.cpp",
- "logd_writer_test.cpp",
- "logprint_test.cpp",
- ],
- shared_libs: [
- "libcutils",
- "libbase",
- ],
- static_libs: ["liblog"],
- isolated: true,
- require_root: true,
-}
-
-// Build tests for the device (with .so). Run with:
-// adb shell /data/nativetest/liblog-unit-tests/liblog-unit-tests
-cc_test {
- name: "liblog-unit-tests",
- defaults: ["liblog-tests-defaults"],
-}
-
-cc_test {
- name: "CtsLiblogTestCases",
- defaults: ["liblog-tests-defaults"],
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
-
- cflags: ["-DNO_PSTORE"],
- test_suites: [
- "cts",
- "device-tests",
- "vts10",
- ],
-}
-
-cc_test_host {
- name: "liblog-host-test",
- static_libs: ["liblog"],
- shared_libs: ["libbase"],
- srcs: [
- "liblog_host_test.cpp",
- "liblog_default_tag.cpp",
- "liblog_global_state.cpp",
- ],
- isolated: true,
-}
diff --git a/liblog/tests/AndroidTest.xml b/liblog/tests/AndroidTest.xml
deleted file mode 100644
index fcb46b1..0000000
--- a/liblog/tests/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS Logging Library test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="systems" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="CtsLiblogTestCases->/data/local/tmp/CtsLiblogTestCases" />
- <option name="append-bitness" value="true" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="CtsLiblogTestCases" />
- <option name="runtime-hint" value="65s" />
- </test>
-</configuration>
diff --git a/liblog/tests/libc_test.cpp b/liblog/tests/libc_test.cpp
deleted file mode 100644
index 1f26263..0000000
--- a/liblog/tests/libc_test.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 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 <gtest/gtest.h>
-
-#include <errno.h>
-#include <stdio.h>
-
-TEST(libc, __pstore_append) {
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
- if (access("/dev/pmsg0", W_OK) != 0) {
- GTEST_SKIP() << "pmsg0 not found, skipping test";
- }
-
- FILE* fp;
- ASSERT_TRUE(NULL != (fp = fopen("/dev/pmsg0", "ae")));
- static const char message[] = "libc.__pstore_append\n";
- ASSERT_EQ((size_t)1, fwrite(message, sizeof(message), 1, fp));
- int fflushReturn = fflush(fp);
- int fflushErrno = fflushReturn ? errno : 0;
- ASSERT_EQ(0, fflushReturn);
- ASSERT_EQ(0, fflushErrno);
- int fcloseReturn = fclose(fp);
- int fcloseErrno = fcloseReturn ? errno : 0;
- ASSERT_EQ(0, fcloseReturn);
- ASSERT_EQ(0, fcloseErrno);
- if ((fcloseErrno == ENOMEM) || (fflushErrno == ENOMEM)) {
- fprintf(stderr,
- "Kernel does not have space allocated to pmsg pstore driver "
- "configured\n");
- }
- if (!fcloseReturn && !fcloseErrno && !fflushReturn && !fflushReturn) {
- fprintf(stderr,
- "Reboot, ensure string libc.__pstore_append is in "
- "/sys/fs/pstore/pmsg-ramoops-0\n");
- }
-#else /* NO_PSTORE */
- GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
-#endif /* NO_PSTORE */
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/liblog/tests/liblog_benchmark.cpp b/liblog/tests/liblog_benchmark.cpp
deleted file mode 100644
index d2f12d6..0000000
--- a/liblog/tests/liblog_benchmark.cpp
+++ /dev/null
@@ -1,1004 +0,0 @@
-/*
- * Copyright (C) 2013-2014 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 <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <sched.h>
-#include <sys/socket.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <unordered_set>
-
-#include <android-base/file.h>
-#include <android-base/properties.h>
-#include <benchmark/benchmark.h>
-#include <cutils/sockets.h>
-#include <log/event_tag_map.h>
-#include <log/log_read.h>
-#include <private/android_logger.h>
-
-BENCHMARK_MAIN();
-
-// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
-// non-syscall libs. Since we are benchmarking, or using this in the emergency
-// signal to stuff a terminating code, we do NOT want to introduce
-// a syscall or usleep on EAGAIN retry.
-#define LOG_FAILURE_RETRY(exp) \
- ({ \
- typeof(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
- (_rc == -EINTR) || (_rc == -EAGAIN)); \
- _rc; \
- })
-
-/*
- * Measure the fastest rate we can reliabley stuff print messages into
- * the log at high pressure. Expect this to be less than double the process
- * wakeup time (2ms?)
- */
-static void BM_log_maximum_retry(benchmark::State& state) {
- while (state.KeepRunning()) {
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_INFO, "BM_log_maximum_retry", "%" PRIu64,
- state.iterations()));
- }
-}
-BENCHMARK(BM_log_maximum_retry);
-
-/*
- * Measure the fastest rate we can stuff print messages into the log
- * at high pressure. Expect this to be less than double the process wakeup
- * time (2ms?)
- */
-static void BM_log_maximum(benchmark::State& state) {
- while (state.KeepRunning()) {
- __android_log_print(ANDROID_LOG_INFO, "BM_log_maximum", "%" PRIu64, state.iterations());
- }
-}
-BENCHMARK(BM_log_maximum);
-
-/*
- * Measure the time it takes to collect the time using
- * discrete acquisition (state.PauseTiming() to state.ResumeTiming())
- * under light load. Expect this to be a syscall period (2us) or
- * data read time if zero-syscall.
- *
- * vdso support in the kernel and the library can allow
- * clock_gettime to be zero-syscall, but there there does remain some
- * benchmarking overhead to pause and resume; assumptions are both are
- * covered.
- */
-static void BM_clock_overhead(benchmark::State& state) {
- while (state.KeepRunning()) {
- state.PauseTiming();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_clock_overhead);
-
-static void do_clock_overhead(benchmark::State& state, clockid_t clk_id) {
- timespec t;
- while (state.KeepRunning()) {
- clock_gettime(clk_id, &t);
- }
-}
-
-static void BM_time_clock_gettime_REALTIME(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_REALTIME);
-}
-BENCHMARK(BM_time_clock_gettime_REALTIME);
-
-static void BM_time_clock_gettime_MONOTONIC(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_MONOTONIC);
-}
-BENCHMARK(BM_time_clock_gettime_MONOTONIC);
-
-static void BM_time_clock_gettime_MONOTONIC_syscall(benchmark::State& state) {
- timespec t;
- while (state.KeepRunning()) {
- syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &t);
- }
-}
-BENCHMARK(BM_time_clock_gettime_MONOTONIC_syscall);
-
-static void BM_time_clock_gettime_MONOTONIC_RAW(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_MONOTONIC_RAW);
-}
-BENCHMARK(BM_time_clock_gettime_MONOTONIC_RAW);
-
-static void BM_time_clock_gettime_BOOTTIME(benchmark::State& state) {
- do_clock_overhead(state, CLOCK_BOOTTIME);
-}
-BENCHMARK(BM_time_clock_gettime_BOOTTIME);
-
-static void BM_time_clock_getres_MONOTONIC(benchmark::State& state) {
- timespec t;
- while (state.KeepRunning()) {
- clock_getres(CLOCK_MONOTONIC, &t);
- }
-}
-BENCHMARK(BM_time_clock_getres_MONOTONIC);
-
-static void BM_time_clock_getres_MONOTONIC_syscall(benchmark::State& state) {
- timespec t;
- while (state.KeepRunning()) {
- syscall(__NR_clock_getres, CLOCK_MONOTONIC, &t);
- }
-}
-BENCHMARK(BM_time_clock_getres_MONOTONIC_syscall);
-
-static void BM_time_time(benchmark::State& state) {
- while (state.KeepRunning()) {
- time_t now;
- now = time(&now);
- }
-}
-BENCHMARK(BM_time_time);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- */
-static void BM_pmsg_short(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- android_pmsg_log_header_t pmsg_header;
- pmsg_header.magic = LOGGER_MAGIC;
- pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- pmsg_header.uid = getuid();
- pmsg_header.pid = getpid();
-
- android_log_header_t header;
- header.tid = gettid();
- header.realtime.tv_sec = ts.tv_sec;
- header.realtime.tv_nsec = ts.tv_nsec;
-
- static const unsigned nr = 1;
- static const unsigned header_length = 2;
- struct iovec newVec[nr + header_length];
-
- newVec[0].iov_base = (unsigned char*)&pmsg_header;
- newVec[0].iov_len = sizeof(pmsg_header);
- newVec[1].iov_base = (unsigned char*)&header;
- newVec[1].iov_len = sizeof(header);
-
- android_log_event_int_t buffer;
-
- header.id = LOG_ID_EVENTS;
- buffer.header.tag = 0;
- buffer.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer.payload.data = snapshot;
-
- newVec[2].iov_base = &buffer;
- newVec[2].iov_len = sizeof(buffer);
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer.payload.data = snapshot;
- writev(pstore_fd, newVec, nr);
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_short);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_short_aligned(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
- if (((uintptr_t)&buffer->pmsg_header) & 7) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header,
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t) +
- sizeof(android_log_event_int_t));
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_short_aligned);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_short_unaligned1(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
- if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header,
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t) +
- sizeof(android_log_event_int_t));
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_short_unaligned1);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_long_aligned(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)(((uintptr_t)buf + 7) & ~7);
- if (((uintptr_t)&buffer->pmsg_header) & 7) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_long_aligned);
-
-/*
- * Measure the time it takes to submit the android logging data to pstore
- * best case aligned single block.
- */
-static void BM_pmsg_long_unaligned1(benchmark::State& state) {
- int pstore_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- if (pstore_fd < 0) {
- state.SkipWithError("/dev/pmsg0");
- return;
- }
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsg_header;
- * // what we provide to socket
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- struct packet {
- android_pmsg_log_header_t pmsg_header;
- android_log_header_t header;
- android_log_event_int_t payload;
- };
- alignas(8) char buf[sizeof(struct packet) + 8 + LOGGER_ENTRY_MAX_PAYLOAD];
- memset(buf, 0, sizeof(buf));
- struct packet* buffer = (struct packet*)((((uintptr_t)buf + 7) & ~7) + 1);
- if ((((uintptr_t)&buffer->pmsg_header) & 7) != 1) {
- fprintf(stderr, "&buffer=0x%p iterations=%" PRIu64 "\n", &buffer->pmsg_header,
- state.iterations());
- }
-
- buffer->pmsg_header.magic = LOGGER_MAGIC;
- buffer->pmsg_header.len =
- sizeof(android_pmsg_log_header_t) + sizeof(android_log_header_t);
- buffer->pmsg_header.uid = getuid();
- buffer->pmsg_header.pid = getpid();
-
- buffer->header.tid = gettid();
- buffer->header.realtime.tv_sec = ts.tv_sec;
- buffer->header.realtime.tv_nsec = ts.tv_nsec;
-
- buffer->header.id = LOG_ID_EVENTS;
- buffer->payload.header.tag = 0;
- buffer->payload.payload.type = EVENT_TYPE_INT;
- uint32_t snapshot = 0;
- buffer->payload.payload.data = snapshot;
-
- while (state.KeepRunning()) {
- ++snapshot;
- buffer->payload.payload.data = snapshot;
- write(pstore_fd, &buffer->pmsg_header, LOGGER_ENTRY_MAX_PAYLOAD);
- }
- state.PauseTiming();
- close(pstore_fd);
-}
-BENCHMARK(BM_pmsg_long_unaligned1);
-
-/*
- * Measure the time it takes to form sprintf plus time using
- * discrete acquisition under light load. Expect this to be a syscall period
- * (2us) or sprintf time if zero-syscall time.
- */
-/* helper function */
-static void test_print(const char* fmt, ...) {
- va_list ap;
- char buf[1024];
-
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
-}
-
-#define logd_yield() sched_yield() // allow logd to catch up
-#define logd_sleep() usleep(50) // really allow logd to catch up
-
-/* performance test */
-static void BM_sprintf_overhead(benchmark::State& state) {
- while (state.KeepRunning()) {
- test_print("BM_sprintf_overhead:%" PRIu64, state.iterations());
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_sprintf_overhead);
-
-/*
- * Measure the time it takes to submit the android printing logging call
- * using discrete acquisition discrete acquisition under light load. Expect
- * this to be a dozen or so syscall periods (40us) plus time to run *printf
- */
-static void BM_log_print_overhead(benchmark::State& state) {
- while (state.KeepRunning()) {
- __android_log_print(ANDROID_LOG_INFO, "BM_log_overhead", "%" PRIu64, state.iterations());
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_print_overhead);
-
-/*
- * Measure the time it takes to submit the android event logging call
- * using discrete acquisition under light load. Expect this to be a long path
- * to logger to convert the unknown tag (0) into a tagname (less than 200us).
- */
-static void BM_log_event_overhead(benchmark::State& state) {
- for (int64_t i = 0; state.KeepRunning(); ++i) {
- // log tag number 0 is not known, nor shall it ever be known
- __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_event_overhead);
-
-/*
- * Measure the time it takes to submit the android event logging call
- * using discrete acquisition under light load with a known logtag. Expect
- * this to be a dozen or so syscall periods (less than 40us)
- */
-static void BM_log_event_overhead_42(benchmark::State& state) {
- for (int64_t i = 0; state.KeepRunning(); ++i) {
- // In system/core/logcat/event.logtags:
- // # These are used for testing, do not modify without updating
- // # tests/framework-tests/src/android/util/EventLogFunctionalTest.java.
- // # system/core/liblog/tests/liblog_benchmark.cpp
- // # system/core/liblog/tests/liblog_test.cpp
- // 42 answer (to life the universe etc|3)
- __android_log_btwrite(42, EVENT_TYPE_LONG, &i, sizeof(i));
- state.PauseTiming();
- logd_yield();
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_event_overhead_42);
-
-/*
- * Measure the time it takes to submit the android event logging call
- * using discrete acquisition under very-light load (<1% CPU utilization).
- */
-static void BM_log_light_overhead(benchmark::State& state) {
- for (int64_t i = 0; state.KeepRunning(); ++i) {
- __android_log_btwrite(0, EVENT_TYPE_LONG, &i, sizeof(i));
- state.PauseTiming();
- usleep(10000);
- state.ResumeTiming();
- }
-}
-BENCHMARK(BM_log_light_overhead);
-
-static void caught_latency(int /*signum*/) {
- unsigned long long v = 0xDEADBEEFA55A5AA5ULL;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-static unsigned long long caught_convert(char* cp) {
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long)(cp[1] & 0xFF) << 8;
- l |= (unsigned long long)(cp[2] & 0xFF) << 16;
- l |= (unsigned long long)(cp[3] & 0xFF) << 24;
- l |= (unsigned long long)(cp[4] & 0xFF) << 32;
- l |= (unsigned long long)(cp[5] & 0xFF) << 40;
- l |= (unsigned long long)(cp[6] & 0xFF) << 48;
- l |= (unsigned long long)(cp[7] & 0xFF) << 56;
- return l;
-}
-
-static const int alarm_time = 3;
-
-/*
- * Measure the time it takes for the logd posting call to acquire the
- * timestamp to place into the internal record. Expect this to be less than
- * 4 syscalls (3us). This test uses manual injection of timing because it is
- * comparing the timestamp at send, and then picking up the corresponding log
- * end-to-end long path from logd to see what actual timestamp was submitted.
- */
-static void BM_log_latency(benchmark::State& state) {
- pid_t pid = getpid();
-
- struct logger_list* logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 0, pid);
-
- if (!logger_list) {
- fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- signal(SIGALRM, caught_latency);
- alarm(alarm_time);
-
- for (size_t j = 0; state.KeepRunning() && j < 10 * state.iterations(); ++j) {
- retry: // We allow transitory errors (logd overloaded) to be retried.
- log_time ts;
- LOG_FAILURE_RETRY((ts = log_time(CLOCK_REALTIME),
- android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts))));
-
- for (;;) {
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- alarm(alarm_time);
-
- if (ret <= 0) {
- state.SkipWithError("android_logger_list_read");
- break;
- }
- if ((log_msg.entry.len != (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- char* eventData = log_msg.msg();
-
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
- continue;
- }
- log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
- if (ts != *tx) {
- if (0xDEADBEEFA55A5AA5ULL == caught_convert(eventData + 4 + 1)) {
- state.SkipWithError("signal");
- break;
- }
- continue;
- }
-
- uint64_t start = ts.nsec();
- uint64_t end = log_msg.nsec();
- if (end < start) goto retry;
- state.SetIterationTime((end - start) / (double)NS_PER_SEC);
- break;
- }
- }
-
- signal(SIGALRM, SIG_DFL);
- alarm(0);
-
- android_logger_list_free(logger_list);
-}
-// Default gets out of hand for this test, so we set a reasonable number of
-// iterations for a timely result.
-BENCHMARK(BM_log_latency)->UseManualTime()->Iterations(200);
-
-static void caught_delay(int /*signum*/) {
- unsigned long long v = 0xDEADBEEFA55A5AA6ULL;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-/*
- * Measure the time it takes for the logd posting call to make it into
- * the logs. Expect this to be less than double the process wakeup time (2ms).
- */
-static void BM_log_delay(benchmark::State& state) {
- pid_t pid = getpid();
-
- struct logger_list* logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 0, pid);
-
- if (!logger_list) {
- fprintf(stderr, "Unable to open events log: %s\n", strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- signal(SIGALRM, caught_delay);
- alarm(alarm_time);
-
- while (state.KeepRunning()) {
- log_time ts(CLOCK_REALTIME);
-
- LOG_FAILURE_RETRY(android_btWriteLog(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-
- for (;;) {
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- alarm(alarm_time);
-
- if (ret <= 0) {
- state.SkipWithError("android_logger_list_read");
- break;
- }
- if ((log_msg.entry.len != (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- char* eventData = log_msg.msg();
-
- if (!eventData || (eventData[4] != EVENT_TYPE_LONG)) {
- continue;
- }
- log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1);
- if (ts != *tx) {
- if (0xDEADBEEFA55A5AA6ULL == caught_convert(eventData + 4 + 1)) {
- state.SkipWithError("signal");
- break;
- }
- continue;
- }
-
- break;
- }
- }
- state.PauseTiming();
-
- signal(SIGALRM, SIG_DFL);
- alarm(0);
-
- android_logger_list_free(logger_list);
-}
-BENCHMARK(BM_log_delay);
-
-/*
- * Measure the time it takes for __android_log_is_loggable.
- */
-static void BM_is_loggable(benchmark::State& state) {
- static const char logd[] = "logd";
-
- while (state.KeepRunning()) {
- __android_log_is_loggable_len(ANDROID_LOG_WARN, logd, strlen(logd),
- ANDROID_LOG_VERBOSE);
- }
-}
-BENCHMARK(BM_is_loggable);
-
-/*
- * Measure the time it takes for __android_log_security.
- */
-static void BM_security(benchmark::State& state) {
- while (state.KeepRunning()) {
- __android_log_security();
- }
-}
-BENCHMARK(BM_security);
-
-// Keep maps around for multiple iterations
-static std::unordered_set<uint32_t> set;
-static EventTagMap* map;
-
-static bool prechargeEventMap() {
- if (map) return true;
-
- fprintf(stderr, "Precharge: start\n");
-
- map = android_openEventTagMap(NULL);
- for (uint32_t tag = 1; tag < USHRT_MAX; ++tag) {
- size_t len;
- if (android_lookupEventTag_len(map, &len, tag) == NULL) continue;
- set.insert(tag);
- }
-
- fprintf(stderr, "Precharge: stop %zu\n", set.size());
-
- return true;
-}
-
-/*
- * Measure the time it takes for android_lookupEventTag_len
- */
-static void BM_lookupEventTag(benchmark::State& state) {
- prechargeEventMap();
-
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
- while (state.KeepRunning()) {
- size_t len;
- android_lookupEventTag_len(map, &len, (*it));
- ++it;
- if (it == set.end()) it = set.begin();
- }
-}
-BENCHMARK(BM_lookupEventTag);
-
-/*
- * Measure the time it takes for android_lookupEventTag_len
- */
-static uint32_t notTag = 1;
-
-static void BM_lookupEventTag_NOT(benchmark::State& state) {
- prechargeEventMap();
-
- while (set.find(notTag) != set.end()) {
- ++notTag;
- if (notTag >= USHRT_MAX) notTag = 1;
- }
-
- while (state.KeepRunning()) {
- size_t len;
- android_lookupEventTag_len(map, &len, notTag);
- }
-
- ++notTag;
- if (notTag >= USHRT_MAX) notTag = 1;
-}
-BENCHMARK(BM_lookupEventTag_NOT);
-
-/*
- * Measure the time it takes for android_lookupEventFormat_len
- */
-static void BM_lookupEventFormat(benchmark::State& state) {
- prechargeEventMap();
-
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
- while (state.KeepRunning()) {
- size_t len;
- android_lookupEventFormat_len(map, &len, (*it));
- ++it;
- if (it == set.end()) it = set.begin();
- }
-}
-BENCHMARK(BM_lookupEventFormat);
-
-// Must be functionally identical to liblog internal SendLogdControlMessage()
-static void send_to_control(char* buf, size_t len) {
- int sock =
- socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM | SOCK_CLOEXEC);
- if (sock < 0) return;
- size_t writeLen = strlen(buf) + 1;
-
- ssize_t ret = TEMP_FAILURE_RETRY(write(sock, buf, writeLen));
- if (ret <= 0) {
- close(sock);
- return;
- }
- while ((ret = read(sock, buf, len)) > 0) {
- if (((size_t)ret == len) || (len < PAGE_SIZE)) {
- break;
- }
- len -= ret;
- buf += ret;
-
- struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0 };
-
- ret = poll(&p, 1, 20);
- if ((ret <= 0) || !(p.revents & POLLIN)) {
- break;
- }
- }
- close(sock);
-}
-
-static void BM_lookupEventTagNum_logd_new(benchmark::State& state) {
- fprintf(stderr,
- "WARNING: "
- "This test can cause logd to grow in size and hit DOS limiter\n");
- // Make copies
- static const char empty_event_log_tags[] = "# content owned by logd\n";
- static const char dev_event_log_tags_path[] = "/dev/event-log-tags";
- std::string dev_event_log_tags;
- if (android::base::ReadFileToString(dev_event_log_tags_path,
- &dev_event_log_tags) &&
- (dev_event_log_tags.length() == 0)) {
- dev_event_log_tags = empty_event_log_tags;
- }
- static const char data_event_log_tags_path[] =
- "/data/misc/logd/event-log-tags";
- std::string data_event_log_tags;
- if (android::base::ReadFileToString(data_event_log_tags_path,
- &data_event_log_tags) &&
- (data_event_log_tags.length() == 0)) {
- data_event_log_tags = empty_event_log_tags;
- }
-
- while (state.KeepRunning()) {
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- log_time now(CLOCK_MONOTONIC);
- char name[64];
- snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
- snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"(new|1)\"",
- name);
- state.ResumeTiming();
- send_to_control(buffer, sizeof(buffer));
- state.PauseTiming();
- }
-
- // Restore copies (logd still know about them, until crash or reboot)
- if (dev_event_log_tags.length() &&
- !android::base::WriteStringToFile(dev_event_log_tags,
- dev_event_log_tags_path)) {
- fprintf(stderr,
- "WARNING: "
- "failed to restore %s\n",
- dev_event_log_tags_path);
- }
- if (data_event_log_tags.length() &&
- !android::base::WriteStringToFile(data_event_log_tags,
- data_event_log_tags_path)) {
- fprintf(stderr,
- "WARNING: "
- "failed to restore %s\n",
- data_event_log_tags_path);
- }
- fprintf(stderr,
- "WARNING: "
- "Restarting logd to make it forget what we just did\n");
- system("stop logd ; start logd");
-}
-BENCHMARK(BM_lookupEventTagNum_logd_new);
-
-static void BM_lookupEventTagNum_logd_existing(benchmark::State& state) {
- prechargeEventMap();
-
- std::unordered_set<uint32_t>::const_iterator it = set.begin();
-
- while (state.KeepRunning()) {
- size_t len;
- const char* name = android_lookupEventTag_len(map, &len, (*it));
- std::string Name(name, len);
- const char* format = android_lookupEventFormat_len(map, &len, (*it));
- std::string Format(format, len);
-
- char buffer[256];
- snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"%s\"",
- Name.c_str(), Format.c_str());
-
- state.ResumeTiming();
- send_to_control(buffer, sizeof(buffer));
- state.PauseTiming();
- ++it;
- if (it == set.end()) it = set.begin();
- }
-}
-BENCHMARK(BM_lookupEventTagNum_logd_existing);
-
-static void BM_log_verbose_overhead(benchmark::State& state) {
- std::string test_log_tag = "liblog_verbose_tag";
- android::base::SetProperty("log.tag." + test_log_tag, "I");
- for (auto _ : state) {
- __android_log_print(ANDROID_LOG_VERBOSE, test_log_tag.c_str(), "%s test log message %d %d",
- "test test", 123, 456);
- }
- android::base::SetProperty("log.tag." + test_log_tag, "");
-}
-BENCHMARK(BM_log_verbose_overhead);
diff --git a/liblog/tests/liblog_default_tag.cpp b/liblog/tests/liblog_default_tag.cpp
deleted file mode 100644
index 31b7467..0000000
--- a/liblog/tests/liblog_default_tag.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-// LOG_TAG must be unset for android-base's logging to use a default tag.
-#undef LOG_TAG
-
-#include <stdlib.h>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/scopeguard.h>
-#include <android/log.h>
-
-#include <gtest/gtest.h>
-
-#ifndef __ANDROID__
-static const char* getprogname() {
- return program_invocation_short_name;
-}
-#endif
-
-TEST(liblog_default_tag, no_default_tag_libbase_write_first) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
-
- expected_tag = getprogname();
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, no_default_tag_liblog_write_first) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
-
- expected_tag = getprogname();
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, libbase_sets_default_tag) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "libbase_test_tag";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
- SetDefaultTag(expected_tag);
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, liblog_sets_default_tag) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "liblog_test_tag";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
- __android_log_set_default_tag(expected_tag.c_str());
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(WARNING) << "message";
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_default_tag, default_tag_plus_log_severity) {
-#ifdef __ANDROID__
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = "liblog_test_tag";
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
- __android_log_set_default_tag(expected_tag.c_str());
-
- auto log_tag_property = "log.tag." + expected_tag;
- SetProperty(log_tag_property, "V");
- auto reset_tag_property_guard = make_scope_guard([=] { SetProperty(log_tag_property, ""); });
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_VERBOSE, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(VERBOSE) << "message";
- EXPECT_TRUE(message_seen);
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
-
-TEST(liblog_default_tag, generated_default_tag_plus_log_severity) {
-#ifdef __ANDROID__
- using namespace android::base;
- bool message_seen = false;
- std::string expected_tag = getprogname();
- SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) {
- message_seen = true;
- EXPECT_EQ(expected_tag, tag);
- });
-
- // Even without any calls to SetDefaultTag(), the first message that attempts to log, will
- // generate a default tag from getprogname() and check log.tag.<default tag> for loggability. This
- // case checks that we can log a Verbose message when log.tag.<getprogname()> is set to 'V'.
- auto log_tag_property = "log.tag." + expected_tag;
- SetProperty(log_tag_property, "V");
- auto reset_tag_property_guard = make_scope_guard([=] { SetProperty(log_tag_property, ""); });
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_VERBOSE, nullptr, "message");
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- LOG(VERBOSE) << "message";
- EXPECT_TRUE(message_seen);
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
\ No newline at end of file
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
deleted file mode 100644
index 1d7ff9f..0000000
--- a/liblog/tests/liblog_global_state.cpp
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "global_state_test_tag"
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android/log.h>
-
-#include <gtest/gtest.h>
-
-TEST(liblog_global_state, libbase_logs_with_libbase_SetLogger) {
- using namespace android::base;
- bool message_seen = false;
- LogSeverity expected_severity = WARNING;
- std::string expected_file = Basename(__FILE__);
- unsigned int expected_line;
- std::string expected_message = "libbase test message";
-
- auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
- unsigned int line, const char* message) {
- message_seen = true;
- EXPECT_EQ(DEFAULT, log_id);
- EXPECT_EQ(expected_severity, severity);
- EXPECT_STREQ(LOG_TAG, tag);
- EXPECT_EQ(expected_file, file);
- EXPECT_EQ(expected_line, line);
- EXPECT_EQ(expected_message, message);
- };
-
- SetLogger(LoggerFunction);
-
- expected_line = __LINE__ + 1;
- LOG(expected_severity) << expected_message;
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_global_state, libbase_logs_with_liblog_set_logger) {
- using namespace android::base;
- // These must be static since they're used by the liblog logger function, which only accepts
- // lambdas without captures. The items used by the libbase logger are explicitly not static, to
- // ensure that lambdas with captures do work there.
- static bool message_seen = false;
- static std::string expected_file = Basename(__FILE__);
- static unsigned int expected_line;
- static std::string expected_message = "libbase test message";
-
- auto liblog_logger_function = [](const struct __android_log_message* log_message) {
- message_seen = true;
- EXPECT_EQ(sizeof(__android_log_message), log_message->struct_size);
- EXPECT_EQ(LOG_ID_DEFAULT, log_message->buffer_id);
- EXPECT_EQ(ANDROID_LOG_WARN, log_message->priority);
- EXPECT_STREQ(LOG_TAG, log_message->tag);
- EXPECT_EQ(expected_file, log_message->file);
- EXPECT_EQ(expected_line, log_message->line);
- EXPECT_EQ(expected_message, log_message->message);
- };
-
- __android_log_set_logger(liblog_logger_function);
-
- expected_line = __LINE__ + 1;
- LOG(WARNING) << expected_message;
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_global_state, liblog_logs_with_libbase_SetLogger) {
- using namespace android::base;
- bool message_seen = false;
- std::string expected_message = "libbase test message";
-
- auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
- unsigned int line, const char* message) {
- message_seen = true;
- EXPECT_EQ(MAIN, log_id);
- EXPECT_EQ(WARNING, severity);
- EXPECT_STREQ(LOG_TAG, tag);
- EXPECT_EQ(nullptr, file);
- EXPECT_EQ(0U, line);
- EXPECT_EQ(expected_message, message);
- };
-
- SetLogger(LoggerFunction);
-
- __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, LOG_TAG, expected_message.c_str());
- EXPECT_TRUE(message_seen);
- message_seen = false;
-}
-
-TEST(liblog_global_state, liblog_logs_with_liblog_set_logger) {
- using namespace android::base;
- // These must be static since they're used by the liblog logger function, which only accepts
- // lambdas without captures. The items used by the libbase logger are explicitly not static, to
- // ensure that lambdas with captures do work there.
- static bool message_seen = false;
- static int expected_buffer_id = LOG_ID_MAIN;
- static int expected_priority = ANDROID_LOG_WARN;
- static std::string expected_message = "libbase test message";
-
- auto liblog_logger_function = [](const struct __android_log_message* log_message) {
- message_seen = true;
- EXPECT_EQ(sizeof(__android_log_message), log_message->struct_size);
- EXPECT_EQ(expected_buffer_id, log_message->buffer_id);
- EXPECT_EQ(expected_priority, log_message->priority);
- EXPECT_STREQ(LOG_TAG, log_message->tag);
- EXPECT_STREQ(nullptr, log_message->file);
- EXPECT_EQ(0U, log_message->line);
- EXPECT_EQ(expected_message, log_message->message);
- };
-
- __android_log_set_logger(liblog_logger_function);
-
- __android_log_buf_write(expected_buffer_id, expected_priority, LOG_TAG, expected_message.c_str());
- EXPECT_TRUE(message_seen);
-}
-
-TEST(liblog_global_state, SetAborter_with_liblog) {
- using namespace android::base;
-
- std::string expected_message = "libbase test message";
- static bool message_seen = false;
- auto aborter_function = [&](const char* message) {
- message_seen = true;
- EXPECT_EQ(expected_message, message);
- };
-
- SetAborter(aborter_function);
- LOG(FATAL) << expected_message;
- EXPECT_TRUE(message_seen);
- message_seen = false;
-
- static std::string expected_message_static = "libbase test message";
- auto liblog_aborter_function = [](const char* message) {
- message_seen = true;
- EXPECT_EQ(expected_message_static, message);
- };
- __android_log_set_aborter(liblog_aborter_function);
- LOG(FATAL) << expected_message_static;
- EXPECT_TRUE(message_seen);
- message_seen = false;
-}
-
-static std::string UniqueLogTag() {
- std::string tag = LOG_TAG;
- tag += "-" + std::to_string(getpid());
- return tag;
-}
-
-TEST(liblog_global_state, is_loggable_both_default) {
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-}
-
-TEST(liblog_global_state, is_loggable_minimum_log_priority_only) {
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(android::base::WARNING, android::base::SetMinimumLogSeverity(android::base::DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- EXPECT_EQ(android::base::DEBUG, android::base::SetMinimumLogSeverity(android::base::WARNING));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-}
-
-TEST(liblog_global_state, is_loggable_tag_log_priority_only) {
-#ifdef __ANDROID__
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- auto log_tag_property = std::string("log.tag.") + tag;
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w"));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
-
-TEST(liblog_global_state, is_loggable_both_set) {
-#ifdef __ANDROID__
- auto tag = UniqueLogTag();
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // When both a tag and a minimum priority are set, we use the lower value of the two.
-
- // tag = warning, minimum_priority = debug, expect 'debug'
- auto log_tag_property = std::string("log.tag.") + tag;
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w"));
- EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // tag = warning, minimum_priority = warning, expect 'warning'
- EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // tag = debug, minimum_priority = warning, expect 'debug'
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d"));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- // tag = debug, minimum_priority = debug, expect 'debug'
- EXPECT_EQ(ANDROID_LOG_WARN, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO));
- EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO));
-
- ASSERT_TRUE(android::base::SetProperty(log_tag_property, ""));
-#else
- GTEST_SKIP() << "No log tag properties on host";
-#endif
-}
diff --git a/liblog/tests/liblog_host_test.cpp b/liblog/tests/liblog_host_test.cpp
deleted file mode 100644
index ec186d4..0000000
--- a/liblog/tests/liblog_host_test.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * 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 <log/log.h>
-#include <private/android_logger.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <regex>
-#include <string>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/test_utils.h>
-#include <gtest/gtest.h>
-
-using android::base::InitLogging;
-using android::base::StderrLogger;
-using android::base::StringPrintf;
-
-static std::string MakeLogPattern(int priority, const char* tag, const char* message) {
- static const char log_characters[] = "XXVDIWEF";
- static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
- "Mismatch in size of log_characters and values in android_LogPriority");
- priority = priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : priority;
- char log_char = log_characters[priority];
-
- return StringPrintf("%s %c \\d+-\\d+ \\d+:\\d+:\\d+ \\s*\\d+ \\s*\\d+ %s", tag, log_char,
- message);
-}
-
-static void CheckMessage(bool expected, const std::string& output, int priority, const char* tag,
- const char* message) {
- std::regex message_regex(MakeLogPattern(priority, tag, message));
- EXPECT_EQ(expected, std::regex_search(output, message_regex)) << message;
-}
-
-static void GenerateLogContent() {
- __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_VERBOSE, "tag", "verbose main");
- __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO, "tag", "info main");
- __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_ERROR, "tag", "error main");
-
- __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, "tag", "info radio");
- __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, "tag", "error radio");
-
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, "tag", "verbose system");
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, "tag", "info system");
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, "tag", "error system");
-
- __android_log_buf_print(LOG_ID_CRASH, ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- __android_log_buf_print(LOG_ID_CRASH, ANDROID_LOG_INFO, "tag", "info crash");
- __android_log_buf_print(LOG_ID_CRASH, ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-std::string GetPidString() {
- int pid = getpid();
- return StringPrintf("%5d", pid);
-}
-
-TEST(liblog, default_write) {
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
-
- GenerateLogContent();
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error main");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error radio");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error system");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-TEST(liblog, verbose_write) {
- setenv("ANDROID_LOG_TAGS", "*:v", true);
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
-
- GenerateLogContent();
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error main");
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error radio");
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error system");
-
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-TEST(liblog, error_write) {
- setenv("ANDROID_LOG_TAGS", "*:e", true);
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
-
- GenerateLogContent();
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose main");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info main");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error main");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose radio");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info radio");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error radio");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose system");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info system");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error system");
-
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_VERBOSE, "tag", "verbose crash");
- CheckMessage(false, captured_stderr.str(), ANDROID_LOG_INFO, "tag", "info crash");
- CheckMessage(true, captured_stderr.str(), ANDROID_LOG_ERROR, "tag", "error crash");
-}
-
-TEST(liblog, kernel_no_write) {
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
- __android_log_buf_print(LOG_ID_KERNEL, ANDROID_LOG_ERROR, "tag", "kernel error");
- EXPECT_EQ("", captured_stderr.str());
-}
-
-TEST(liblog, binary_no_write) {
- CapturedStderr captured_stderr;
- InitLogging(nullptr, StderrLogger);
- __android_log_buf_print(LOG_ID_EVENTS, ANDROID_LOG_ERROR, "tag", "error events");
- __android_log_buf_print(LOG_ID_STATS, ANDROID_LOG_ERROR, "tag", "error stats");
- __android_log_buf_print(LOG_ID_SECURITY, ANDROID_LOG_ERROR, "tag", "error security");
-
- __android_log_bswrite(0x12, "events");
- __android_log_stats_bwrite(0x34, "stats", strlen("stats"));
- __android_log_security_bswrite(0x56, "security");
-
- EXPECT_EQ("", captured_stderr.str());
-}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
deleted file mode 100644
index c49d87b..0000000
--- a/liblog/tests/liblog_test.cpp
+++ /dev/null
@@ -1,2770 +0,0 @@
-/*
- * Copyright (C) 2013-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/scopeguard.h>
-#include <android-base/stringprintf.h>
-#ifdef __ANDROID__ // includes sys/properties.h which does not exist outside
-#include <cutils/properties.h>
-#endif
-#include <gtest/gtest.h>
-#include <log/log_event_list.h>
-#include <log/log_properties.h>
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-using android::base::make_scope_guard;
-
-// #define ENABLE_FLAKY_TESTS
-
-// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
-// non-syscall libs. Since we are only using this in the emergency of
-// a signal to stuff a terminating code into the logs, we will spin rather
-// than try a usleep.
-#define LOG_FAILURE_RETRY(exp) \
- ({ \
- typeof(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
- (_rc == -EINTR) || (_rc == -EAGAIN)); \
- _rc; \
- })
-
-// std::unique_ptr doesn't let you provide a pointer to a deleter (android_logger_list_close()) if
-// the type (struct logger_list) is an incomplete type, so we create ListCloser instead.
-struct ListCloser {
- void operator()(struct logger_list* list) { android_logger_list_close(list); }
-};
-
-// This function is meant to be used for most log tests, it does the following:
-// 1) Open the log_buffer with a blocking reader
-// 2) Write the messages via write_messages
-// 3) Set an alarm for 2 seconds as a timeout
-// 4) Read until check_message returns true, which should be used to indicate the target message
-// is found
-// 5) Open log_buffer with a non_blocking reader and dump all messages
-// 6) Count the number of times check_messages returns true for these messages and assert it's
-// only 1.
-template <typename FWrite, typename FCheck>
-static void RunLogTests(log_id_t log_buffer, FWrite write_messages, FCheck check_message) {
- pid_t pid = getpid();
-
- auto logger_list = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(log_buffer, 0, 1000, pid)};
- ASSERT_TRUE(logger_list);
-
- write_messages();
-
- alarm(2);
- auto alarm_guard = android::base::make_scope_guard([] { alarm(0); });
- bool found = false;
- while (!found) {
- log_msg log_msg;
- ASSERT_GT(android_logger_list_read(logger_list.get(), &log_msg), 0);
-
- ASSERT_EQ(log_buffer, log_msg.id());
- ASSERT_EQ(pid, log_msg.entry.pid);
-
- ASSERT_NE(nullptr, log_msg.msg());
-
- check_message(log_msg, &found);
- }
-
- auto logger_list_non_block = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(log_buffer, ANDROID_LOG_NONBLOCK, 1000, pid)};
- ASSERT_TRUE(logger_list_non_block);
-
- size_t count = 0;
- while (true) {
- log_msg log_msg;
- auto ret = android_logger_list_read(logger_list_non_block.get(), &log_msg);
- if (ret == -EAGAIN) {
- break;
- }
- ASSERT_GT(ret, 0);
-
- ASSERT_EQ(log_buffer, log_msg.id());
- ASSERT_EQ(pid, log_msg.entry.pid);
-
- ASSERT_NE(nullptr, log_msg.msg());
-
- found = false;
- check_message(log_msg, &found);
- if (found) {
- ++count;
- }
- }
-
- EXPECT_EQ(1U, count);
-}
-
-TEST(liblog, __android_log_btwrite) {
- int intBuf = 0xDEADBEEF;
- EXPECT_LT(0,
- __android_log_btwrite(0, EVENT_TYPE_INT, &intBuf, sizeof(intBuf)));
- long long longBuf = 0xDEADBEEFA55A5AA5;
- EXPECT_LT(
- 0, __android_log_btwrite(0, EVENT_TYPE_LONG, &longBuf, sizeof(longBuf)));
- char Buf[] = "\20\0\0\0DeAdBeEfA55a5aA5";
- EXPECT_LT(0,
- __android_log_btwrite(0, EVENT_TYPE_STRING, Buf, sizeof(Buf) - 1));
-}
-
-#if defined(__ANDROID__)
-static std::string popenToString(const std::string& command) {
- std::string ret;
-
- FILE* fp = popen(command.c_str(), "re");
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &ret)) ret = "";
- pclose(fp);
- }
- return ret;
-}
-
-static bool isPmsgActive() {
- pid_t pid = getpid();
-
- std::string myPidFds =
- popenToString(android::base::StringPrintf("ls -l /proc/%d/fd", pid));
- if (myPidFds.length() == 0) return true; // guess it is?
-
- return std::string::npos != myPidFds.find(" -> /dev/pmsg0");
-}
-
-static bool isLogdwActive() {
- std::string logdwSignature =
- popenToString("grep -a /dev/socket/logdw /proc/net/unix");
- size_t beginning = logdwSignature.find(' ');
- if (beginning == std::string::npos) return true;
- beginning = logdwSignature.find(' ', beginning + 1);
- if (beginning == std::string::npos) return true;
- size_t end = logdwSignature.find(' ', beginning + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(' ', end + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(' ', end + 1);
- if (end == std::string::npos) return true;
- end = logdwSignature.find(' ', end + 1);
- if (end == std::string::npos) return true;
- std::string allLogdwEndpoints = popenToString(
- "grep -a ' 00000002" + logdwSignature.substr(beginning, end - beginning) +
- " ' /proc/net/unix | " +
- "sed -n 's/.* \\([0-9][0-9]*\\)$/ -> socket:[\\1]/p'");
- if (allLogdwEndpoints.length() == 0) return true;
-
- // NB: allLogdwEndpoints has some false positives in it, but those
- // strangers do not overlap with the simplistic activities inside this
- // test suite.
-
- pid_t pid = getpid();
-
- std::string myPidFds =
- popenToString(android::base::StringPrintf("ls -l /proc/%d/fd", pid));
- if (myPidFds.length() == 0) return true;
-
- // NB: fgrep with multiple strings is broken in Android
- for (beginning = 0;
- (end = allLogdwEndpoints.find('\n', beginning)) != std::string::npos;
- beginning = end + 1) {
- if (myPidFds.find(allLogdwEndpoints.substr(beginning, end - beginning)) !=
- std::string::npos)
- return true;
- }
- return false;
-}
-
-static bool tested__android_log_close;
-#endif
-
-TEST(liblog, __android_log_btwrite__android_logger_list_read) {
-#ifdef __ANDROID__
- log_time ts(CLOCK_MONOTONIC);
- log_time ts1(ts);
-
- bool has_pstore = access("/dev/pmsg0", W_OK) == 0;
-
- auto write_function = [&] {
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- // Check that we can close and reopen the logger
- bool logdwActiveAfter__android_log_btwrite;
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- if (has_pstore) {
- bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
- }
- logdwActiveAfter__android_log_btwrite = isLogdwActive();
- EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
- __android_log_close();
- if (getuid() == AID_ROOT) {
- if (has_pstore) {
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- }
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- }
-
- ts1 = log_time(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
- if (getuid() == AID_ROOT) {
- if (has_pstore) {
- bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
- }
- logdwActiveAfter__android_log_btwrite = isLogdwActive();
- EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
- }
- };
-
- int count = 0;
- int second_count = 0;
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- return;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- return;
- }
-
- log_time* tx = reinterpret_cast<log_time*>(&eventData->payload.data);
- if (ts == *tx) {
- ++count;
- } else if (ts1 == *tx) {
- ++second_count;
- }
-
- if (count == 1 && second_count == 1) {
- count = 0;
- second_count = 0;
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_write__android_logger_list_read) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
-
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- std::string buf = android::base::StringPrintf("pid=%u ts=%ld.%09ld", pid, ts.tv_sec, ts.tv_nsec);
- static const char tag[] = "liblog.__android_log_write__android_logger_list_read";
- static const char prio = ANDROID_LOG_DEBUG;
-
- std::string expected_message =
- std::string(&prio, sizeof(prio)) + tag + std::string("", 1) + buf + std::string("", 1);
-
- auto write_function = [&] { ASSERT_LT(0, __android_log_write(prio, tag, buf.c_str())); };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if (log_msg.entry.len != expected_message.length()) {
- return;
- }
-
- if (expected_message != std::string(log_msg.msg(), log_msg.entry.len)) {
- return;
- }
-
- *found = true;
- };
-
- RunLogTests(LOG_ID_MAIN, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-static void bswrite_test(const char* message) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
-
- size_t num_lines = 1, size = 0, length = 0, total = 0;
- const char* cp = message;
- while (*cp) {
- if (*cp == '\n') {
- if (cp[1]) {
- ++num_lines;
- }
- } else {
- ++size;
- }
- ++cp;
- ++total;
- ++length;
- if ((LOGGER_ENTRY_MAX_PAYLOAD - 4 - 1 - 4) <= length) {
- break;
- }
- }
- while (*cp) {
- ++cp;
- ++total;
- }
-
- auto write_function = [&] { EXPECT_LT(0, __android_log_bswrite(0, message)); };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((size_t)log_msg.entry.len != (sizeof(android_log_event_string_t) + length) ||
- log_msg.id() != LOG_ID_EVENTS) {
- return;
- }
-
- android_log_event_string_t* eventData;
- eventData = reinterpret_cast<android_log_event_string_t*>(log_msg.msg());
-
- if (!eventData || (eventData->type != EVENT_TYPE_STRING)) {
- return;
- }
-
- size_t len = eventData->length;
- if (len == total) {
- *found = true;
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- char msgBuf[1024];
- if (length != total) {
- fprintf(stderr, "Expect \"Binary log entry conversion failed\"\n");
- }
- int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
- &log_msg.entry, &entry, nullptr, msgBuf, sizeof(msgBuf));
- EXPECT_EQ((length == total) ? 0 : -1, processBinaryLogBuffer);
- if ((processBinaryLogBuffer == 0) || entry.message) {
- size_t line_overhead = 20;
- if (pid > 99999) ++line_overhead;
- if (pid > 999999) ++line_overhead;
- fflush(stderr);
- if (processBinaryLogBuffer) {
- EXPECT_GT((int)((line_overhead * num_lines) + size),
- android_log_printLogLine(logformat, fileno(stderr), &entry));
- } else {
- EXPECT_EQ((int)((line_overhead * num_lines) + size),
- android_log_printLogLine(logformat, fileno(stderr), &entry));
- }
- }
- android_log_format_free(logformat);
- }
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-
-#else
- message = NULL;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_bswrite_and_print) {
- bswrite_test("Hello World");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__empty_string) {
- bswrite_test("");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__newline_prefix) {
- bswrite_test("\nHello World\n");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__newline_space_prefix) {
- bswrite_test("\n Hello World \n");
-}
-
-TEST(liblog, __android_log_bswrite_and_print__multiple_newline) {
- bswrite_test("one\ntwo\nthree\nfour\nfive\nsix\nseven\neight\nnine\nten");
-}
-
-static void buf_write_test(const char* message) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
-
- static const char tag[] = "TEST__android_log_buf_write";
-
- auto write_function = [&] {
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO, tag, message));
- };
- size_t num_lines = 1, size = 0, length = 0;
- const char* cp = message;
- while (*cp) {
- if (*cp == '\n') {
- if (cp[1]) {
- ++num_lines;
- }
- } else {
- ++size;
- }
- ++length;
- if ((LOGGER_ENTRY_MAX_PAYLOAD - 2 - sizeof(tag)) <= length) {
- break;
- }
- ++cp;
- }
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((size_t)log_msg.entry.len != (sizeof(tag) + length + 2) || log_msg.id() != LOG_ID_MAIN) {
- return;
- }
-
- *found = true;
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- int processLogBuffer = android_log_processLogBuffer(&log_msg.entry, &entry);
- EXPECT_EQ(0, processLogBuffer);
- if (processLogBuffer == 0) {
- size_t line_overhead = 11;
- if (pid > 99999) ++line_overhead;
- if (pid > 999999) ++line_overhead;
- fflush(stderr);
- EXPECT_EQ((int)(((line_overhead + sizeof(tag)) * num_lines) + size),
- android_log_printLogLine(logformat, fileno(stderr), &entry));
- }
- android_log_format_free(logformat);
- };
-
- RunLogTests(LOG_ID_MAIN, write_function, check_function);
-
-#else
- message = NULL;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_buf_write_and_print__empty) {
- buf_write_test("");
-}
-
-TEST(liblog, __android_log_buf_write_and_print__newline_prefix) {
- buf_write_test("\nHello World\n");
-}
-
-TEST(liblog, __android_log_buf_write_and_print__newline_space_prefix) {
- buf_write_test("\n Hello World \n");
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-#ifdef __ANDROID__
-static unsigned signaled;
-static log_time signal_time;
-
-/*
- * Strictly, we are not allowed to log messages in a signal context, but we
- * do make an effort to keep the failure surface minimized, and this in-effect
- * should catch any regressions in that effort. The odds of a logged message
- * in a signal handler causing a lockup problem should be _very_ small.
- */
-static void caught_blocking_signal(int /*signum*/) {
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
-
- v += getpid() & 0xFFFF;
-
- ++signaled;
- if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
- signal_time = log_time(CLOCK_MONOTONIC);
- signal_time.tv_sec += 2;
- }
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-// Fill in current process user and system time in 10ms increments
-static void get_ticks(unsigned long long* uticks, unsigned long long* sticks) {
- *uticks = *sticks = 0;
-
- pid_t pid = getpid();
-
- char buffer[512];
- snprintf(buffer, sizeof(buffer), "/proc/%u/stat", pid);
-
- FILE* fp = fopen(buffer, "re");
- if (!fp) {
- return;
- }
-
- char* cp = fgets(buffer, sizeof(buffer), fp);
- fclose(fp);
- if (!cp) {
- return;
- }
-
- pid_t d;
- char s[sizeof(buffer)];
- char c;
- long long ll;
- unsigned long long ull;
-
- if (15 != sscanf(buffer,
- "%d %s %c %lld %lld %lld %lld %lld %llu %llu %llu %llu %llu "
- "%llu %llu ",
- &d, s, &c, &ll, &ll, &ll, &ll, &ll, &ull, &ull, &ull, &ull,
- &ull, uticks, sticks)) {
- *uticks = *sticks = 0;
- }
-}
-#endif
-
-TEST(liblog, android_logger_list_read__cpu_signal) {
-#ifdef __ANDROID__
- struct logger_list* logger_list;
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 1000, pid)));
-
- int count = 0;
-
- int signals = 0;
-
- unsigned long long uticks_start;
- unsigned long long sticks_start;
- get_ticks(&uticks_start, &sticks_start);
-
- const unsigned alarm_time = 10;
-
- memset(&signal_time, 0, sizeof(signal_time));
-
- signal(SIGALRM, caught_blocking_signal);
- alarm(alarm_time);
-
- signaled = 0;
-
- do {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- alarm(alarm_time);
-
- ++count;
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
-
- char* cp = reinterpret_cast<char*>(&eventData->payload.data);
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long)(cp[1] & 0xFF) << 8;
- l |= (unsigned long long)(cp[2] & 0xFF) << 16;
- l |= (unsigned long long)(cp[3] & 0xFF) << 24;
- l |= (unsigned long long)(cp[4] & 0xFF) << 32;
- l |= (unsigned long long)(cp[5] & 0xFF) << 40;
- l |= (unsigned long long)(cp[6] & 0xFF) << 48;
- l |= (unsigned long long)(cp[7] & 0xFF) << 56;
-
- if (l == v) {
- ++signals;
- break;
- }
- } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- EXPECT_LE(1, count);
-
- EXPECT_EQ(1, signals);
-
- android_logger_list_close(logger_list);
-
- unsigned long long uticks_end;
- unsigned long long sticks_end;
- get_ticks(&uticks_end, &sticks_end);
-
- // Less than 1% in either user or system time, or both
- const unsigned long long one_percent_ticks = alarm_time;
- unsigned long long user_ticks = uticks_end - uticks_start;
- unsigned long long system_ticks = sticks_end - sticks_start;
- EXPECT_GT(one_percent_ticks, user_ticks);
- EXPECT_GT(one_percent_ticks, system_ticks);
- EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-#ifdef __ANDROID__
-/*
- * Strictly, we are not allowed to log messages in a signal context, the
- * correct way to handle this is to ensure the messages are constructed in
- * a thread; the signal handler should only unblock the thread.
- */
-static sem_t thread_trigger;
-
-static void caught_blocking_thread(int /*signum*/) {
- sem_post(&thread_trigger);
-}
-
-static void* running_thread(void*) {
- unsigned long long v = 0xDEADBEAFA55A0000ULL;
-
- v += getpid() & 0xFFFF;
-
- struct timespec timeout;
- clock_gettime(CLOCK_REALTIME, &timeout);
- timeout.tv_sec += 55;
- sem_timedwait(&thread_trigger, &timeout);
-
- ++signaled;
- if ((signal_time.tv_sec == 0) && (signal_time.tv_nsec == 0)) {
- signal_time = log_time(CLOCK_MONOTONIC);
- signal_time.tv_sec += 2;
- }
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-
- return NULL;
-}
-
-static int start_thread() {
- sem_init(&thread_trigger, 0, 0);
-
- pthread_attr_t attr;
- if (pthread_attr_init(&attr)) {
- return -1;
- }
-
- struct sched_param param;
-
- memset(¶m, 0, sizeof(param));
- pthread_attr_setschedparam(&attr, ¶m);
- pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
-
- if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
- pthread_attr_destroy(&attr);
- return -1;
- }
-
- pthread_t thread;
- if (pthread_create(&thread, &attr, running_thread, NULL)) {
- pthread_attr_destroy(&attr);
- return -1;
- }
-
- pthread_attr_destroy(&attr);
- return 0;
-}
-#endif
-
-TEST(liblog, android_logger_list_read__cpu_thread) {
-#ifdef __ANDROID__
- struct logger_list* logger_list;
- unsigned long long v = 0xDEADBEAFA55A0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_EVENTS, 0, 1000, pid)));
-
- int count = 0;
-
- int signals = 0;
-
- unsigned long long uticks_start;
- unsigned long long sticks_start;
- get_ticks(&uticks_start, &sticks_start);
-
- const unsigned alarm_time = 10;
-
- memset(&signal_time, 0, sizeof(signal_time));
-
- signaled = 0;
- EXPECT_EQ(0, start_thread());
-
- signal(SIGALRM, caught_blocking_thread);
- alarm(alarm_time);
-
- do {
- log_msg log_msg;
- if (LOG_FAILURE_RETRY(android_logger_list_read(logger_list, &log_msg)) <= 0) {
- break;
- }
-
- alarm(alarm_time);
-
- ++count;
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_EVENTS)) {
- continue;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
-
- char* cp = reinterpret_cast<char*>(&eventData->payload.data);
- unsigned long long l = cp[0] & 0xFF;
- l |= (unsigned long long)(cp[1] & 0xFF) << 8;
- l |= (unsigned long long)(cp[2] & 0xFF) << 16;
- l |= (unsigned long long)(cp[3] & 0xFF) << 24;
- l |= (unsigned long long)(cp[4] & 0xFF) << 32;
- l |= (unsigned long long)(cp[5] & 0xFF) << 40;
- l |= (unsigned long long)(cp[6] & 0xFF) << 48;
- l |= (unsigned long long)(cp[7] & 0xFF) << 56;
-
- if (l == v) {
- ++signals;
- break;
- }
- } while (!signaled || (log_time(CLOCK_MONOTONIC) < signal_time));
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- EXPECT_LE(1, count);
-
- EXPECT_EQ(1, signals);
-
- android_logger_list_close(logger_list);
-
- unsigned long long uticks_end;
- unsigned long long sticks_end;
- get_ticks(&uticks_end, &sticks_end);
-
- // Less than 1% in either user or system time, or both
- const unsigned long long one_percent_ticks = alarm_time;
- unsigned long long user_ticks = uticks_end - uticks_start;
- unsigned long long system_ticks = sticks_end - sticks_start;
- EXPECT_GT(one_percent_ticks, user_ticks);
- EXPECT_GT(one_percent_ticks, system_ticks);
- EXPECT_GT(one_percent_ticks, user_ticks + system_ticks);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
-
-static const char max_payload_buf[] =
- "LEONATO\n\
-I learn in this letter that Don Peter of Arragon\n\
-comes this night to Messina\n\
-MESSENGER\n\
-He is very near by this: he was not three leagues off\n\
-when I left him\n\
-LEONATO\n\
-How many gentlemen have you lost in this action?\n\
-MESSENGER\n\
-But few of any sort, and none of name\n\
-LEONATO\n\
-A victory is twice itself when the achiever brings\n\
-home full numbers. I find here that Don Peter hath\n\
-bestowed much honour on a young Florentine called Claudio\n\
-MESSENGER\n\
-Much deserved on his part and equally remembered by\n\
-Don Pedro: he hath borne himself beyond the\n\
-promise of his age, doing, in the figure of a lamb,\n\
-the feats of a lion: he hath indeed better\n\
-bettered expectation than you must expect of me to\n\
-tell you how\n\
-LEONATO\n\
-He hath an uncle here in Messina will be very much\n\
-glad of it.\n\
-MESSENGER\n\
-I have already delivered him letters, and there\n\
-appears much joy in him; even so much that joy could\n\
-not show itself modest enough without a badge of\n\
-bitterness.\n\
-LEONATO\n\
-Did he break out into tears?\n\
-MESSENGER\n\
-In great measure.\n\
-LEONATO\n\
-A kind overflow of kindness: there are no faces\n\
-truer than those that are so washed. How much\n\
-better is it to weep at joy than to joy at weeping!\n\
-BEATRICE\n\
-I pray you, is Signior Mountanto returned from the\n\
-wars or no?\n\
-MESSENGER\n\
-I know none of that name, lady: there was none such\n\
-in the army of any sort.\n\
-LEONATO\n\
-What is he that you ask for, niece?\n\
-HERO\n\
-My cousin means Signior Benedick of Padua.\n\
-MESSENGER\n\
-O, he's returned; and as pleasant as ever he was.\n\
-BEATRICE\n\
-He set up his bills here in Messina and challenged\n\
-Cupid at the flight; and my uncle's fool, reading\n\
-the challenge, subscribed for Cupid, and challenged\n\
-him at the bird-bolt. I pray you, how many hath he\n\
-killed and eaten in these wars? But how many hath\n\
-he killed? for indeed I promised to eat all of his killing.\n\
-LEONATO\n\
-Faith, niece, you tax Signior Benedick too much;\n\
-but he'll be meet with you, I doubt it not.\n\
-MESSENGER\n\
-He hath done good service, lady, in these wars.\n\
-BEATRICE\n\
-You had musty victual, and he hath holp to eat it:\n\
-he is a very valiant trencherman; he hath an\n\
-excellent stomach.\n\
-MESSENGER\n\
-And a good soldier too, lady.\n\
-BEATRICE\n\
-And a good soldier to a lady: but what is he to a lord?\n\
-MESSENGER\n\
-A lord to a lord, a man to a man; stuffed with all\n\
-honourable virtues.\n\
-BEATRICE\n\
-It is so, indeed; he is no less than a stuffed man:\n\
-but for the stuffing,--well, we are all mortal.\n\
-LEONATO\n\
-You must not, sir, mistake my niece. There is a\n\
-kind of merry war betwixt Signior Benedick and her:\n\
-they never meet but there's a skirmish of wit\n\
-between them.\n\
-BEATRICE\n\
-Alas! he gets nothing by that. In our last\n\
-conflict four of his five wits went halting off, and\n\
-now is the whole man governed with one: so that if\n\
-he have wit enough to keep himself warm, let him\n\
-bear it for a difference between himself and his\n\
-horse; for it is all the wealth that he hath left,\n\
-to be known a reasonable creature. Who is his\n\
-companion now? He hath every month a new sworn brother.\n\
-MESSENGER\n\
-Is't possible?\n\
-BEATRICE\n\
-Very easily possible: he wears his faith but as\n\
-the fashion of his hat; it ever changes with the\n\
-next block.\n\
-MESSENGER\n\
-I see, lady, the gentleman is not in your books.\n\
-BEATRICE\n\
-No; an he were, I would burn my study. But, I pray\n\
-you, who is his companion? Is there no young\n\
-squarer now that will make a voyage with him to the devil?\n\
-MESSENGER\n\
-He is most in the company of the right noble Claudio.\n\
-BEATRICE\n\
-O Lord, he will hang upon him like a disease: he\n\
-is sooner caught than the pestilence, and the taker\n\
-runs presently mad. God help the noble Claudio! if\n\
-he have caught the Benedick, it will cost him a\n\
-thousand pound ere a' be cured.\n\
-MESSENGER\n\
-I will hold friends with you, lady.\n\
-BEATRICE\n\
-Do, good friend.\n\
-LEONATO\n\
-You will never run mad, niece.\n\
-BEATRICE\n\
-No, not till a hot January.\n\
-MESSENGER\n\
-Don Pedro is approached.\n\
-Enter DON PEDRO, DON JOHN, CLAUDIO, BENEDICK, and BALTHASAR\n\
-\n\
-DON PEDRO\n\
-Good Signior Leonato, you are come to meet your\n\
-trouble: the fashion of the world is to avoid\n\
-cost, and you encounter it\n\
-LEONATO\n\
-Never came trouble to my house in the likeness of your grace,\n\
-for trouble being gone, comfort should remain, but\n\
-when you depart from me, sorrow abides and happiness\n\
-takes his leave.";
-
-TEST(liblog, max_payload) {
-#ifdef __ANDROID__
- static const char max_payload_tag[] = "TEST_max_payload_and_longish_tag_XXXX";
-#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(max_payload_tag) - 1)
-
- pid_t pid = getpid();
- char tag[sizeof(max_payload_tag)];
- memcpy(tag, max_payload_tag, sizeof(tag));
- snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
-
- auto write_function = [&] {
- LOG_FAILURE_RETRY(
- __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO, tag, max_payload_buf));
- };
-
- ssize_t max_len = 0;
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* data = log_msg.msg();
-
- if (!data || strcmp(++data, tag)) {
- return;
- }
-
- data += strlen(data) + 1;
-
- const char* left = data;
- const char* right = max_payload_buf;
- while (*left && *right && (*left == *right)) {
- ++left;
- ++right;
- }
-
- if (max_len <= (left - data)) {
- max_len = left - data + 1;
- }
-
- if (max_len > 512) {
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_SYSTEM, write_function, check_function);
-
- EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_buf_print__maxtag) {
-#ifdef __ANDROID__
- auto write_function = [&] {
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO, max_payload_buf,
- max_payload_buf));
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- if ((size_t)log_msg.entry.len < LOGGER_ENTRY_MAX_PAYLOAD) {
- return;
- }
-
- *found = true;
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- int processLogBuffer = android_log_processLogBuffer(&log_msg.entry, &entry);
- EXPECT_EQ(0, processLogBuffer);
- if (processLogBuffer == 0) {
- fflush(stderr);
- int printLogLine =
- android_log_printLogLine(logformat, fileno(stderr), &entry);
- // Legacy tag truncation
- EXPECT_LE(128, printLogLine);
- // Measured maximum if we try to print part of the tag as message
- EXPECT_GT(LOGGER_ENTRY_MAX_PAYLOAD * 13 / 8, printLogLine);
- }
- android_log_format_free(logformat);
- };
-
- RunLogTests(LOG_ID_MAIN, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-// Note: This test is tautological. android_logger_list_read() calls recv() with
-// LOGGER_ENTRY_MAX_PAYLOAD as its size argument, so it's not possible for this test to read a
-// payload larger than that size.
-TEST(liblog, too_big_payload) {
-#ifdef __ANDROID__
- pid_t pid = getpid();
- static const char big_payload_tag[] = "TEST_big_payload_XXXX";
- char tag[sizeof(big_payload_tag)];
- memcpy(tag, big_payload_tag, sizeof(tag));
- snprintf(tag + sizeof(tag) - 5, 5, "%04X", pid & 0xFFFF);
-
- std::string longString(3266519, 'x');
- ssize_t ret;
-
- auto write_function = [&] {
- ret = LOG_FAILURE_RETRY(
- __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO, tag, longString.c_str()));
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* data = log_msg.msg();
-
- if (!data || strcmp(++data, tag)) {
- return;
- }
-
- data += strlen(data) + 1;
-
- const char* left = data;
- const char* right = longString.c_str();
- while (*left && *right && (*left == *right)) {
- ++left;
- ++right;
- }
-
- ssize_t len = left - data + 1;
- // Check that we don't see any entries larger than the max payload.
- EXPECT_LE(static_cast<size_t>(len), LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag));
-
- // Once we've found our expected entry, break.
- if (len == LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag)) {
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_SYSTEM, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, dual_reader) {
-#ifdef __ANDROID__
- static const int expected_count1 = 25;
- static const int expected_count2 = 25;
-
- pid_t pid = getpid();
-
- auto logger_list1 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, 0, expected_count1, pid)};
- ASSERT_TRUE(logger_list1);
-
- auto logger_list2 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, 0, expected_count2, pid)};
- ASSERT_TRUE(logger_list2);
-
- for (int i = 25; i > 0; --i) {
- static const char fmt[] = "dual_reader %02d";
- char buffer[sizeof(fmt) + 8];
- snprintf(buffer, sizeof(buffer), fmt, i);
- LOG_FAILURE_RETRY(__android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "liblog", buffer));
- }
-
- alarm(2);
- auto alarm_guard = android::base::make_scope_guard([] { alarm(0); });
-
- // Wait until we see all messages with the blocking reader.
- int count1 = 0;
- int count2 = 0;
-
- while (count1 != expected_count2 || count2 != expected_count2) {
- log_msg log_msg;
- if (count1 < expected_count1) {
- ASSERT_GT(android_logger_list_read(logger_list1.get(), &log_msg), 0);
- count1++;
- }
- if (count2 < expected_count2) {
- ASSERT_GT(android_logger_list_read(logger_list2.get(), &log_msg), 0);
- count2++;
- }
- }
-
- // Test again with the nonblocking reader.
- auto logger_list_non_block1 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, expected_count1, pid)};
- ASSERT_TRUE(logger_list_non_block1);
-
- auto logger_list_non_block2 = std::unique_ptr<struct logger_list, ListCloser>{
- android_logger_list_open(LOG_ID_MAIN, ANDROID_LOG_NONBLOCK, expected_count2, pid)};
- ASSERT_TRUE(logger_list_non_block2);
- count1 = 0;
- count2 = 0;
- bool done1 = false;
- bool done2 = false;
-
- while (!done1 || !done2) {
- log_msg log_msg;
-
- if (!done1) {
- if (android_logger_list_read(logger_list_non_block1.get(), &log_msg) <= 0) {
- done1 = true;
- } else {
- ++count1;
- }
- }
-
- if (!done2) {
- if (android_logger_list_read(logger_list_non_block2.get(), &log_msg) <= 0) {
- done2 = true;
- } else {
- ++count2;
- }
- }
- }
-
- EXPECT_EQ(expected_count1, count1);
- EXPECT_EQ(expected_count2, count2);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-static bool checkPriForTag(AndroidLogFormat* p_format, const char* tag,
- android_LogPriority pri) {
- return android_log_shouldPrintLine(p_format, tag, pri) &&
- !android_log_shouldPrintLine(p_format, tag,
- (android_LogPriority)(pri - 1));
-}
-
-TEST(liblog, filterRule) {
- static const char tag[] = "random";
-
- AndroidLogFormat* p_format = android_log_format_new();
-
- android_log_addFilterRule(p_format, "*:i");
-
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
- android_log_addFilterRule(p_format, "*");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:v");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "*:i");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_INFO));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
-
- android_log_addFilterRule(p_format, tag);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:v");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:d");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) > 0);
- android_log_addFilterRule(p_format, "random:w");
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
-
- android_log_addFilterRule(p_format, "crap:*");
- EXPECT_TRUE(checkPriForTag(p_format, "crap", ANDROID_LOG_VERBOSE));
- EXPECT_TRUE(
- android_log_shouldPrintLine(p_format, "crap", ANDROID_LOG_VERBOSE) > 0);
-
- // invalid expression
- EXPECT_TRUE(android_log_addFilterRule(p_format, "random:z") < 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
- EXPECT_TRUE(android_log_shouldPrintLine(p_format, tag, ANDROID_LOG_DEBUG) ==
- 0);
-
- // Issue #550946
- EXPECT_TRUE(android_log_addFilterString(p_format, " ") == 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_WARN));
-
- // note trailing space
- EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:d ") == 0);
- EXPECT_TRUE(checkPriForTag(p_format, tag, ANDROID_LOG_DEBUG));
-
- EXPECT_TRUE(android_log_addFilterString(p_format, "*:s random:z") < 0);
-
-#if 0 // bitrot, seek update
- char defaultBuffer[512];
-
- android_log_formatLogLine(p_format,
- defaultBuffer, sizeof(defaultBuffer), 0, ANDROID_LOG_ERROR, 123,
- 123, 123, tag, "nofile", strlen("Hello"), "Hello", NULL);
-
- fprintf(stderr, "%s\n", defaultBuffer);
-#endif
-
- android_log_format_free(p_format);
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-TEST(liblog, is_loggable) {
-#ifdef __ANDROID__
- static const char tag[] = "is_loggable";
- static const char log_namespace[] = "persist.log.tag.";
- static const size_t base_offset = 8; /* skip "persist." */
- // sizeof("string") = strlen("string") + 1
- char key[sizeof(log_namespace) + sizeof(tag) - 1];
- char hold[4][PROP_VALUE_MAX];
- static const struct {
- int level;
- char type;
- } levels[] = {
- {ANDROID_LOG_VERBOSE, 'v'}, {ANDROID_LOG_DEBUG, 'd'},
- {ANDROID_LOG_INFO, 'i'}, {ANDROID_LOG_WARN, 'w'},
- {ANDROID_LOG_ERROR, 'e'}, {ANDROID_LOG_FATAL, 'a'},
- {ANDROID_LOG_SILENT, 's'}, {-2, 'g'}, // Illegal value, resort to default
- };
-
- // Set up initial test condition
- memset(hold, 0, sizeof(hold));
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- property_get(key, hold[0], "");
- property_set(key, "");
- property_get(key + base_offset, hold[1], "");
- property_set(key + base_offset, "");
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- property_get(key, hold[2], "");
- property_set(key, "");
- property_get(key, hold[3], "");
- property_set(key + base_offset, "");
-
- // All combinations of level and defaults
- for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- if (levels[j].level == -2) {
- continue;
- }
- fprintf(stderr, "i=%zu j=%zu\r", i, j);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1)) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), levels[j].level));
- }
- }
- }
- }
-
- // All combinations of level and tag and global properties
- for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- char buf[2];
- buf[0] = levels[j].type;
- buf[1] = '\0';
-
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
- buf);
- usleep(20000);
- property_set(key, buf);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
- key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
-
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
- buf);
- property_set(key, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
- key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_DEBUG) && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
- }
- }
-
- // All combinations of level and tag properties, but with global set to INFO
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- usleep(20000);
- property_set(key, "I");
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- for (size_t i = 0; i < (sizeof(levels) / sizeof(levels[0])); ++i) {
- if (levels[i].level == -2) {
- continue;
- }
- for (size_t j = 0; j < (sizeof(levels) / sizeof(levels[0])); ++j) {
- char buf[2];
- buf[0] = levels[j].type;
- buf[1] = '\0';
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j, key,
- buf);
- usleep(20000);
- property_set(key, buf);
- bool android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key, "");
-
- fprintf(stderr, "i=%zu j=%zu property_set(\"%s\",\"%s\")\r", i, j,
- key + base_offset, buf);
- property_set(key + base_offset, buf);
- android_log_is_loggable = __android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG);
- if ((levels[i].level < levels[j].level) || (levels[j].level == -1) ||
- ((levels[i].level < ANDROID_LOG_INFO) // Yes INFO
- && (levels[j].level == -2))) {
- if (android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_FALSE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_FALSE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- } else {
- if (!android_log_is_loggable) {
- fprintf(stderr, "\n");
- }
- EXPECT_TRUE(android_log_is_loggable);
- for (size_t k = 10; k; --k) {
- EXPECT_TRUE(__android_log_is_loggable_len(
- levels[i].level, tag, strlen(tag), ANDROID_LOG_DEBUG));
- }
- }
- usleep(20000);
- property_set(key + base_offset, "");
- }
- }
-
- // reset parms
- snprintf(key, sizeof(key), "%s%s", log_namespace, tag);
- usleep(20000);
- property_set(key, hold[0]);
- property_set(key + base_offset, hold[1]);
- strcpy(key, log_namespace);
- key[sizeof(log_namespace) - 2] = '\0';
- property_set(key, hold[2]);
- property_set(key + base_offset, hold[3]);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
-
-#ifdef ENABLE_FLAKY_TESTS
-// Following tests the specific issues surrounding error handling wrt logd.
-// Kills logd and toss all collected data, equivalent to logcat -b all -c,
-// except we also return errors to the logging callers.
-#ifdef __ANDROID__
-// helper to liblog.enoent to count end-to-end matching logging messages.
-static int count_matching_ts(log_time ts) {
- usleep(1000000);
-
- pid_t pid = getpid();
-
- struct logger_list* logger_list =
- android_logger_list_open(LOG_ID_EVENTS, ANDROID_LOG_NONBLOCK, 1000, pid);
-
- int count = 0;
- if (logger_list == NULL) return count;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
-
- if (log_msg.entry.len != sizeof(android_log_event_long_t)) continue;
- if (log_msg.id() != LOG_ID_EVENTS) continue;
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
- if (!eventData) continue;
- if (eventData->payload.type != EVENT_TYPE_LONG) continue;
-
- log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
- if (ts != tx) continue;
-
- // found event message with matching timestamp signature in payload
- ++count;
- }
- android_logger_list_close(logger_list);
-
- return count;
-}
-
-TEST(liblog, enoent) {
-#ifdef __ANDROID__
- if (getuid() != 0) {
- GTEST_SKIP() << "Skipping test, must be run as root.";
- return;
- }
-
- log_time ts(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- EXPECT_EQ(1, count_matching_ts(ts));
-
- // This call will fail unless we are root, beware of any
- // test prior to this one playing with setuid and causing interference.
- // We need to run before these tests so that they do not interfere with
- // this test.
- //
- // Stopping the logger can affect some other test's expectations as they
- // count on the log buffers filled with existing content, and this
- // effectively does a logcat -c emptying it. So we want this test to be
- // as near as possible to the bottom of the file. For example
- // liblog.android_logger_get_ is one of those tests that has no recourse
- // and that would be adversely affected by emptying the log if it was run
- // right after this test.
- system("stop logd");
- usleep(1000000);
-
- // A clean stop like we are testing returns -ENOENT, but in the _real_
- // world we could get -ENOTCONN or -ECONNREFUSED depending on timing.
- // Alas we can not test these other return values; accept that they
- // are treated equally within the open-retry logic in liblog.
- ts = log_time(CLOCK_MONOTONIC);
- int ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
- std::string content = android::base::StringPrintf(
- "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
- ret, (ret <= 0) ? strerror(-ret) : "(content sent)");
- EXPECT_TRUE(ret == -ENOENT || ret == -ENOTCONN || ret == -ECONNREFUSED) << content;
- ret = __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts));
- content = android::base::StringPrintf(
- "__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) = %d %s\n",
- ret, (ret <= 0) ? strerror(-ret) : "(content sent)");
- EXPECT_TRUE(ret == -ENOENT || ret == -ENOTCONN || ret == -ECONNREFUSED) << content;
- EXPECT_EQ(0, count_matching_ts(ts));
-
- system("start logd");
- usleep(1000000);
-
- EXPECT_EQ(0, count_matching_ts(ts));
-
- ts = log_time(CLOCK_MONOTONIC);
- EXPECT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
- EXPECT_EQ(1, count_matching_ts(ts));
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // __ANDROID__
-#endif // ENABLE_FLAKY_TESTS
-
-// Below this point we run risks of setuid(AID_SYSTEM) which may affect others.
-
-#ifdef ENABLE_FLAKY_TESTS
-// Do not retest properties, and cannot log into LOG_ID_SECURITY
-TEST(liblog, __security) {
-#ifdef __ANDROID__
- static const char persist_key[] = "persist.logd.security";
- static const char readonly_key[] = "ro.organization_owned";
- // A silly default value that can never be in readonly_key so
- // that it can be determined the property is not set.
- static const char nothing_val[] = "_NOTHING_TO_SEE_HERE_";
- char persist[PROP_VALUE_MAX];
- char persist_hold[PROP_VALUE_MAX];
- char readonly[PROP_VALUE_MAX];
-
- // First part of this test requires the test itself to have the appropriate
- // permissions. If we do not have them, we can not override them, so we
- // bail rather than give a failing grade.
- property_get(persist_key, persist, "");
- fprintf(stderr, "INFO: getprop %s -> %s\n", persist_key, persist);
- strncpy(persist_hold, persist, PROP_VALUE_MAX);
- property_get(readonly_key, readonly, nothing_val);
- fprintf(stderr, "INFO: getprop %s -> %s\n", readonly_key, readonly);
-
- if (!strcmp(readonly, nothing_val)) {
- // Lets check if we can set the value (we should not be allowed to do so)
- EXPECT_FALSE(__android_log_security());
- fprintf(stderr, "WARNING: setting ro.organization_owned to a domain\n");
- static const char domain[] = "com.google.android.SecOps.DeviceOwner";
- EXPECT_NE(0, property_set(readonly_key, domain));
- useconds_t total_time = 0;
- static const useconds_t seconds = 1000000;
- static const useconds_t max_time = 5 * seconds; // not going to happen
- static const useconds_t rest = 20 * 1000;
- for (; total_time < max_time; total_time += rest) {
- usleep(rest); // property system does not guarantee performance.
- property_get(readonly_key, readonly, nothing_val);
- if (!strcmp(readonly, domain)) {
- if (total_time > rest) {
- fprintf(stderr, "INFO: took %u.%06u seconds to set property\n",
- (unsigned)(total_time / seconds),
- (unsigned)(total_time % seconds));
- }
- break;
- }
- }
- EXPECT_STRNE(domain, readonly);
- }
-
- if (!strcasecmp(readonly, "false") || !readonly[0] ||
- !strcmp(readonly, nothing_val)) {
- // not enough permissions to run tests surrounding persist.logd.security
- EXPECT_FALSE(__android_log_security());
- return;
- }
-
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "TRUE");
- property_get(persist_key, persist, "");
- uid_t uid = getuid();
- gid_t gid = getgid();
- bool perm = (gid == AID_ROOT) || (uid == AID_ROOT);
- EXPECT_STREQ(perm ? "TRUE" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "FALSE");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "FALSE" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "true");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "true" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "false");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "false" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, "");
- property_get(persist_key, persist, "");
- EXPECT_STREQ(perm ? "" : persist_hold, persist);
- if (!strcasecmp(persist, "true")) {
- EXPECT_TRUE(__android_log_security());
- } else {
- EXPECT_FALSE(__android_log_security());
- }
- property_set(persist_key, persist_hold);
- property_get(persist_key, persist, "");
- EXPECT_STREQ(persist_hold, persist);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __security_buffer) {
-#ifdef __ANDROID__
- struct logger_list* logger_list;
- android_event_long_t buffer;
-
- static const char persist_key[] = "persist.logd.security";
- char persist[PROP_VALUE_MAX];
- bool set_persist = false;
- bool allow_security = false;
-
- if (__android_log_security()) {
- allow_security = true;
- } else {
- property_get(persist_key, persist, "");
- if (strcasecmp(persist, "true")) {
- property_set(persist_key, "TRUE");
- if (__android_log_security()) {
- allow_security = true;
- set_persist = true;
- } else {
- property_set(persist_key, persist);
- }
- }
- }
-
- if (!allow_security) {
- fprintf(stderr,
- "WARNING: "
- "security buffer disabled, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t*>((void*)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- /* Matches clientHasLogCredentials() in logd */
- uid_t uid = getuid();
- gid_t gid = getgid();
- bool clientHasLogCredentials = true;
- if ((uid != AID_SYSTEM) && (uid != AID_ROOT) && (uid != AID_LOG) &&
- (gid != AID_SYSTEM) && (gid != AID_ROOT) && (gid != AID_LOG)) {
- uid_t euid = geteuid();
- if ((euid != AID_SYSTEM) && (euid != AID_ROOT) && (euid != AID_LOG)) {
- gid_t egid = getegid();
- if ((egid != AID_SYSTEM) && (egid != AID_ROOT) && (egid != AID_LOG)) {
- int num_groups = getgroups(0, NULL);
- if (num_groups > 0) {
- gid_t groups[num_groups];
- num_groups = getgroups(num_groups, groups);
- while (num_groups > 0) {
- if (groups[num_groups - 1] == AID_LOG) {
- break;
- }
- --num_groups;
- }
- }
- if (num_groups <= 0) {
- clientHasLogCredentials = false;
- }
- }
- }
- }
- if (!clientHasLogCredentials) {
- fprintf(stderr,
- "WARNING: "
- "not in system context, bypassing end-to-end test\n");
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t*>((void*)&ts));
-
- // expect failure!
- ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
-
- return;
- }
-
- EXPECT_EQ(0, setuid(AID_SYSTEM)); // only one that can read security buffer
-
- uid = getuid();
- gid = getgid();
- pid_t pid = getpid();
-
- ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(LOG_ID_SECURITY, ANDROID_LOG_NONBLOCK,
- 1000, pid)));
-
- log_time ts(CLOCK_MONOTONIC);
-
- buffer.type = EVENT_TYPE_LONG;
- buffer.data = *(static_cast<uint64_t*>((void*)&ts));
-
- ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
- usleep(1000000);
-
- int count = 0;
-
- for (;;) {
- log_msg log_msg;
- if (android_logger_list_read(logger_list, &log_msg) <= 0) {
- break;
- }
-
- ASSERT_EQ(log_msg.entry.pid, pid);
-
- if ((log_msg.entry.len != sizeof(android_log_event_long_t)) ||
- (log_msg.id() != LOG_ID_SECURITY)) {
- continue;
- }
-
- android_log_event_long_t* eventData;
- eventData = reinterpret_cast<android_log_event_long_t*>(log_msg.msg());
-
- if (!eventData || (eventData->payload.type != EVENT_TYPE_LONG)) {
- continue;
- }
-
- log_time tx(reinterpret_cast<char*>(&eventData->payload.data));
- if (ts == tx) {
- ++count;
- }
- }
-
- if (set_persist) {
- property_set(persist_key, persist);
- }
-
- android_logger_list_close(logger_list);
-
- bool clientHasSecurityCredentials = (uid == AID_SYSTEM) || (gid == AID_SYSTEM);
- if (!clientHasSecurityCredentials) {
- fprintf(stderr,
- "WARNING: "
- "not system, content submitted but can not check end-to-end\n");
- }
- EXPECT_EQ(clientHasSecurityCredentials ? 1 : 0, count);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
-
-#ifdef __ANDROID__
-static void android_errorWriteWithInfoLog_helper(int tag, const char* subtag, int uid,
- const char* payload, int data_len) {
- auto write_function = [&] {
- int ret = android_errorWriteWithInfoLog(tag, subtag, uid, payload, data_len);
- ASSERT_LT(0, ret);
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* event_data = log_msg.msg();
- char* original = event_data;
-
- // Tag
- auto* event_header = reinterpret_cast<android_event_header_t*>(event_data);
- event_data += sizeof(android_event_header_t);
- if (event_header->tag != tag) {
- return;
- }
-
- // List type
- auto* event_list = reinterpret_cast<android_event_list_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_LIST, event_list->type);
- ASSERT_EQ(3, event_list->element_count);
- event_data += sizeof(android_event_list_t);
-
- // Element #1: string type for subtag
- auto* event_string_subtag = reinterpret_cast<android_event_string_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_STRING, event_string_subtag->type);
- int32_t subtag_len = strlen(subtag);
- if (subtag_len > 32) {
- subtag_len = 32;
- }
- ASSERT_EQ(subtag_len, event_string_subtag->length);
- if (memcmp(subtag, &event_string_subtag->data, subtag_len)) {
- return;
- }
- event_data += sizeof(android_event_string_t) + subtag_len;
-
- // Element #2: int type for uid
- auto* event_int_uid = reinterpret_cast<android_event_int_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_INT, event_int_uid->type);
- ASSERT_EQ(uid, event_int_uid->data);
- event_data += sizeof(android_event_int_t);
-
- // Element #3: string type for data
- auto* event_string_data = reinterpret_cast<android_event_string_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_STRING, event_string_data->type);
- int32_t message_data_len = event_string_data->length;
- if (data_len < 512) {
- ASSERT_EQ(data_len, message_data_len);
- }
- if (memcmp(payload, &event_string_data->data, message_data_len) != 0) {
- return;
- }
- event_data += sizeof(android_event_string_t);
-
- if (data_len >= 512) {
- event_data += message_data_len;
- // 4 bytes for the tag, and max_payload_buf should be truncated.
- ASSERT_LE(4 + 512, event_data - original); // worst expectations
- ASSERT_GT(4 + data_len, event_data - original); // must be truncated
- }
- *found = true;
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-}
-#endif
-
-// Make multiple tests and re-tests orthogonal to prevent falsing.
-#ifdef TEST_LOGGER
-#define UNIQUE_TAG(X) \
- (0x12340000 + (((X) + sizeof(int) + sizeof(void*)) << 8) + TEST_LOGGER)
-#else
-#define UNIQUE_TAG(X) \
- (0x12340000 + (((X) + sizeof(int) + sizeof(void*)) << 8) + 0xBA)
-#endif
-
-TEST(liblog, android_errorWriteWithInfoLog__android_logger_list_read__typical) {
-#ifdef __ANDROID__
- android_errorWriteWithInfoLog_helper(UNIQUE_TAG(1), "test-subtag", -1, max_payload_buf, 200);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog,
- android_errorWriteWithInfoLog__android_logger_list_read__data_too_large) {
-#ifdef __ANDROID__
- android_errorWriteWithInfoLog_helper(UNIQUE_TAG(2), "test-subtag", -1, max_payload_buf,
- sizeof(max_payload_buf));
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog,
- android_errorWriteWithInfoLog__android_logger_list_read__null_data) {
-#ifdef __ANDROID__
- int retval_android_errorWriteWithinInfoLog =
- android_errorWriteWithInfoLog(UNIQUE_TAG(3), "test-subtag", -1, nullptr, 200);
- ASSERT_GT(0, retval_android_errorWriteWithinInfoLog);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog,
- android_errorWriteWithInfoLog__android_logger_list_read__subtag_too_long) {
-#ifdef __ANDROID__
- android_errorWriteWithInfoLog_helper(
- UNIQUE_TAG(4), "abcdefghijklmnopqrstuvwxyz now i know my abc", -1, max_payload_buf, 200);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, __android_log_bswrite_and_print___max) {
- bswrite_test(max_payload_buf);
-}
-
-TEST(liblog, __android_log_buf_write_and_print__max) {
- buf_write_test(max_payload_buf);
-}
-
-TEST(liblog, android_errorWriteLog__android_logger_list_read__success) {
-#ifdef __ANDROID__
- int kTag = UNIQUE_TAG(5);
- const char* kSubTag = "test-subtag";
-
- auto write_function = [&] {
- int retval_android_errorWriteLog = android_errorWriteLog(kTag, kSubTag);
- ASSERT_LT(0, retval_android_errorWriteLog);
- };
-
- auto check_function = [&](log_msg log_msg, bool* found) {
- char* event_data = log_msg.msg();
-
- // Tag
- auto* event_header = reinterpret_cast<android_event_header_t*>(event_data);
- event_data += sizeof(android_event_header_t);
- if (event_header->tag != kTag) {
- return;
- }
-
- // List type
- auto* event_list = reinterpret_cast<android_event_list_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_LIST, event_list->type);
- ASSERT_EQ(3, event_list->element_count);
- event_data += sizeof(android_event_list_t);
-
- // Element #1: string type for subtag
- auto* event_string_subtag = reinterpret_cast<android_event_string_t*>(event_data);
- ASSERT_EQ(EVENT_TYPE_STRING, event_string_subtag->type);
- int32_t subtag_len = strlen(kSubTag);
- ASSERT_EQ(subtag_len, event_string_subtag->length);
- if (memcmp(kSubTag, &event_string_subtag->data, subtag_len) == 0) {
- *found = true;
- }
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, android_errorWriteLog__android_logger_list_read__null_subtag) {
-#ifdef __ANDROID__
- EXPECT_LT(android_errorWriteLog(UNIQUE_TAG(6), nullptr), 0);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-// Do not retest logger list handling
-#ifdef __ANDROID__
-static int is_real_element(int type) {
- return ((type == EVENT_TYPE_INT) || (type == EVENT_TYPE_LONG) ||
- (type == EVENT_TYPE_STRING) || (type == EVENT_TYPE_FLOAT));
-}
-
-static int android_log_buffer_to_string(const char* msg, size_t len,
- char* strOut, size_t strOutLen) {
- android_log_context context = create_android_log_parser(msg, len);
- android_log_list_element elem;
- bool overflow = false;
- /* Reserve 1 byte for null terminator. */
- size_t origStrOutLen = strOutLen--;
-
- if (!context) {
- return -EBADF;
- }
-
- memset(&elem, 0, sizeof(elem));
-
- size_t outCount;
-
- do {
- elem = android_log_read_next(context);
- switch ((int)elem.type) {
- case EVENT_TYPE_LIST:
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = '[';
- strOutLen--;
- }
- break;
-
- case EVENT_TYPE_LIST_STOP:
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = ']';
- strOutLen--;
- }
- break;
-
- case EVENT_TYPE_INT:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1, "%" PRId32, elem.data.int32);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
-
- case EVENT_TYPE_LONG:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1, "%" PRId64, elem.data.int64);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
-
- case EVENT_TYPE_FLOAT:
- /*
- * snprintf also requires room for the null terminator, which
- * we don't care about but we have allocated enough room for
- * that
- */
- outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
- if (outCount <= strOutLen) {
- strOut += outCount;
- strOutLen -= outCount;
- } else {
- overflow = true;
- }
- break;
-
- default:
- elem.complete = true;
- break;
-
- case EVENT_TYPE_UNKNOWN:
-#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
- if (elem.complete) {
- break;
- }
-#endif
- elem.data.string = const_cast<char*>("<unknown>");
- elem.len = strlen(elem.data.string);
- FALLTHROUGH_INTENDED;
- case EVENT_TYPE_STRING:
- if (elem.len <= strOutLen) {
- memcpy(strOut, elem.data.string, elem.len);
- strOut += elem.len;
- strOutLen -= elem.len;
- } else if (strOutLen > 0) {
- /* copy what we can */
- memcpy(strOut, elem.data.string, strOutLen);
- strOut += strOutLen;
- strOutLen = 0;
- overflow = true;
- }
- break;
- }
-
- if (elem.complete) {
- break;
- }
- /* Determine whether to put a comma or not. */
- if (!overflow &&
- (is_real_element(elem.type) || (elem.type == EVENT_TYPE_LIST_STOP))) {
- android_log_list_element next = android_log_peek_next(context);
- if (!next.complete &&
- (is_real_element(next.type) || (next.type == EVENT_TYPE_LIST))) {
- if (strOutLen == 0) {
- overflow = true;
- } else {
- *strOut++ = ',';
- strOutLen--;
- }
- }
- }
- } while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
-
- android_log_destroy(&context);
-
- if (overflow) {
- if (strOutLen < origStrOutLen) {
- /* leave an indicator */
- *(strOut - 1) = '!';
- } else {
- /* nothing was written at all */
- *strOut++ = '!';
- }
- }
- *strOut++ = '\0';
-
- if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
- fprintf(stderr, "Binary log entry conversion failed\n");
- return -EINVAL;
- }
-
- return 0;
-}
-#endif // __ANDROID__
-
-#ifdef __ANDROID__
-static const char* event_test_int32(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t);
-
- return "1076895760";
-}
-
-static const char* event_test_int64(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint64_t);
-
- return "-9191740941672636400";
-}
-
-static const char* event_test_list_int64(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint64_t);
-
- return "[-9191740941672636400]";
-}
-
-static const char* event_test_simple_automagic_list(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- // The convenience API where we allow a simple list to be
- // created without explicit begin or end calls.
- EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
- sizeof(uint64_t);
-
- return "[1076895760,-9191740941672636400]";
-}
-
-static const char* event_test_list_empty(uint32_t tag, size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t);
-
- return "[]";
-}
-
-static const char* event_test_complex_nested_list(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
-
- EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
- EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
- EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
- EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
- EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
- EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
- EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
-
- //
- // This one checks for the automagic list creation because a list
- // begin and end was missing for it! This is actually an <oops> corner
- // case, and not the behavior we morally support. The automagic API is to
- // allow for a simple case of a series of objects in a single list. e.g.
- // int32,int32,int32,string -> [int32,int32,int32,string]
- //
- EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
-
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint64_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
- 1 + sizeof(uint8_t) + sizeof(uint8_t) +
- 4 * (sizeof(uint8_t) + sizeof(uint32_t)) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint32_t) +
- sizeof("dlroW olleH") - 1;
-
- return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW "
- "olleH]";
-}
-
-static const char* event_test_7_level_prefix(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 5));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 6));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 7));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + 7 * (sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t));
-
- return "[[[[[[[1],2],3],4],5],6],7]";
-}
-
-static const char* event_test_7_level_suffix(uint32_t tag,
- size_t& expected_len) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
- if (!ctx) {
- return NULL;
- }
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 1));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 2));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 3));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 4));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 5));
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, 6));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list_end(ctx));
- EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
-
- expected_len = sizeof(uint32_t) + 6 * (sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t));
-
- return "[1,[2,[3,[4,[5,[6]]]]]]";
-}
-
-static const char* event_test_android_log_error_write(uint32_t tag,
- size_t& expected_len) {
- EXPECT_LE(
- 0, __android_log_error_write(tag, "Hello World", 42, "dlroW olleH", 11));
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
- 1 + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof("dlroW olleH") - 1;
-
- return "[Hello World,42,dlroW olleH]";
-}
-
-static const char* event_test_android_log_error_write_null(uint32_t tag,
- size_t& expected_len) {
- EXPECT_LE(0, __android_log_error_write(tag, "Hello World", 42, NULL, 0));
-
- expected_len = sizeof(uint32_t) + sizeof(uint8_t) + sizeof(uint8_t) +
- sizeof(uint8_t) + sizeof(uint32_t) + sizeof("Hello World") -
- 1 + sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t) +
- sizeof(uint32_t) + sizeof("") - 1;
-
- return "[Hello World,42,]";
-}
-
-// make sure all user buffers are flushed
-static void print_barrier() {
- std::cout.flush();
- fflush(stdout);
- std::cerr.flush();
- fflush(stderr); // everything else is paranoia ...
-}
-
-static void create_android_logger(const char* (*fn)(uint32_t tag,
- size_t& expected_len)) {
- size_t expected_len;
- const char* expected_string;
- auto write_function = [&] {
- expected_string = (*fn)(1005, expected_len);
- ASSERT_NE(nullptr, expected_string);
- };
-
- pid_t pid = getpid();
- auto check_function = [&](log_msg log_msg, bool* found) {
- if (static_cast<size_t>(log_msg.entry.len) != expected_len) {
- return;
- }
-
- char* eventData = log_msg.msg();
-
- AndroidLogFormat* logformat = android_log_format_new();
- EXPECT_TRUE(NULL != logformat);
- AndroidLogEntry entry;
- char msgBuf[1024];
- int processBinaryLogBuffer =
- android_log_processBinaryLogBuffer(&log_msg.entry, &entry, nullptr, msgBuf, sizeof(msgBuf));
- EXPECT_EQ(0, processBinaryLogBuffer);
- if (processBinaryLogBuffer == 0) {
- int line_overhead = 20;
- if (pid > 99999) ++line_overhead;
- if (pid > 999999) ++line_overhead;
- print_barrier();
- int printLogLine =
- android_log_printLogLine(logformat, fileno(stderr), &entry);
- print_barrier();
- EXPECT_EQ(line_overhead + (int)strlen(expected_string), printLogLine);
- }
- android_log_format_free(logformat);
-
- // test buffer reading API
- int buffer_to_string = -1;
- if (eventData) {
- auto* event_header = reinterpret_cast<android_event_header_t*>(eventData);
- eventData += sizeof(android_event_header_t);
- snprintf(msgBuf, sizeof(msgBuf), "I/[%" PRId32 "]", event_header->tag);
- print_barrier();
- fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
- memset(msgBuf, 0, sizeof(msgBuf));
- buffer_to_string =
- android_log_buffer_to_string(eventData, log_msg.entry.len, msgBuf, sizeof(msgBuf));
- fprintf(stderr, "%s\n", msgBuf);
- print_barrier();
- }
- EXPECT_EQ(0, buffer_to_string);
- EXPECT_STREQ(expected_string, msgBuf);
- *found = true;
- };
-
- RunLogTests(LOG_ID_EVENTS, write_function, check_function);
-}
-#endif
-
-TEST(liblog, create_android_logger_int32) {
-#ifdef __ANDROID__
- create_android_logger(event_test_int32);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_int64) {
-#ifdef __ANDROID__
- create_android_logger(event_test_int64);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_list_int64) {
-#ifdef __ANDROID__
- create_android_logger(event_test_list_int64);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_simple_automagic_list) {
-#ifdef __ANDROID__
- create_android_logger(event_test_simple_automagic_list);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_list_empty) {
-#ifdef __ANDROID__
- create_android_logger(event_test_list_empty);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_complex_nested_list) {
-#ifdef __ANDROID__
- create_android_logger(event_test_complex_nested_list);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_7_level_prefix) {
-#ifdef __ANDROID__
- create_android_logger(event_test_7_level_prefix);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_7_level_suffix) {
-#ifdef __ANDROID__
- create_android_logger(event_test_7_level_suffix);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_android_log_error_write) {
-#ifdef __ANDROID__
- create_android_logger(event_test_android_log_error_write);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_android_log_error_write_null) {
-#ifdef __ANDROID__
- create_android_logger(event_test_android_log_error_write_null);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(liblog, create_android_logger_overflow) {
- android_log_context ctx;
-
- EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
- if (ctx) {
- for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- }
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- /* One more for good measure, must be permanently unhappy */
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_destroy(&ctx));
- EXPECT_TRUE(NULL == ctx);
- }
-
- ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
- for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
- EXPECT_LE(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_write_int32(ctx, i));
- }
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- /* One more for good measure, must be permanently unhappy */
- EXPECT_GT(0, android_log_write_list_begin(ctx));
- EXPECT_LE(0, android_log_destroy(&ctx));
- ASSERT_TRUE(NULL == ctx);
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
-static const char __pmsg_file[] =
- "/data/william-shakespeare/MuchAdoAboutNothing.txt";
-#endif /* NO_PSTORE */
-#endif
-
-TEST(liblog, __android_log_pmsg_file_write) {
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
- __android_log_close();
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
- int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
- LOG_ID_CRASH, ANDROID_LOG_VERBOSE, __pmsg_file, max_payload_buf,
- sizeof(max_payload_buf));
- EXPECT_LT(0, return__android_log_pmsg_file_write);
- if (return__android_log_pmsg_file_write == -ENOMEM) {
- fprintf(stderr,
- "Kernel does not have space allocated to pmsg pstore driver "
- "configured\n");
- } else if (!return__android_log_pmsg_file_write) {
- fprintf(stderr,
- "Reboot, ensure file %s matches\n"
- "with liblog.__android_log_msg_file_read test\n",
- __pmsg_file);
- }
- bool pmsgActiveAfter__android_pmsg_file_write;
- bool logdwActiveAfter__android_pmsg_file_write;
- if (getuid() == AID_ROOT) {
- pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
- logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
- EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
- }
- EXPECT_LT(
- 0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_pmsg_file_write", "main"));
- if (getuid() == AID_ROOT) {
- bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
- bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
- EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
- }
- EXPECT_LT(0, __android_log_pmsg_file_write(LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, max_payload_buf,
- sizeof(max_payload_buf)));
- if (getuid() == AID_ROOT) {
- pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
- logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
- EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
- EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
- }
-#else /* NO_PSTORE */
- GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
-#endif /* NO_PSTORE */
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
-static ssize_t __pmsg_fn(log_id_t logId, char prio, const char* filename,
- const char* buf, size_t len, void* arg) {
- EXPECT_TRUE(NULL == arg);
- EXPECT_EQ(LOG_ID_CRASH, logId);
- EXPECT_EQ(ANDROID_LOG_VERBOSE, prio);
- EXPECT_FALSE(NULL == strstr(__pmsg_file, filename));
- EXPECT_EQ(len, sizeof(max_payload_buf));
- EXPECT_STREQ(max_payload_buf, buf);
-
- ++signaled;
- if ((len != sizeof(max_payload_buf)) || strcmp(max_payload_buf, buf)) {
- fprintf(stderr, "comparison fails on content \"%s\"\n", buf);
- }
- return arg || (LOG_ID_CRASH != logId) || (ANDROID_LOG_VERBOSE != prio) ||
- !strstr(__pmsg_file, filename) ||
- (len != sizeof(max_payload_buf)) ||
- !!strcmp(max_payload_buf, buf)
- ? -ENOEXEC
- : 1;
-}
-#endif /* NO_PSTORE */
-#endif
-
-TEST(liblog, __android_log_pmsg_file_read) {
-#ifdef __ANDROID__
-#ifndef NO_PSTORE
- signaled = 0;
-
- __android_log_close();
- if (getuid() == AID_ROOT) {
- tested__android_log_close = true;
- bool pmsgActiveAfter__android_log_close = isPmsgActive();
- bool logdwActiveAfter__android_log_close = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_close);
- EXPECT_FALSE(logdwActiveAfter__android_log_close);
- } else if (!tested__android_log_close) {
- fprintf(stderr, "WARNING: can not test __android_log_close()\n");
- }
-
- ssize_t ret = __android_log_pmsg_file_read(LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
- __pmsg_file, __pmsg_fn, NULL);
-
- if (getuid() == AID_ROOT) {
- bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
- bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
- EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
- EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
- }
-
- if (ret == -ENOENT) {
- fprintf(stderr,
- "No pre-boot results of liblog.__android_log_mesg_file_write to "
- "compare with,\n"
- "false positive test result.\n");
- return;
- }
-
- EXPECT_LT(0, ret);
- EXPECT_EQ(1U, signaled);
-#else /* NO_PSTORE */
- GTEST_LOG_(INFO) << "This test does nothing because of NO_PSTORE.\n";
-#endif /* NO_PSTORE */
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif // ENABLE_FLAKY_TESTS
diff --git a/liblog/tests/log_id_test.cpp b/liblog/tests/log_id_test.cpp
deleted file mode 100644
index 9fb5a2c..0000000
--- a/liblog/tests/log_id_test.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2013-2017 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 <inttypes.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_id.h>
-
-// We do not want to include <android/log.h> to acquire ANDROID_LOG_INFO for
-// include file API purity. We do however want to allow the _option_ that
-// log/log_id.h could include this file, or related content, in the future.
-#ifndef __android_LogPriority_defined
-#define ANDROID_LOG_INFO 4
-#endif
-
-TEST(liblog, log_id) {
- int count = 0;
-
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- log_id_t id = static_cast<log_id_t>(i);
- const char* name = android_log_id_to_name(id);
- if (id != android_name_to_log_id(name)) {
- continue;
- }
- ++count;
- fprintf(stderr, "log buffer %s\r", name);
- }
- ASSERT_EQ(LOG_ID_MAX, count);
-}
-
-TEST(liblog, __android_log_buf_print) {
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print", "radio"));
- usleep(1000);
- EXPECT_LT(0,
- __android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print", "system"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_buf_print", "main"));
- usleep(1000);
-}
-
-TEST(liblog, __android_log_buf_write) {
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_RADIO, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write", "radio"));
- usleep(1000);
- EXPECT_LT(0,
- __android_log_buf_write(LOG_ID_SYSTEM, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write", "system"));
- usleep(1000);
- EXPECT_LT(0, __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_INFO,
- "TEST__android_log_buf_write", "main"));
- usleep(1000);
-}
-
-static void* ConcurrentPrintFn(void* arg) {
- int ret = __android_log_buf_print(
- LOG_ID_MAIN, ANDROID_LOG_INFO, "TEST__android_log_print",
- "Concurrent %" PRIuPTR, reinterpret_cast<uintptr_t>(arg));
- return reinterpret_cast<void*>(ret);
-}
-
-#define NUM_CONCURRENT 64
-#define _concurrent_name(a, n) a##__concurrent##n
-#define concurrent_name(a, n) _concurrent_name(a, n)
-
-TEST(liblog, concurrent_name(__android_log_buf_print, NUM_CONCURRENT)) {
- pthread_t t[NUM_CONCURRENT];
- int i;
- for (i = 0; i < NUM_CONCURRENT; i++) {
- ASSERT_EQ(0, pthread_create(&t[i], NULL, ConcurrentPrintFn,
- reinterpret_cast<void*>(i)));
- }
- int ret = 1;
- for (i = 0; i < NUM_CONCURRENT; i++) {
- void* result;
- ASSERT_EQ(0, pthread_join(t[i], &result));
- int this_result = reinterpret_cast<uintptr_t>(result);
- if ((0 < ret) && (ret != this_result)) {
- ret = this_result;
- }
- }
- ASSERT_LT(0, ret);
-}
diff --git a/liblog/tests/log_radio_test.cpp b/liblog/tests/log_radio_test.cpp
deleted file mode 100644
index fa1255e..0000000
--- a/liblog/tests/log_radio_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 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 <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_radio.h>
-
-TEST(liblog, RLOG) {
- static const char content[] = "log_radio.h";
- static const char content_false[] = "log_radio.h false";
-
-// ratelimit content to 10/s to keep away from spam filters
-// do not send identical content together to keep away from spam filters
-
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGV"
- RLOGV(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGD"
- RLOGD(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGI"
- RLOGI(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGW"
- RLOGW(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGE"
- RLOGE(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGV"
- RLOGV_IF(true, content);
- usleep(100000);
- RLOGV_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGD"
- RLOGD_IF(true, content);
- usleep(100000);
- RLOGD_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGI"
- RLOGI_IF(true, content);
- usleep(100000);
- RLOGI_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGW"
- RLOGW_IF(true, content);
- usleep(100000);
- RLOGW_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__RLOGE"
- RLOGE_IF(true, content);
- usleep(100000);
- RLOGE_IF(false, content_false);
-
-#ifdef __ANDROID__
- // give time for content to long-path through logger
- sleep(1);
-
- std::string buf = android::base::StringPrintf(
- "logcat -b radio --pid=%u -d -s"
- " TEST__RLOGV TEST__RLOGD TEST__RLOGI TEST__RLOGW TEST__RLOGE",
- (unsigned)getpid());
- FILE* fp = popen(buf.c_str(), "re");
- int count = 0;
- int count_false = 0;
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
- pclose(fp);
- for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos;
- ++pos) {
- ++count;
- }
- for (size_t pos = 0;
- (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
- ++count_false;
- }
- }
- EXPECT_EQ(0, count_false);
-#if LOG_NDEBUG
- ASSERT_EQ(8, count);
-#else
- ASSERT_EQ(10, count);
-#endif
-
-#else
- GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
-#endif
-}
diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp
deleted file mode 100644
index 7acd363..0000000
--- a/liblog/tests/log_read_test.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2013-2017 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 <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android/log.h> // minimal logging API
-#include <gtest/gtest.h>
-#include <log/log_properties.h>
-// Test the APIs in this standalone include file
-#include <log/log_read.h>
-// Do not use anything in log/log_time.h despite side effects of the above.
-#include <private/android_logger.h>
-
-using android::base::GetBoolProperty;
-
-TEST(liblog, android_logger_get_) {
-#ifdef __ANDROID__
- // This test assumes the log buffers are filled with noise from
- // normal operations. It will fail if done immediately after a
- // logcat -c.
- struct logger_list* logger_list = android_logger_list_alloc(0, 0, 0);
-
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- log_id_t id = static_cast<log_id_t>(i);
- std::string name = android_log_id_to_name(id);
- fprintf(stderr, "log buffer %s\r", name.c_str());
- struct logger* logger;
- EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id)));
- EXPECT_EQ(id, android_logger_get_id(logger));
- ssize_t get_log_size = android_logger_get_log_size(logger);
- /* security buffer is allowed to be denied */
- if (name != "security") {
- EXPECT_GT(get_log_size, 0);
- // crash buffer is allowed to be empty, that is actually healthy!
- // stats buffer is no longer in use.
- if (name == "crash" || name == "stats") {
- continue;
- }
-
- // kernel buffer is empty if ro.logd.kernel is false
- if (name == "kernel" && !GetBoolProperty("ro.logd.kernel", false)) {
- continue;
- }
-
- EXPECT_LE(0, android_logger_get_log_readable_size(logger));
- } else {
- EXPECT_NE(0, get_log_size);
- if (get_log_size < 0) {
- EXPECT_GT(0, android_logger_get_log_readable_size(logger));
- } else {
- EXPECT_LE(0, android_logger_get_log_readable_size(logger));
- }
- }
- }
-
- android_logger_list_close(logger_list);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/liblog/tests/log_system_test.cpp b/liblog/tests/log_system_test.cpp
deleted file mode 100644
index 13f026d..0000000
--- a/liblog/tests/log_system_test.cpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2017 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 <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_system.h>
-
-TEST(liblog, SLOG) {
- static const char content[] = "log_system.h";
- static const char content_false[] = "log_system.h false";
-
-// ratelimit content to 10/s to keep away from spam filters
-// do not send identical content together to keep away from spam filters
-
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGV"
- SLOGV(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGD"
- SLOGD(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGI"
- SLOGI(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGW"
- SLOGW(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGE"
- SLOGE(content);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGV"
- SLOGV_IF(true, content);
- usleep(100000);
- SLOGV_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGD"
- SLOGD_IF(true, content);
- usleep(100000);
- SLOGD_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGI"
- SLOGI_IF(true, content);
- usleep(100000);
- SLOGI_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGW"
- SLOGW_IF(true, content);
- usleep(100000);
- SLOGW_IF(false, content_false);
- usleep(100000);
-#undef LOG_TAG
-#define LOG_TAG "TEST__SLOGE"
- SLOGE_IF(true, content);
- usleep(100000);
- SLOGE_IF(false, content_false);
-
-#ifdef __ANDROID__
- // give time for content to long-path through logger
- sleep(1);
-
- std::string buf = android::base::StringPrintf(
- "logcat -b system --pid=%u -d -s"
- " TEST__SLOGV TEST__SLOGD TEST__SLOGI TEST__SLOGW TEST__SLOGE",
- (unsigned)getpid());
- FILE* fp = popen(buf.c_str(), "re");
- int count = 0;
- int count_false = 0;
- if (fp) {
- if (!android::base::ReadFdToString(fileno(fp), &buf)) buf = "";
- pclose(fp);
- for (size_t pos = 0; (pos = buf.find(content, pos)) != std::string::npos;
- ++pos) {
- ++count;
- }
- for (size_t pos = 0;
- (pos = buf.find(content_false, pos)) != std::string::npos; ++pos) {
- ++count_false;
- }
- }
- EXPECT_EQ(0, count_false);
-#if LOG_NDEBUG
- ASSERT_EQ(8, count);
-#else
- ASSERT_EQ(10, count);
-#endif
-
-#else
- GTEST_LOG_(INFO) << "This test does not test end-to-end.\n";
-#endif
-}
diff --git a/liblog/tests/log_time_test.cpp b/liblog/tests/log_time_test.cpp
deleted file mode 100644
index 47fe594..0000000
--- a/liblog/tests/log_time_test.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2017 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 <time.h>
-
-#include <gtest/gtest.h>
-// Test the APIs in this standalone include file
-#include <log/log_time.h>
-
-TEST(liblog, log_time) {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- log_time tl(ts);
-
- EXPECT_EQ(tl, ts);
- EXPECT_GE(tl, ts);
- EXPECT_LE(tl, ts);
-}
diff --git a/liblog/tests/log_wrap_test.cpp b/liblog/tests/log_wrap_test.cpp
deleted file mode 100644
index 755898a..0000000
--- a/liblog/tests/log_wrap_test.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2013-2017 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 <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/chrono_utils.h>
-#include <android-base/stringprintf.h>
-#include <android/log.h> // minimal logging API
-#include <gtest/gtest.h>
-#include <log/log_properties.h>
-#include <log/log_read.h>
-#include <log/log_time.h>
-
-#ifdef __ANDROID__
-static void read_with_wrap() {
- // Read the last line in the log to get a starting timestamp. We're assuming
- // the log is not empty.
- const int mode = ANDROID_LOG_NONBLOCK;
- struct logger_list* logger_list =
- android_logger_list_open(LOG_ID_MAIN, mode, 1000, 0);
-
- ASSERT_NE(logger_list, nullptr);
-
- log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- android_logger_list_close(logger_list);
- ASSERT_GT(ret, 0);
-
- log_time start(log_msg.entry.sec, log_msg.entry.nsec);
- ASSERT_NE(start, log_time());
-
- logger_list =
- android_logger_list_alloc_time(mode | ANDROID_LOG_WRAP, start, 0);
- ASSERT_NE(logger_list, nullptr);
-
- struct logger* logger = android_logger_open(logger_list, LOG_ID_MAIN);
- EXPECT_NE(logger, nullptr);
- if (logger) {
- android_logger_list_read(logger_list, &log_msg);
- }
-
- android_logger_list_close(logger_list);
-}
-#endif
-
-// b/64143705 confirm fixed
-TEST(liblog, wrap_mode_blocks) {
-#ifdef __ANDROID__
- // The read call is expected to take up to 2 hours in the happy case. There was a previous bug
- // where it would take only 30 seconds due to an alarm() in logd_reader.cpp. That alarm has been
- // removed, so we check here that the read call blocks for a reasonable amount of time (5s).
-
- struct sigaction ignore = {.sa_handler = [](int) { _exit(0); }};
- struct sigaction old_sigaction;
- sigaction(SIGALRM, &ignore, &old_sigaction);
- alarm(5);
-
- android::base::Timer timer;
- read_with_wrap();
-
- FAIL() << "read_with_wrap() should not return before the alarm is triggered.";
-
- alarm(0);
- sigaction(SIGALRM, &old_sigaction, nullptr);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/liblog/tests/logd_writer_test.cpp b/liblog/tests/logd_writer_test.cpp
deleted file mode 100644
index b8e4726..0000000
--- a/liblog/tests/logd_writer_test.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2020 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 <sys/un.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <gtest/gtest.h>
-
-using android::base::StringPrintf;
-using android::base::unique_fd;
-
-// logd_writer takes advantage of the fact that connect() can be called multiple times for a DGRAM
-// socket. This tests for that behavior.
-TEST(liblog, multi_connect_dgram_socket) {
-#ifdef __ANDROID__
- if (getuid() != 0) {
- GTEST_SKIP() << "Skipping test, must be run as root.";
- return;
- }
- auto temp_dir = TemporaryDir();
- auto socket_path = StringPrintf("%s/test_socket", temp_dir.path);
-
- unique_fd server_socket;
-
- auto open_server_socket = [&] {
- server_socket.reset(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0)));
- ASSERT_TRUE(server_socket.ok());
-
- sockaddr_un server_sockaddr = {};
- server_sockaddr.sun_family = AF_UNIX;
- strlcpy(server_sockaddr.sun_path, socket_path.c_str(), sizeof(server_sockaddr.sun_path));
- ASSERT_EQ(0,
- TEMP_FAILURE_RETRY(bind(server_socket, reinterpret_cast<sockaddr*>(&server_sockaddr),
- sizeof(server_sockaddr))));
- };
-
- // Open the server socket.
- open_server_socket();
-
- // Open the client socket.
- auto client_socket =
- unique_fd{TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0))};
- ASSERT_TRUE(client_socket.ok());
- sockaddr_un client_sockaddr = {};
- client_sockaddr.sun_family = AF_UNIX;
- strlcpy(client_sockaddr.sun_path, socket_path.c_str(), sizeof(client_sockaddr.sun_path));
- ASSERT_EQ(0,
- TEMP_FAILURE_RETRY(connect(client_socket, reinterpret_cast<sockaddr*>(&client_sockaddr),
- sizeof(client_sockaddr))));
-
- // Ensure that communication works.
- constexpr static char kSmoke[] = "smoke test";
- ssize_t smoke_len = sizeof(kSmoke);
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
- char read_buf[512];
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(read(server_socket, read_buf, sizeof(read_buf))));
- ASSERT_STREQ(kSmoke, read_buf);
-
- // Close the server socket.
- server_socket.reset();
- ASSERT_EQ(0, unlink(socket_path.c_str())) << strerror(errno);
-
- // Ensure that write() from the client returns an error since the server is closed.
- ASSERT_EQ(-1, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
- ASSERT_EQ(errno, ECONNREFUSED) << strerror(errno);
-
- // Open the server socket again.
- open_server_socket();
-
- // Reconnect the same client socket.
- ASSERT_EQ(0,
- TEMP_FAILURE_RETRY(connect(client_socket, reinterpret_cast<sockaddr*>(&client_sockaddr),
- sizeof(client_sockaddr))))
- << strerror(errno);
-
- // Ensure that communication works.
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(write(client_socket, kSmoke, sizeof(kSmoke))));
- ASSERT_EQ(smoke_len, TEMP_FAILURE_RETRY(read(server_socket, read_buf, sizeof(read_buf))));
- ASSERT_STREQ(kSmoke, read_buf);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
\ No newline at end of file
diff --git a/liblog/tests/logprint_test.cpp b/liblog/tests/logprint_test.cpp
deleted file mode 100644
index 72e53f9..0000000
--- a/liblog/tests/logprint_test.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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 <log/logprint.h>
-
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <log/log_read.h>
-
-size_t convertPrintable(char* p, const char* message, size_t messageLen);
-
-TEST(liblog, convertPrintable_ascii) {
- auto input = "easy string, output same";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
- EXPECT_STREQ(input, output);
-}
-
-TEST(liblog, convertPrintable_escapes) {
- // Note that \t is not escaped.
- auto input = "escape\a\b\t\v\f\r\\";
- auto expected_output = "escape\\a\\b\t\\v\\f\\r\\\\";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
- EXPECT_STREQ(expected_output, output);
-}
-
-TEST(liblog, convertPrintable_validutf8) {
- auto input = u8"¢ह€𐍈";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(input));
- EXPECT_STREQ(input, output);
-}
-
-TEST(liblog, convertPrintable_invalidutf8) {
- auto input = "\x80\xC2\x01\xE0\xA4\x06\xE0\x06\xF0\x90\x8D\x06\xF0\x90\x06\xF0\x0E";
- auto expected_output =
- "\\x80\\xC2\\x01\\xE0\\xA4\\x06\\xE0\\x06\\xF0\\x90\\x8D\\x06\\xF0\\x90\\x06\\xF0\\x0E";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
- EXPECT_STREQ(expected_output, output);
-}
-
-TEST(liblog, convertPrintable_mixed) {
- auto input =
- u8"\x80\xC2¢ह€𐍈\x01\xE0\xA4\x06¢ह€𐍈\xE0\x06\a\b\xF0\x90¢ह€𐍈\x8D\x06\xF0\t\t\x90\x06\xF0\x0E";
- auto expected_output =
- u8"\\x80\\xC2¢ह€𐍈\\x01\\xE0\\xA4\\x06¢ह€𐍈\\xE0\\x06\\a\\b\\xF0\\x90¢ह€𐍈\\x8D\\x06\\xF0\t\t"
- u8"\\x90\\x06\\xF0\\x0E";
- auto output_size = convertPrintable(nullptr, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
-
- char output[output_size];
-
- output_size = convertPrintable(output, input, strlen(input));
- EXPECT_EQ(output_size, strlen(expected_output));
- EXPECT_STREQ(expected_output, output);
-}
-
-TEST(liblog, log_print_different_header_size) {
- constexpr int32_t kPid = 123;
- constexpr uint32_t kTid = 456;
- constexpr uint32_t kSec = 1000;
- constexpr uint32_t kNsec = 999;
- constexpr uint32_t kLid = LOG_ID_MAIN;
- constexpr uint32_t kUid = 987;
- constexpr char kPriority = ANDROID_LOG_ERROR;
-
- auto create_buf = [](char* buf, size_t len, uint16_t hdr_size) {
- memset(buf, 0, len);
- logger_entry* header = reinterpret_cast<logger_entry*>(buf);
- header->hdr_size = hdr_size;
- header->pid = kPid;
- header->tid = kTid;
- header->sec = kSec;
- header->nsec = kNsec;
- header->lid = kLid;
- header->uid = kUid;
- char* message = buf + header->hdr_size;
- uint16_t message_len = 0;
- message[message_len++] = kPriority;
- message[message_len++] = 'T';
- message[message_len++] = 'a';
- message[message_len++] = 'g';
- message[message_len++] = '\0';
- message[message_len++] = 'm';
- message[message_len++] = 's';
- message[message_len++] = 'g';
- message[message_len++] = '!';
- message[message_len++] = '\0';
- header->len = message_len;
- };
-
- auto check_entry = [&](const AndroidLogEntry& entry) {
- EXPECT_EQ(kSec, static_cast<uint32_t>(entry.tv_sec));
- EXPECT_EQ(kNsec, static_cast<uint32_t>(entry.tv_nsec));
- EXPECT_EQ(kPriority, entry.priority);
- EXPECT_EQ(kUid, static_cast<uint32_t>(entry.uid));
- EXPECT_EQ(kPid, entry.pid);
- EXPECT_EQ(kTid, static_cast<uint32_t>(entry.tid));
- EXPECT_STREQ("Tag", entry.tag);
- EXPECT_EQ(4U, entry.tagLen); // Apparently taglen includes the nullptr?
- EXPECT_EQ(4U, entry.messageLen);
- EXPECT_STREQ("msg!", entry.message);
- };
- alignas(logger_entry) char buf[LOGGER_ENTRY_MAX_LEN];
- create_buf(buf, sizeof(buf), sizeof(logger_entry));
-
- AndroidLogEntry entry_normal_size;
- ASSERT_EQ(0,
- android_log_processLogBuffer(reinterpret_cast<logger_entry*>(buf), &entry_normal_size));
- check_entry(entry_normal_size);
-
- create_buf(buf, sizeof(buf), sizeof(logger_entry) + 3);
- AndroidLogEntry entry_odd_size;
- ASSERT_EQ(0, android_log_processLogBuffer(reinterpret_cast<logger_entry*>(buf), &entry_odd_size));
- check_entry(entry_odd_size);
-}
\ No newline at end of file
diff --git a/liblog/uio.h b/liblog/uio.h
deleted file mode 100644
index c85893c..0000000
--- a/liblog/uio.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#if defined(_WIN32)
-#include <stddef.h>
-struct iovec {
- void* iov_base;
- size_t iov_len;
-};
-#else
-#include <sys/uio.h>
-#endif
diff --git a/libpixelflinger/Android.bp b/libpixelflinger/Android.bp
deleted file mode 100644
index 45a32da..0000000
--- a/libpixelflinger/Android.bp
+++ /dev/null
@@ -1,97 +0,0 @@
-cc_defaults {
- name: "pixelflinger_defaults",
-
- cflags: [
- "-fstrict-aliasing",
- "-fomit-frame-pointer",
- "-Wall",
- "-Werror",
- "-Wno-unused-function",
- ],
- export_include_dirs: ["include"],
- header_libs: ["libbase_headers"],
- shared_libs: [
- "libcutils",
- "liblog",
- "libutils",
- ],
-
- arch: {
- arm: {
- neon: {
- cflags: ["-D__ARM_HAVE_NEON"],
- },
- },
- },
-}
-
-cc_library_static {
- name: "libpixelflinger-arm",
- defaults: ["pixelflinger_defaults"],
-
- srcs: [
- "fixed.cpp",
- "picker.cpp",
- "pixelflinger.cpp",
- "trap.cpp",
- "scanline.cpp",
- ],
-
- arch: {
- arm: {
- instruction_set: "arm",
- },
- },
-}
-
-// For the tests to use
-cc_library_headers {
- name: "libpixelflinger_internal",
- export_include_dirs: [
- "include",
- ".",
- ],
-}
-
-cc_library {
- name: "libpixelflinger",
- defaults: ["pixelflinger_defaults"],
-
- srcs: [
- "codeflinger/ARMAssemblerInterface.cpp",
- "codeflinger/ARMAssemblerProxy.cpp",
- "codeflinger/CodeCache.cpp",
- "codeflinger/GGLAssembler.cpp",
- "codeflinger/load_store.cpp",
- "codeflinger/blending.cpp",
- "codeflinger/texturing.cpp",
- "format.cpp",
- "clear.cpp",
- "raster.cpp",
- "buffer.cpp",
- ],
- whole_static_libs: ["libpixelflinger-arm"],
-
- arch: {
- arm: {
- srcs: [
- "codeflinger/ARMAssembler.cpp",
- "codeflinger/disassem.c",
- "col32cb16blend.S",
- "t32cb16blend.S",
- ],
-
- neon: {
- srcs: ["col32cb16blend_neon.S"],
- },
- },
- arm64: {
- srcs: [
- "codeflinger/Arm64Assembler.cpp",
- "codeflinger/Arm64Disassembler.cpp",
- "arch-arm64/col32cb16blend.S",
- "arch-arm64/t32cb16blend.S",
- ],
- },
- },
-}
diff --git a/libpixelflinger/MODULE_LICENSE_APACHE2 b/libpixelflinger/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/libpixelflinger/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/libpixelflinger/NOTICE b/libpixelflinger/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/libpixelflinger/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/libpixelflinger/arch-arm64/col32cb16blend.S b/libpixelflinger/arch-arm64/col32cb16blend.S
deleted file mode 100644
index 84596f9..0000000
--- a/libpixelflinger/arch-arm64/col32cb16blend.S
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- .text
- .balign 0
-
- .global scanline_col32cb16blend_arm64
-
-//
-// This function alpha blends a fixed color into a destination scanline, using
-// the formula:
-//
-// d = s + (((a + (a >> 7)) * d) >> 8)
-//
-// where d is the destination pixel,
-// s is the source color,
-// a is the alpha channel of the source color.
-//
-
-// x0 = destination buffer pointer
-// w1 = color value
-// w2 = count
-
-
-scanline_col32cb16blend_arm64:
-
- lsr w5, w1, #24 // shift down alpha
- mov w9, #0xff // create mask
- add w5, w5, w5, lsr #7 // add in top bit
- mov w4, #256 // create #0x100
- sub w5, w4, w5 // invert alpha
- and w10, w1, #0xff // extract red
- and w12, w9, w1, lsr #8 // extract green
- and w4, w9, w1, lsr #16 // extract blue
- lsl w10, w10, #5 // prescale red
- lsl w12, w12, #6 // prescale green
- lsl w4, w4, #5 // prescale blue
- lsr w9, w9, #2 // create dest green mask
-
-1:
- ldrh w8, [x0] // load dest pixel
- subs w2, w2, #1 // decrement loop counter
- lsr w6, w8, #11 // extract dest red
- and w7, w9, w8, lsr #5 // extract dest green
- and w8, w8, #0x1f // extract dest blue
-
- madd w6, w6, w5, w10 // dest red * alpha + src red
- madd w7, w7, w5, w12 // dest green * alpha + src green
- madd w8, w8, w5, w4 // dest blue * alpha + src blue
-
- lsr w6, w6, #8 // shift down red
- lsr w7, w7, #8 // shift down green
- lsl w6, w6, #11 // shift red into 565
- orr w6, w6, w7, lsl #5 // shift green into 565
- orr w6, w6, w8, lsr #8 // shift blue into 565
-
- strh w6, [x0], #2 // store pixel to dest, update ptr
- b.ne 1b // if count != 0, loop
-
- ret
-
-
-
diff --git a/libpixelflinger/arch-arm64/t32cb16blend.S b/libpixelflinger/arch-arm64/t32cb16blend.S
deleted file mode 100644
index a9733c0..0000000
--- a/libpixelflinger/arch-arm64/t32cb16blend.S
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
- .text
- .balign 0
-
- .global scanline_t32cb16blend_arm64
-
-/*
- * .macro pixel
- *
- * This macro alpha blends RGB565 original pixel located in either
- * top or bottom 16 bits of DREG register with SRC 32 bit pixel value
- * and writes the result to FB register
- *
- * \DREG is a 32-bit register containing *two* original destination RGB565
- * pixels, with the even one in the low-16 bits, and the odd one in the
- * high 16 bits.
- *
- * \SRC is a 32-bit 0xAABBGGRR pixel value, with pre-multiplied colors.
- *
- * \FB is a target register that will contain the blended pixel values.
- *
- * \ODD is either 0 or 1 and indicates if we're blending the lower or
- * upper 16-bit pixels in DREG into FB
- *
- *
- * clobbered: w6, w7, w15, w16, w17
- *
- */
-
-.macro pixel, DREG, SRC, FB, ODD
-
- // SRC = 0xAABBGGRR
- lsr w7, \SRC, #24 // sA
- add w7, w7, w7, lsr #7 // sA + (sA >> 7)
- mov w6, #0x100
- sub w7, w6, w7 // sA = 0x100 - (sA+(sA>>7))
-
-1:
-
-.if \ODD //Blending odd pixel present in top 16 bits of DREG register
-
- // red
- lsr w16, \DREG, #(16 + 11)
- mul w16, w7, w16
- lsr w6, \SRC, #3
- and w6, w6, #0x1F
- add w16, w6, w16, lsr #8
- cmp w16, #0x1F
- orr w17, \FB, #(0x1F<<(16 + 11))
- orr w15, \FB, w16, lsl #(16 + 11)
- csel \FB, w17, w15, hi
- // green
- and w6, \DREG, #(0x3F<<(16 + 5))
- lsr w17,w6,#(16+5)
- mul w6, w7, w17
- lsr w16, \SRC, #(8+2)
- and w16, w16, #0x3F
- add w6, w16, w6, lsr #8
- cmp w6, #0x3F
- orr w17, \FB, #(0x3F<<(16 + 5))
- orr w15, \FB, w6, lsl #(16 + 5)
- csel \FB, w17, w15, hi
- // blue
- and w16, \DREG, #(0x1F << 16)
- lsr w17,w16,#16
- mul w16, w7, w17
- lsr w6, \SRC, #(8+8+3)
- and w6, w6, #0x1F
- add w16, w6, w16, lsr #8
- cmp w16, #0x1F
- orr w17, \FB, #(0x1F << 16)
- orr w15, \FB, w16, lsl #16
- csel \FB, w17, w15, hi
-
-.else //Blending even pixel present in bottom 16 bits of DREG register
-
- // red
- lsr w16, \DREG, #11
- and w16, w16, #0x1F
- mul w16, w7, w16
- lsr w6, \SRC, #3
- and w6, w6, #0x1F
- add w16, w6, w16, lsr #8
- cmp w16, #0x1F
- mov w17, #(0x1F<<11)
- lsl w15, w16, #11
- csel \FB, w17, w15, hi
-
-
- // green
- and w6, \DREG, #(0x3F<<5)
- mul w6, w7, w6
- lsr w16, \SRC, #(8+2)
- and w16, w16, #0x3F
- add w6, w16, w6, lsr #(5+8)
- cmp w6, #0x3F
- orr w17, \FB, #(0x3F<<5)
- orr w15, \FB, w6, lsl #5
- csel \FB, w17, w15, hi
-
- // blue
- and w16, \DREG, #0x1F
- mul w16, w7, w16
- lsr w6, \SRC, #(8+8+3)
- and w6, w6, #0x1F
- add w16, w6, w16, lsr #8
- cmp w16, #0x1F
- orr w17, \FB, #0x1F
- orr w15, \FB, w16
- csel \FB, w17, w15, hi
-
-.endif // End of blending even pixel
-
-.endm // End of pixel macro
-
-
-// x0: dst ptr
-// x1: src ptr
-// w2: count
-// w3: d
-// w4: s0
-// w5: s1
-// w6: pixel
-// w7: pixel
-// w8: free
-// w9: free
-// w10: free
-// w11: free
-// w12: scratch
-// w14: pixel
-
-scanline_t32cb16blend_arm64:
-
- // align DST to 32 bits
- tst x0, #0x3
- b.eq aligned
- subs w2, w2, #1
- b.lo return
-
-last:
- ldr w4, [x1], #4
- ldrh w3, [x0]
- pixel w3, w4, w12, 0
- strh w12, [x0], #2
-
-aligned:
- subs w2, w2, #2
- b.lo 9f
-
- // The main loop is unrolled twice and processes 4 pixels
-8:
- ldp w4,w5, [x1], #8
- add x0, x0, #4
- // it's all zero, skip this pixel
- orr w3, w4, w5
- cbz w3, 7f
-
- // load the destination
- ldr w3, [x0, #-4]
- // stream the destination
- pixel w3, w4, w12, 0
- pixel w3, w5, w12, 1
- str w12, [x0, #-4]
-
- // 2nd iteration of the loop, don't stream anything
- subs w2, w2, #2
- csel w4, w5, w4, lt
- blt 9f
- ldp w4,w5, [x1], #8
- add x0, x0, #4
- orr w3, w4, w5
- cbz w3, 7f
- ldr w3, [x0, #-4]
- pixel w3, w4, w12, 0
- pixel w3, w5, w12, 1
- str w12, [x0, #-4]
-
-7: subs w2, w2, #2
- bhs 8b
- mov w4, w5
-
-9: adds w2, w2, #1
- b.lo return
- b last
-
-return:
- ret
diff --git a/libpixelflinger/buffer.cpp b/libpixelflinger/buffer.cpp
deleted file mode 100644
index ea9514c..0000000
--- a/libpixelflinger/buffer.cpp
+++ /dev/null
@@ -1,389 +0,0 @@
-/* libs/pixelflinger/buffer.cpp
-**
-** Copyright 2006, 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 <assert.h>
-
-#include <android-base/macros.h>
-
-#include "buffer.h"
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-static void read_pixel(const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, pixel_t* pixel);
-static void write_pixel(const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, const pixel_t* pixel);
-static void readRGB565(const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, pixel_t* pixel);
-static void readABGR8888(const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, pixel_t* pixel);
-
-static uint32_t logic_op(int op, uint32_t s, uint32_t d);
-static uint32_t extract(uint32_t v, int h, int l, int bits);
-static uint32_t expand(uint32_t v, int sbits, int dbits);
-static uint32_t downshift_component(uint32_t in, uint32_t v,
- int sh, int sl, int dh, int dl, int ch, int cl, int dither);
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_texture(context_t* c)
-{
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- texture_t& t = c->state.texture[i];
- t.s_coord = GGL_ONE_TO_ONE;
- t.t_coord = GGL_ONE_TO_ONE;
- t.s_wrap = GGL_REPEAT;
- t.t_wrap = GGL_REPEAT;
- t.min_filter = GGL_NEAREST;
- t.mag_filter = GGL_NEAREST;
- t.env = GGL_MODULATE;
- }
- c->activeTMU = &(c->state.texture[0]);
-}
-
-void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src)
-{
- dst->width = src->width;
- dst->height = src->height;
- dst->stride = src->stride;
- dst->data = src->data;
- dst->format = src->format;
- dst->dirty = 1;
- if (__builtin_expect(dst->stride < 0, false)) {
- const GGLFormat& pixelFormat(c->formats[dst->format]);
- const int32_t bpr = -dst->stride * pixelFormat.size;
- dst->data += bpr * (dst->height-1);
- }
-}
-
-static void pick_read_write(surface_t* s)
-{
- // Choose best reader/writers.
- switch (s->format) {
- case GGL_PIXEL_FORMAT_RGBA_8888: s->read = readABGR8888; break;
- case GGL_PIXEL_FORMAT_RGB_565: s->read = readRGB565; break;
- default: s->read = read_pixel; break;
- }
- s->write = write_pixel;
-}
-
-void ggl_pick_texture(context_t* c)
-{
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- surface_t& s = c->state.texture[i].surface;
- if ((!c->state.texture[i].enable) || (!s.dirty))
- continue;
- s.dirty = 0;
- pick_read_write(&s);
- generated_tex_vars_t& gen = c->generated_vars.texture[i];
- gen.width = s.width;
- gen.height = s.height;
- gen.stride = s.stride;
- gen.data = uintptr_t(s.data);
- }
-}
-
-void ggl_pick_cb(context_t* c)
-{
- surface_t& s = c->state.buffers.color;
- if (s.dirty) {
- s.dirty = 0;
- pick_read_write(&s);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-void read_pixel(const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, pixel_t* pixel)
-{
- assert((x < s->width) && (y < s->height));
-
- const GGLFormat* f = &(c->formats[s->format]);
- int32_t index = x + (s->stride * y);
- uint8_t* const data = s->data + index * f->size;
- uint32_t v = 0;
- switch (f->size) {
- case 1: v = *data; break;
- case 2: v = *(uint16_t*)data; break;
- case 3: v = (data[2]<<16)|(data[1]<<8)|data[0]; break;
- case 4: v = GGL_RGBA_TO_HOST(*(uint32_t*)data); break;
- }
- for (int i=0 ; i<4 ; i++) {
- pixel->s[i] = f->c[i].h - f->c[i].l;
- if (pixel->s[i])
- pixel->c[i] = extract(v, f->c[i].h, f->c[i].l, f->size*8);
- }
-}
-
-void readRGB565(const surface_t* s, context_t* /*c*/,
- uint32_t x, uint32_t y, pixel_t* pixel)
-{
- uint16_t v = *(reinterpret_cast<uint16_t*>(s->data) + (x + (s->stride * y)));
- pixel->c[0] = 0;
- pixel->c[1] = v>>11;
- pixel->c[2] = (v>>5)&0x3F;
- pixel->c[3] = v&0x1F;
- pixel->s[0] = 0;
- pixel->s[1] = 5;
- pixel->s[2] = 6;
- pixel->s[3] = 5;
-}
-
-void readABGR8888(const surface_t* s, context_t* /*c*/,
- uint32_t x, uint32_t y, pixel_t* pixel)
-{
- uint32_t v = *(reinterpret_cast<uint32_t*>(s->data) + (x + (s->stride * y)));
- v = GGL_RGBA_TO_HOST(v);
- pixel->c[0] = v>>24; // A
- pixel->c[1] = v&0xFF; // R
- pixel->c[2] = (v>>8)&0xFF; // G
- pixel->c[3] = (v>>16)&0xFF; // B
- pixel->s[0] =
- pixel->s[1] =
- pixel->s[2] =
- pixel->s[3] = 8;
-}
-
-void write_pixel(const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, const pixel_t* pixel)
-{
- assert((x < s->width) && (y < s->height));
-
- int dither = -1;
- if (c->state.enables & GGL_ENABLE_DITHER) {
- dither = c->ditherMatrix[ (x & GGL_DITHER_MASK) +
- ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
- }
-
- const GGLFormat* f = &(c->formats[s->format]);
- int32_t index = x + (s->stride * y);
- uint8_t* const data = s->data + index * f->size;
-
- uint32_t mask = 0;
- uint32_t v = 0;
- for (int i=0 ; i<4 ; i++) {
- const int component_mask = 1 << i;
- if (f->components>=GGL_LUMINANCE &&
- (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
- // destinations L formats don't have G or B
- continue;
- }
- const int l = f->c[i].l;
- const int h = f->c[i].h;
- if (h && (c->state.mask.color & component_mask)) {
- mask |= (((1<<(h-l))-1)<<l);
- uint32_t u = pixel->c[i];
- int32_t pixelSize = pixel->s[i];
- if (pixelSize < (h-l)) {
- u = expand(u, pixelSize, h-l);
- pixelSize = h-l;
- }
- v = downshift_component(v, u, pixelSize, 0, h, l, 0, 0, dither);
- }
- }
-
- if ((c->state.mask.color != 0xF) ||
- (c->state.enables & GGL_ENABLE_LOGIC_OP)) {
- uint32_t d = 0;
- switch (f->size) {
- case 1: d = *data; break;
- case 2: d = *(uint16_t*)data; break;
- case 3: d = (data[2]<<16)|(data[1]<<8)|data[0]; break;
- case 4: d = GGL_RGBA_TO_HOST(*(uint32_t*)data); break;
- }
- if (c->state.enables & GGL_ENABLE_LOGIC_OP) {
- v = logic_op(c->state.logic_op.opcode, v, d);
- v &= mask;
- }
- v |= (d & ~mask);
- }
-
- switch (f->size) {
- case 1: *data = v; break;
- case 2: *(uint16_t*)data = v; break;
- case 3:
- data[0] = v;
- data[1] = v>>8;
- data[2] = v>>16;
- break;
- case 4: *(uint32_t*)data = GGL_HOST_TO_RGBA(v); break;
- }
-}
-
-static uint32_t logic_op(int op, uint32_t s, uint32_t d)
-{
- switch(op) {
- case GGL_CLEAR: return 0;
- case GGL_AND: return s & d;
- case GGL_AND_REVERSE: return s & ~d;
- case GGL_COPY: return s;
- case GGL_AND_INVERTED: return ~s & d;
- case GGL_NOOP: return d;
- case GGL_XOR: return s ^ d;
- case GGL_OR: return s | d;
- case GGL_NOR: return ~(s | d);
- case GGL_EQUIV: return ~(s ^ d);
- case GGL_INVERT: return ~d;
- case GGL_OR_REVERSE: return s | ~d;
- case GGL_COPY_INVERTED: return ~s;
- case GGL_OR_INVERTED: return ~s | d;
- case GGL_NAND: return ~(s & d);
- case GGL_SET: return ~0;
- };
- return s;
-}
-
-
-uint32_t ggl_expand(uint32_t v, int sbits, int dbits)
-{
- return expand(v, sbits, dbits);
-}
-
-uint32_t ggl_pack_color(context_t* c, int32_t format,
- GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a)
-{
- const GGLFormat* f = &(c->formats[format]);
- uint32_t p = 0;
- const int32_t hbits = GGL_COLOR_BITS;
- const int32_t lbits = GGL_COLOR_BITS - 8;
- p = downshift_component(p, r, hbits, lbits, f->rh, f->rl, 0, 1, -1);
- p = downshift_component(p, g, hbits, lbits, f->gh, f->gl, 0, 1, -1);
- p = downshift_component(p, b, hbits, lbits, f->bh, f->bl, 0, 1, -1);
- p = downshift_component(p, a, hbits, lbits, f->ah, f->al, 0, 1, -1);
- switch (f->size) {
- case 1:
- p |= p << 8;
- FALLTHROUGH_INTENDED;
- case 2:
- p |= p << 16;
- }
- return p;
-}
-
-// ----------------------------------------------------------------------------
-
-// extract a component from a word
-uint32_t extract(uint32_t v, int h, int l, int bits)
-{
- assert(h);
- if (l) {
- v >>= l;
- }
- if (h != bits) {
- v &= (1<<(h-l))-1;
- }
- return v;
-}
-
-// expand a component from sbits to dbits
-uint32_t expand(uint32_t v, int sbits, int dbits)
-{
- if (dbits > sbits) {
- assert(sbits);
- if (sbits==1) {
- v = (v<<dbits) - v;
- } else {
- if (dbits % sbits) {
- v <<= (dbits-sbits);
- dbits -= sbits;
- do {
- v |= v>>sbits;
- dbits -= sbits;
- sbits *= 2;
- } while (dbits>0);
- } else {
- dbits -= sbits;
- do {
- v |= v<<sbits;
- dbits -= sbits;
- if (sbits*2 < dbits) {
- sbits *= 2;
- }
- } while (dbits > 0);
- }
- }
- }
- return v;
-}
-
-// downsample a component from sbits to dbits
-// and shift / construct the pixel
-uint32_t downshift_component( uint32_t in, uint32_t v,
- int sh, int sl, // src
- int dh, int dl, // dst
- int ch, int cl, // clear
- int dither)
-{
- const int sbits = sh-sl;
- const int dbits = dh-dl;
-
- assert(sbits>=dbits);
-
-
- if (sbits>dbits) {
- if (dither>=0) {
- v -= (v>>dbits); // fix up
- const int shift = (GGL_DITHER_BITS - (sbits-dbits));
- if (shift >= 0) v += (dither >> shift) << sl;
- else v += (dither << (-shift)) << sl;
- } else {
- // don't do that right now, so we can reproduce the same
- // artifacts we get on ARM (Where we don't do this)
- // -> this is not really needed if we don't dither
- //if (dBits > 1) { // result already OK if dBits==1
- // v -= (v>>dbits); // fix up
- // v += 1 << ((sbits-dbits)-1); // rounding
- //}
- }
- }
-
-
- // we need to clear the high bits of the source
- if (ch) {
- v <<= 32-sh;
- sl += 32-sh;
- sh = 32;
- }
-
- if (dl) {
- if (cl || (sbits>dbits)) {
- v >>= sh-dbits;
- sl = 0;
- sh = dbits;
- in |= v<<dl;
- } else {
- // sbits==dbits and we don't need to clean the lower bits
- // so we just have to shift the component to the right location
- int shift = dh-sh;
- in |= v<<shift;
- }
- } else {
- // destination starts at bit 0
- // ie: sh-dh == sh-dbits
- int shift = sh-dh;
- if (shift > 0) in |= v>>shift;
- else if (shift < 0) in |= v<<shift;
- else in |= v;
- }
- return in;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/libpixelflinger/buffer.h b/libpixelflinger/buffer.h
deleted file mode 100644
index 9c9e4bc..0000000
--- a/libpixelflinger/buffer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/* libs/pixelflinger/buffer.h
-**
-** Copyright 2006, 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 ANDROID_GGL_TEXTURE_H
-#define ANDROID_GGL_TEXTURE_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_texture(context_t* c);
-
-void ggl_set_surface(context_t* c, surface_t* dst, const GGLSurface* src);
-
-void ggl_pick_texture(context_t* c);
-void ggl_pick_cb(context_t* c);
-
-uint32_t ggl_expand(uint32_t v, int sbits, int dbits);
-uint32_t ggl_pack_color(context_t* c, int32_t format,
- GGLcolor r, GGLcolor g, GGLcolor b, GGLcolor a);
-
-}; // namespace android
-
-#endif // ANDROID_GGL_TEXTURE_H
diff --git a/libpixelflinger/clear.cpp b/libpixelflinger/clear.cpp
deleted file mode 100644
index b962456..0000000
--- a/libpixelflinger/clear.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/* libs/pixelflinger/clear.cpp
-**
-** Copyright 2006, 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 <cutils/memory.h>
-
-#include "clear.h"
-#include "buffer.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static void ggl_clear(void* c, GGLbitfield mask);
-static void ggl_clearColorx(void* c,
- GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a);
-static void ggl_clearDepthx(void* c, GGLclampx depth);
-static void ggl_clearStencil(void* c, GGLint s);
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_clear(context_t* c)
-{
- GGLContext& procs = *(GGLContext*)c;
- GGL_INIT_PROC(procs, clear);
- GGL_INIT_PROC(procs, clearColorx);
- GGL_INIT_PROC(procs, clearDepthx);
- GGL_INIT_PROC(procs, clearStencil);
- c->state.clear.dirty = GGL_STENCIL_BUFFER_BIT |
- GGL_COLOR_BUFFER_BIT |
- GGL_DEPTH_BUFFER_BIT;
- c->state.clear.depth = FIXED_ONE;
-}
-
-// ----------------------------------------------------------------------------
-
-static void memset2d(context_t* c, const surface_t& s, uint32_t packed,
- uint32_t l, uint32_t t, uint32_t w, uint32_t h)
-{
- const uint32_t size = c->formats[s.format].size;
- const int32_t stride = s.stride * size;
- uint8_t* dst = (uint8_t*)s.data + (l + t*s.stride)*size;
- w *= size;
-
- if (ggl_likely(int32_t(w) == stride)) {
- // clear the whole thing in one call
- w *= h;
- h = 1;
- }
-
- switch (size) {
- case 1:
- do {
- memset(dst, packed, w);
- dst += stride;
- } while(--h);
- break;
- case 2:
- do {
- android_memset16((uint16_t*)dst, packed, w);
- dst += stride;
- } while(--h);
- break;
- case 3: // XXX: 24-bit clear.
- break;
- case 4:
- do {
- android_memset32((uint32_t*)dst, packed, w);
- dst += stride;
- } while(--h);
- break;
- }
-}
-
-static inline GGLfixed fixedToZ(GGLfixed z) {
- return GGLfixed(((int64_t(z) << 16) - z) >> 16);
-}
-
-static void ggl_clear(void* con, GGLbitfield mask)
-{
- GGL_CONTEXT(c, con);
-
- // XXX: rgba-dithering, rgba-masking
- // XXX: handle all formats of Z and S
-
- const uint32_t l = c->state.scissor.left;
- const uint32_t t = c->state.scissor.top;
- uint32_t w = c->state.scissor.right - l;
- uint32_t h = c->state.scissor.bottom - t;
-
- if (!w || !h)
- return;
-
- // unexsiting buffers have no effect...
- if (c->state.buffers.color.format == 0)
- mask &= ~GGL_COLOR_BUFFER_BIT;
-
- if (c->state.buffers.depth.format == 0)
- mask &= ~GGL_DEPTH_BUFFER_BIT;
-
- if (c->state.buffers.stencil.format == 0)
- mask &= ~GGL_STENCIL_BUFFER_BIT;
-
- if (mask & GGL_COLOR_BUFFER_BIT) {
- if (c->state.clear.dirty & GGL_COLOR_BUFFER_BIT) {
- c->state.clear.dirty &= ~GGL_COLOR_BUFFER_BIT;
-
- uint32_t colorPacked = ggl_pack_color(c,
- c->state.buffers.color.format,
- gglFixedToIteratedColor(c->state.clear.r),
- gglFixedToIteratedColor(c->state.clear.g),
- gglFixedToIteratedColor(c->state.clear.b),
- gglFixedToIteratedColor(c->state.clear.a));
-
- c->state.clear.colorPacked = GGL_HOST_TO_RGBA(colorPacked);
- }
- const uint32_t packed = c->state.clear.colorPacked;
- memset2d(c, c->state.buffers.color, packed, l, t, w, h);
- }
- if (mask & GGL_DEPTH_BUFFER_BIT) {
- if (c->state.clear.dirty & GGL_DEPTH_BUFFER_BIT) {
- c->state.clear.dirty &= ~GGL_DEPTH_BUFFER_BIT;
- uint32_t depth = fixedToZ(c->state.clear.depth);
- c->state.clear.depthPacked = (depth<<16)|depth;
- }
- const uint32_t packed = c->state.clear.depthPacked;
- memset2d(c, c->state.buffers.depth, packed, l, t, w, h);
- }
-
- // XXX: do stencil buffer
-}
-
-static void ggl_clearColorx(void* con,
- GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a)
-{
- GGL_CONTEXT(c, con);
- c->state.clear.r = gglClampx(r);
- c->state.clear.g = gglClampx(g);
- c->state.clear.b = gglClampx(b);
- c->state.clear.a = gglClampx(a);
- c->state.clear.dirty |= GGL_COLOR_BUFFER_BIT;
-}
-
-static void ggl_clearDepthx(void* con, GGLclampx depth)
-{
- GGL_CONTEXT(c, con);
- c->state.clear.depth = gglClampx(depth);
- c->state.clear.dirty |= GGL_DEPTH_BUFFER_BIT;
-}
-
-static void ggl_clearStencil(void* con, GGLint s)
-{
- GGL_CONTEXT(c, con);
- c->state.clear.stencil = s;
- c->state.clear.dirty |= GGL_STENCIL_BUFFER_BIT;
-}
-
-}; // namespace android
diff --git a/libpixelflinger/clear.h b/libpixelflinger/clear.h
deleted file mode 100644
index b071df0..0000000
--- a/libpixelflinger/clear.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* libs/pixelflinger/clear.h
-**
-** Copyright 2006, 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 ANDROID_GGL_CLEAR_H
-#define ANDROID_GGL_CLEAR_H
-
-#include <pixelflinger/pixelflinger.h>
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_clear(context_t* c);
-
-}; // namespace android
-
-#endif // ANDROID_GGL_CLEAR_H
diff --git a/libpixelflinger/codeflinger/ARMAssembler.cpp b/libpixelflinger/codeflinger/ARMAssembler.cpp
deleted file mode 100644
index f47b6e4..0000000
--- a/libpixelflinger/codeflinger/ARMAssembler.cpp
+++ /dev/null
@@ -1,579 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssembler.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "ARMAssembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "ARMAssembler.h"
-#include "CodeCache.h"
-#include "disassem.h"
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark ARMAssembler...
-#endif
-
-ARMAssembler::ARMAssembler(const sp<Assembly>& assembly)
- : ARMAssemblerInterface(),
- mAssembly(assembly)
-{
- mBase = mPC = (uint32_t *)assembly->base();
- mDuration = ggl_system_time();
-}
-
-ARMAssembler::~ARMAssembler()
-{
-}
-
-uint32_t* ARMAssembler::pc() const
-{
- return mPC;
-}
-
-uint32_t* ARMAssembler::base() const
-{
- return mBase;
-}
-
-void ARMAssembler::reset()
-{
- mBase = mPC = (uint32_t *)mAssembly->base();
- mBranchTargets.clear();
- mLabels.clear();
- mLabelsInverseMapping.clear();
- mComments.clear();
-}
-
-int ARMAssembler::getCodegenArch()
-{
- return CODEGEN_ARCH_ARM;
-}
-
-// ----------------------------------------------------------------------------
-
-void ARMAssembler::disassemble(const char* name)
-{
- if (name) {
- printf("%s:\n", name);
- }
- size_t count = pc()-base();
- uint32_t* i = base();
- while (count--) {
- ssize_t label = mLabelsInverseMapping.indexOfKey(i);
- if (label >= 0) {
- printf("%s:\n", mLabelsInverseMapping.valueAt(label));
- }
- ssize_t comment = mComments.indexOfKey(i);
- if (comment >= 0) {
- printf("; %s\n", mComments.valueAt(comment));
- }
- printf("%08x: %08x ", uintptr_t(i), int(i[0]));
- ::disassemble((uintptr_t)i);
- i++;
- }
-}
-
-void ARMAssembler::comment(const char* string)
-{
- mComments.add(mPC, string);
-}
-
-void ARMAssembler::label(const char* theLabel)
-{
- mLabels.add(theLabel, mPC);
- mLabelsInverseMapping.add(mPC, theLabel);
-}
-
-void ARMAssembler::B(int cc, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (cc<<28) | (0xA<<24) | 0;
-}
-
-void ARMAssembler::BL(int cc, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (cc<<28) | (0xB<<24) | 0;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Prolog/Epilog & Generate...
-#endif
-
-
-void ARMAssembler::prolog()
-{
- // write dummy prolog code
- mPrologPC = mPC;
- STM(AL, FD, SP, 1, LSAVED);
-}
-
-void ARMAssembler::epilog(uint32_t touched)
-{
- touched &= LSAVED;
- if (touched) {
- // write prolog code
- uint32_t* pc = mPC;
- mPC = mPrologPC;
- STM(AL, FD, SP, 1, touched | LLR);
- mPC = pc;
- // write epilog code
- LDM(AL, FD, SP, 1, touched | LLR);
- BX(AL, LR);
- } else { // heh, no registers to save!
- // write prolog code
- uint32_t* pc = mPC;
- mPC = mPrologPC;
- MOV(AL, 0, R0, R0); // NOP
- mPC = pc;
- // write epilog code
- BX(AL, LR);
- }
-}
-
-int ARMAssembler::generate(const char* name)
-{
- // fixup all the branches
- size_t count = mBranchTargets.size();
- while (count--) {
- const branch_target_t& bt = mBranchTargets[count];
- uint32_t* target_pc = mLabels.valueFor(bt.label);
- LOG_ALWAYS_FATAL_IF(!target_pc,
- "error resolving branch targets, target_pc is null");
- int32_t offset = int32_t(target_pc - (bt.pc+2));
- *bt.pc |= offset & 0xFFFFFF;
- }
-
- mAssembly->resize( int(pc()-base())*4 );
-
- // the instruction cache is flushed by CodeCache
- const int64_t duration = ggl_system_time() - mDuration;
- const char * const format = "generated %s (%d ins) at [%p:%p] in %lld ns\n";
- ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.pf.disasm", value, "0");
- if (atoi(value) != 0) {
- printf(format, name, int(pc()-base()), base(), pc(), duration);
- disassemble(name);
- }
-
- return OK;
-}
-
-uint32_t* ARMAssembler::pcForLabel(const char* label)
-{
- return mLabels.valueFor(label);
-}
-
-// ----------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Data Processing...
-#endif
-
-void ARMAssembler::dataProcessing(int opcode, int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
- *mPC++ = (cc<<28) | (opcode<<21) | (s<<20) | (Rn<<16) | (Rd<<12) | Op2;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Multiply...
-#endif
-
-// multiply...
-void ARMAssembler::MLA(int cc, int s,
- int Rd, int Rm, int Rs, int Rn) {
- if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
- LOG_FATAL_IF(Rd==Rm, "MLA(r%u,r%u,r%u,r%u)", Rd,Rm,Rs,Rn);
- *mPC++ = (cc<<28) | (1<<21) | (s<<20) |
- (Rd<<16) | (Rn<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::MUL(int cc, int s,
- int Rd, int Rm, int Rs) {
- if (Rd == Rm) { int t = Rm; Rm=Rs; Rs=t; }
- LOG_FATAL_IF(Rd==Rm, "MUL(r%u,r%u,r%u)", Rd,Rm,Rs);
- *mPC++ = (cc<<28) | (s<<20) | (Rd<<16) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "UMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- *mPC++ = (cc<<28) | (1<<23) | (s<<20) |
- (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
- (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
- (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-void ARMAssembler::SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
- (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Branches...
-#endif
-
-// branches...
-void ARMAssembler::B(int cc, uint32_t* pc)
-{
- int32_t offset = int32_t(pc - (mPC+2));
- *mPC++ = (cc<<28) | (0xA<<24) | (offset & 0xFFFFFF);
-}
-
-void ARMAssembler::BL(int cc, uint32_t* pc)
-{
- int32_t offset = int32_t(pc - (mPC+2));
- *mPC++ = (cc<<28) | (0xB<<24) | (offset & 0xFFFFFF);
-}
-
-void ARMAssembler::BX(int cc, int Rn)
-{
- *mPC++ = (cc<<28) | 0x12FFF10 | Rn;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Data Transfer...
-#endif
-
-// data transfert...
-void ARMAssembler::LDR(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (1<<26) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
-}
-void ARMAssembler::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (1<<20) | (Rn<<16) | (Rd<<12) | offset;
-}
-void ARMAssembler::STR(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (1<<26) | (Rn<<16) | (Rd<<12) | offset;
-}
-void ARMAssembler::STRB(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (1<<26) | (1<<22) | (Rn<<16) | (Rd<<12) | offset;
-}
-
-void ARMAssembler::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
-}
-void ARMAssembler::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xD0 | offset;
-}
-void ARMAssembler::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (1<<20) | (Rn<<16) | (Rd<<12) | 0xF0 | offset;
-}
-void ARMAssembler::STRH(int cc, int Rd, int Rn, uint32_t offset) {
- *mPC++ = (cc<<28) | (Rn<<16) | (Rd<<12) | 0xB0 | offset;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Block Data Transfer...
-#endif
-
-// block data transfer...
-void ARMAssembler::LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list)
-{ // ED FD EA FA IB IA DB DA
- const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
- const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
- *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
- (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
-}
-
-void ARMAssembler::STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list)
-{ // ED FD EA FA IB IA DB DA
- const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
- const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
- *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
- (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Special...
-#endif
-
-// special...
-void ARMAssembler::SWP(int cc, int Rn, int Rd, int Rm) {
- *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-}
-void ARMAssembler::SWPB(int cc, int Rn, int Rd, int Rm) {
- *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
-}
-void ARMAssembler::SWI(int cc, uint32_t comment) {
- *mPC++ = (cc<<28) | (0xF<<24) | comment;
-}
-
-#if 0
-#pragma mark -
-#pragma mark DSP instructions...
-#endif
-
-// DSP instructions...
-void ARMAssembler::PLD(int Rn, uint32_t offset) {
- LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
- "PLD only P=1, W=0");
- *mPC++ = 0xF550F000 | (Rn<<16) | offset;
-}
-
-void ARMAssembler::CLZ(int cc, int Rd, int Rm)
-{
- *mPC++ = (cc<<28) | 0x16F0F10| (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QADD(int cc, int Rd, int Rm, int Rn)
-{
- *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QDADD(int cc, int Rd, int Rm, int Rn)
-{
- *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QSUB(int cc, int Rd, int Rm, int Rn)
-{
- *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::QDSUB(int cc, int Rd, int Rm, int Rn)
-{
- *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
-}
-
-void ARMAssembler::SMUL(int cc, int xy,
- int Rd, int Rm, int Rs)
-{
- *mPC++ = (cc<<28) | 0x1600080 | (Rd<<16) | (Rs<<8) | (xy<<4) | Rm;
-}
-
-void ARMAssembler::SMULW(int cc, int y,
- int Rd, int Rm, int Rs)
-{
- *mPC++ = (cc<<28) | 0x12000A0 | (Rd<<16) | (Rs<<8) | (y<<4) | Rm;
-}
-
-void ARMAssembler::SMLA(int cc, int xy,
- int Rd, int Rm, int Rs, int Rn)
-{
- *mPC++ = (cc<<28) | 0x1000080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (xy<<4) | Rm;
-}
-
-void ARMAssembler::SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm)
-{
- *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
-}
-
-void ARMAssembler::SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn)
-{
- *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Byte/half word extract and extend (ARMv6+ only)...
-#endif
-
-void ARMAssembler::UXTB16(int cc, int Rd, int Rm, int rotate)
-{
- *mPC++ = (cc<<28) | 0x6CF0070 | (Rd<<12) | ((rotate >> 3) << 10) | Rm;
-}
-#if 0
-#pragma mark -
-#pragma mark Bit manipulation (ARMv7+ only)...
-#endif
-
-// Bit manipulation (ARMv7+ only)...
-void ARMAssembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
-{
- *mPC++ = (cc<<28) | 0x7E00000 | ((width-1)<<16) | (Rd<<12) | (lsb<<7) | 0x50 | Rn;
-}
-
-#if 0
-#pragma mark -
-#pragma mark Addressing modes...
-#endif
-
-int ARMAssembler::buildImmediate(
- uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
- rot = 0;
- imm = immediate;
- if (imm > 0x7F) { // skip the easy cases
- while (!(imm&3) || (imm&0xFC000000)) {
- uint32_t newval;
- newval = imm >> 2;
- newval |= (imm&3) << 30;
- imm = newval;
- rot += 2;
- if (rot == 32) {
- rot = 0;
- break;
- }
- }
- }
- rot = (16 - (rot>>1)) & 0xF;
-
- if (imm>=0x100)
- return -EINVAL;
-
- if (((imm>>(rot<<1)) | (imm<<(32-(rot<<1)))) != immediate)
- return -1;
-
- return 0;
-}
-
-// shifters...
-
-bool ARMAssembler::isValidImmediate(uint32_t immediate)
-{
- uint32_t rot, imm;
- return buildImmediate(immediate, rot, imm) == 0;
-}
-
-uint32_t ARMAssembler::imm(uint32_t immediate)
-{
- uint32_t rot, imm;
- int err = buildImmediate(immediate, rot, imm);
-
- LOG_ALWAYS_FATAL_IF(err==-EINVAL,
- "immediate %08x cannot be encoded",
- immediate);
-
- LOG_ALWAYS_FATAL_IF(err,
- "immediate (%08x) encoding bogus!",
- immediate);
-
- return (1<<25) | (rot<<8) | imm;
-}
-
-uint32_t ARMAssembler::reg_imm(int Rm, int type, uint32_t shift)
-{
- return ((shift&0x1F)<<7) | ((type&0x3)<<5) | (Rm&0xF);
-}
-
-uint32_t ARMAssembler::reg_rrx(int Rm)
-{
- return (ROR<<5) | (Rm&0xF);
-}
-
-uint32_t ARMAssembler::reg_reg(int Rm, int type, int Rs)
-{
- return ((Rs&0xF)<<8) | ((type&0x3)<<5) | (1<<4) | (Rm&0xF);
-}
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
-uint32_t ARMAssembler::immed12_pre(int32_t immed12, int W)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
- "LDR(B)/STR(B)/PLD immediate too big (%08x)",
- immed12);
- return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
- ((W&1)<<21) | (abs(immed12)&0x7FF);
-}
-
-uint32_t ARMAssembler::immed12_post(int32_t immed12)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
- "LDR(B)/STR(B)/PLD immediate too big (%08x)",
- immed12);
-
- return (((uint32_t(immed12)>>31)^1)<<23) | (abs(immed12)&0x7FF);
-}
-
-uint32_t ARMAssembler::reg_scale_pre(int Rm, int type,
- uint32_t shift, int W)
-{
- return (1<<25) | (1<<24) |
- (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) |
- reg_imm(abs(Rm), type, shift);
-}
-
-uint32_t ARMAssembler::reg_scale_post(int Rm, int type, uint32_t shift)
-{
- return (1<<25) | (((uint32_t(Rm)>>31)^1)<<23) | reg_imm(abs(Rm), type, shift);
-}
-
-// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
-uint32_t ARMAssembler::immed8_pre(int32_t immed8, int W)
-{
- uint32_t offset = abs(immed8);
-
- LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
- "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
- immed8);
-
- return (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
- ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
-}
-
-uint32_t ARMAssembler::immed8_post(int32_t immed8)
-{
- uint32_t offset = abs(immed8);
-
- LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
- "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
- immed8);
-
- return (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
- (((offset&0xF0)<<4) | (offset&0xF));
-}
-
-uint32_t ARMAssembler::reg_pre(int Rm, int W)
-{
- return (1<<24) | (((uint32_t(Rm)>>31)^1)<<23) | ((W&1)<<21) | (abs(Rm)&0xF);
-}
-
-uint32_t ARMAssembler::reg_post(int Rm)
-{
- return (((uint32_t(Rm)>>31)^1)<<23) | (abs(Rm)&0xF);
-}
-
-}; // namespace android
diff --git a/libpixelflinger/codeflinger/ARMAssembler.h b/libpixelflinger/codeflinger/ARMAssembler.h
deleted file mode 100644
index 76acf7e..0000000
--- a/libpixelflinger/codeflinger/ARMAssembler.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssembler.h
-**
-** Copyright 2006, 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 ANDROID_ARMASSEMBLER_H
-#define ANDROID_ARMASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "tinyutils/smartpointer.h"
-#include "utils/Vector.h"
-#include "utils/KeyedVector.h"
-
-#include "ARMAssemblerInterface.h"
-#include "CodeCache.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ARMAssembler : public ARMAssemblerInterface
-{
-public:
- explicit ARMAssembler(const sp<Assembly>& assembly);
- virtual ~ARMAssembler();
-
- uint32_t* base() const;
- uint32_t* pc() const;
-
-
- void disassemble(const char* name);
-
- // ------------------------------------------------------------------------
- // ARMAssemblerInterface...
- // ------------------------------------------------------------------------
-
- virtual void reset();
-
- virtual int generate(const char* name);
- virtual int getCodegenArch();
-
- virtual void prolog();
- virtual void epilog(uint32_t touched);
- virtual void comment(const char* string);
-
-
- // -----------------------------------------------------------------------
- // shifters and addressing modes
- // -----------------------------------------------------------------------
-
- // shifters...
- virtual bool isValidImmediate(uint32_t immed);
- virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
-
- virtual uint32_t imm(uint32_t immediate);
- virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
- virtual uint32_t reg_rrx(int Rm);
- virtual uint32_t reg_reg(int Rm, int type, int Rs);
-
- // addressing modes...
- // LDR(B)/STR(B)/PLD
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed12_pre(int32_t immed12, int W=0);
- virtual uint32_t immed12_post(int32_t immed12);
- virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
- virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
-
- // LDRH/LDRSB/LDRSH/STRH
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed8_pre(int32_t immed8, int W=0);
- virtual uint32_t immed8_post(int32_t immed8);
- virtual uint32_t reg_pre(int Rm, int W=0);
- virtual uint32_t reg_post(int Rm);
-
-
- virtual void dataProcessing(int opcode, int cc, int s,
- int Rd, int Rn,
- uint32_t Op2);
- virtual void MLA(int cc, int s,
- int Rd, int Rm, int Rs, int Rn);
- virtual void MUL(int cc, int s,
- int Rd, int Rm, int Rs);
- virtual void UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
-
- virtual void B(int cc, uint32_t* pc);
- virtual void BL(int cc, uint32_t* pc);
- virtual void BX(int cc, int Rn);
- virtual void label(const char* theLabel);
- virtual void B(int cc, const char* label);
- virtual void BL(int cc, const char* label);
-
- virtual uint32_t* pcForLabel(const char* label);
-
- virtual void LDR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void LDRB(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void STR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void STRB(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void LDRH (int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
- virtual void LDRSB(int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
- virtual void LDRSH(int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
- virtual void STRH (int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
-
-
- virtual void LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
- virtual void STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
-
- virtual void SWP(int cc, int Rn, int Rd, int Rm);
- virtual void SWPB(int cc, int Rn, int Rd, int Rm);
- virtual void SWI(int cc, uint32_t comment);
-
- virtual void PLD(int Rn, uint32_t offset);
- virtual void CLZ(int cc, int Rd, int Rm);
- virtual void QADD(int cc, int Rd, int Rm, int Rn);
- virtual void QDADD(int cc, int Rd, int Rm, int Rn);
- virtual void QSUB(int cc, int Rd, int Rm, int Rn);
- virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
- virtual void SMUL(int cc, int xy,
- int Rd, int Rm, int Rs);
- virtual void SMULW(int cc, int y,
- int Rd, int Rm, int Rs);
- virtual void SMLA(int cc, int xy,
- int Rd, int Rm, int Rs, int Rn);
- virtual void SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm);
- virtual void SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn);
- virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
- virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
-
-private:
- ARMAssembler(const ARMAssembler& rhs);
- ARMAssembler& operator = (const ARMAssembler& rhs);
-
- sp<Assembly> mAssembly;
- uint32_t* mBase;
- uint32_t* mPC;
- uint32_t* mPrologPC;
- int64_t mDuration;
-
- struct branch_target_t {
- inline branch_target_t() : label(0), pc(0) { }
- inline branch_target_t(const char* l, uint32_t* p)
- : label(l), pc(p) { }
- const char* label;
- uint32_t* pc;
- };
-
- Vector<branch_target_t> mBranchTargets;
- KeyedVector< const char*, uint32_t* > mLabels;
- KeyedVector< uint32_t*, const char* > mLabelsInverseMapping;
- KeyedVector< uint32_t*, const char* > mComments;
-};
-
-}; // namespace android
-
-#endif //ANDROID_ARMASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp b/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
deleted file mode 100644
index c96cf4b..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerInterface.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-#define LOG_TAG "pixelflinger-code"
-
-#include <errno.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "ARMAssemblerInterface.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-ARMAssemblerInterface::~ARMAssemblerInterface()
-{
-}
-
-// --------------------------------------------------------------------
-
-// The following two functions are static and used for initializers
-// in the original ARM code. The above versions (without __), are now
-// virtual, and can be overridden in the MIPS code. But since these are
-// needed at initialization time, they must be static. Not thrilled with
-// this implementation, but it works...
-
-uint32_t ARMAssemblerInterface::__immed12_pre(int32_t immed12, int W)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
- "LDR(B)/STR(B)/PLD immediate too big (%08x)",
- immed12);
- return (1<<24) | (((uint32_t(immed12)>>31)^1)<<23) |
- ((W&1)<<21) | (abs(immed12)&0x7FF);
-}
-
-uint32_t ARMAssemblerInterface::__immed8_pre(int32_t immed8, int W)
-{
- uint32_t offset = abs(immed8);
-
- LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
- "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
- immed8);
-
- return (1<<24) | (1<<22) | (((uint32_t(immed8)>>31)^1)<<23) |
- ((W&1)<<21) | (((offset&0xF0)<<4)|(offset&0xF));
-}
-
-// The following four functions are required for address manipulation
-// These are virtual functions, which can be overridden by architectures
-// that need special handling of address values (e.g. 64-bit arch)
-
-void ARMAssemblerInterface::ADDR_LDR(int cc, int Rd,
- int Rn, uint32_t offset)
-{
- LDR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerInterface::ADDR_STR(int cc, int Rd,
- int Rn, uint32_t offset)
-{
- STR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerInterface::ADDR_ADD(int cc, int s,
- int Rd, int Rn, uint32_t Op2)
-{
- dataProcessing(opADD, cc, s, Rd, Rn, Op2);
-}
-void ARMAssemblerInterface::ADDR_SUB(int cc, int s,
- int Rd, int Rn, uint32_t Op2)
-{
- dataProcessing(opSUB, cc, s, Rd, Rn, Op2);
-}
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/ARMAssemblerInterface.h b/libpixelflinger/codeflinger/ARMAssemblerInterface.h
deleted file mode 100644
index 72935ac..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerInterface.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerInterface.h
-**
-** Copyright 2006, 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 ANDROID_ARMASSEMBLER_INTERFACE_H
-#define ANDROID_ARMASSEMBLER_INTERFACE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ARMAssemblerInterface
-{
-public:
- virtual ~ARMAssemblerInterface();
-
- enum {
- EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
- HS = CS,
- LO = CC
- };
- enum {
- S = 1
- };
- enum {
- LSL, LSR, ASR, ROR
- };
- enum {
- ED, FD, EA, FA,
- IB, IA, DB, DA
- };
- enum {
- R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15,
- SP = R13,
- LR = R14,
- PC = R15
- };
- enum {
- #define LIST(rr) L##rr=1<<rr
- LIST(R0), LIST(R1), LIST(R2), LIST(R3), LIST(R4), LIST(R5), LIST(R6),
- LIST(R7), LIST(R8), LIST(R9), LIST(R10), LIST(R11), LIST(R12),
- LIST(R13), LIST(R14), LIST(R15),
- LIST(SP), LIST(LR), LIST(PC),
- #undef LIST
- LSAVED = LR4|LR5|LR6|LR7|LR8|LR9|LR10|LR11 | LLR
- };
-
- enum {
- CODEGEN_ARCH_ARM = 1, CODEGEN_ARCH_MIPS, CODEGEN_ARCH_ARM64, CODEGEN_ARCH_MIPS64
- };
-
- // -----------------------------------------------------------------------
- // shifters and addressing modes
- // -----------------------------------------------------------------------
-
- // these static versions are used for initializers on LDxx/STxx below
- static uint32_t __immed12_pre(int32_t immed12, int W=0);
- static uint32_t __immed8_pre(int32_t immed12, int W=0);
-
- virtual bool isValidImmediate(uint32_t immed) = 0;
- virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm) = 0;
-
- virtual uint32_t imm(uint32_t immediate) = 0;
- virtual uint32_t reg_imm(int Rm, int type, uint32_t shift) = 0;
- virtual uint32_t reg_rrx(int Rm) = 0;
- virtual uint32_t reg_reg(int Rm, int type, int Rs) = 0;
-
- // addressing modes...
- // LDR(B)/STR(B)/PLD
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed12_pre(int32_t immed12, int W=0) = 0;
- virtual uint32_t immed12_post(int32_t immed12) = 0;
- virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0) = 0;
- virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0) = 0;
-
- // LDRH/LDRSB/LDRSH/STRH
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed8_pre(int32_t immed8, int W=0) = 0;
- virtual uint32_t immed8_post(int32_t immed8) = 0;
- virtual uint32_t reg_pre(int Rm, int W=0) = 0;
- virtual uint32_t reg_post(int Rm) = 0;
-
- // -----------------------------------------------------------------------
- // basic instructions & code generation
- // -----------------------------------------------------------------------
-
- // generate the code
- virtual void reset() = 0;
- virtual int generate(const char* name) = 0;
- virtual void disassemble(const char* name) = 0;
- virtual int getCodegenArch() = 0;
-
- // construct prolog and epilog
- virtual void prolog() = 0;
- virtual void epilog(uint32_t touched) = 0;
- virtual void comment(const char* string) = 0;
-
- // data processing...
- enum {
- opAND, opEOR, opSUB, opRSB, opADD, opADC, opSBC, opRSC,
- opTST, opTEQ, opCMP, opCMN, opORR, opMOV, opBIC, opMVN,
- opADD64, opSUB64
- };
-
- virtual void
- dataProcessing( int opcode, int cc, int s,
- int Rd, int Rn,
- uint32_t Op2) = 0;
-
- // multiply...
- virtual void MLA(int cc, int s,
- int Rd, int Rm, int Rs, int Rn) = 0;
- virtual void MUL(int cc, int s,
- int Rd, int Rm, int Rs) = 0;
- virtual void UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) = 0;
- virtual void UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) = 0;
- virtual void SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) = 0;
- virtual void SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) = 0;
-
- // branches...
- virtual void B(int cc, uint32_t* pc) = 0;
- virtual void BL(int cc, uint32_t* pc) = 0;
- virtual void BX(int cc, int Rn) = 0;
-
- virtual void label(const char* theLabel) = 0;
- virtual void B(int cc, const char* label) = 0;
- virtual void BL(int cc, const char* label) = 0;
-
- // valid only after generate() has been called
- virtual uint32_t* pcForLabel(const char* label) = 0;
-
- // data transfer...
- virtual void LDR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0)) = 0;
- virtual void LDRB(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0)) = 0;
- virtual void STR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0)) = 0;
- virtual void STRB(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0)) = 0;
-
- virtual void LDRH (int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0)) = 0;
- virtual void LDRSB(int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0)) = 0;
- virtual void LDRSH(int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0)) = 0;
- virtual void STRH (int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0)) = 0;
-
- // block data transfer...
- virtual void LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list) = 0;
- virtual void STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list) = 0;
-
- // special...
- virtual void SWP(int cc, int Rn, int Rd, int Rm) = 0;
- virtual void SWPB(int cc, int Rn, int Rd, int Rm) = 0;
- virtual void SWI(int cc, uint32_t comment) = 0;
-
- // DSP instructions...
- enum {
- // B=0, T=1
- // yx
- xyBB = 0, // 0000,
- xyTB = 2, // 0010,
- xyBT = 4, // 0100,
- xyTT = 6, // 0110,
- yB = 0, // 0000,
- yT = 4, // 0100
- };
-
- virtual void PLD(int Rn, uint32_t offset) = 0;
-
- virtual void CLZ(int cc, int Rd, int Rm) = 0;
-
- virtual void QADD(int cc, int Rd, int Rm, int Rn) = 0;
- virtual void QDADD(int cc, int Rd, int Rm, int Rn) = 0;
- virtual void QSUB(int cc, int Rd, int Rm, int Rn) = 0;
- virtual void QDSUB(int cc, int Rd, int Rm, int Rn) = 0;
-
- virtual void SMUL(int cc, int xy,
- int Rd, int Rm, int Rs) = 0;
- virtual void SMULW(int cc, int y,
- int Rd, int Rm, int Rs) = 0;
- virtual void SMLA(int cc, int xy,
- int Rd, int Rm, int Rs, int Rn) = 0;
- virtual void SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm) = 0;
- virtual void SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn) = 0;
-
- // byte/half word extract...
- virtual void UXTB16(int cc, int Rd, int Rm, int rotate) = 0;
-
- // bit manipulation...
- virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width) = 0;
-
- // -----------------------------------------------------------------------
- // convenience...
- // -----------------------------------------------------------------------
- inline void
- ADC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opADC, cc, s, Rd, Rn, Op2);
- }
- inline void
- ADD(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opADD, cc, s, Rd, Rn, Op2);
- }
- inline void
- AND(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opAND, cc, s, Rd, Rn, Op2);
- }
- inline void
- BIC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opBIC, cc, s, Rd, Rn, Op2);
- }
- inline void
- EOR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opEOR, cc, s, Rd, Rn, Op2);
- }
- inline void
- MOV(int cc, int s, int Rd, uint32_t Op2) {
- dataProcessing(opMOV, cc, s, Rd, 0, Op2);
- }
- inline void
- MVN(int cc, int s, int Rd, uint32_t Op2) {
- dataProcessing(opMVN, cc, s, Rd, 0, Op2);
- }
- inline void
- ORR(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opORR, cc, s, Rd, Rn, Op2);
- }
- inline void
- RSB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opRSB, cc, s, Rd, Rn, Op2);
- }
- inline void
- RSC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opRSC, cc, s, Rd, Rn, Op2);
- }
- inline void
- SBC(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opSBC, cc, s, Rd, Rn, Op2);
- }
- inline void
- SUB(int cc, int s, int Rd, int Rn, uint32_t Op2) {
- dataProcessing(opSUB, cc, s, Rd, Rn, Op2);
- }
- inline void
- TEQ(int cc, int Rn, uint32_t Op2) {
- dataProcessing(opTEQ, cc, 1, 0, Rn, Op2);
- }
- inline void
- TST(int cc, int Rn, uint32_t Op2) {
- dataProcessing(opTST, cc, 1, 0, Rn, Op2);
- }
- inline void
- CMP(int cc, int Rn, uint32_t Op2) {
- dataProcessing(opCMP, cc, 1, 0, Rn, Op2);
- }
- inline void
- CMN(int cc, int Rn, uint32_t Op2) {
- dataProcessing(opCMN, cc, 1, 0, Rn, Op2);
- }
-
- inline void SMULBB(int cc, int Rd, int Rm, int Rs) {
- SMUL(cc, xyBB, Rd, Rm, Rs); }
- inline void SMULTB(int cc, int Rd, int Rm, int Rs) {
- SMUL(cc, xyTB, Rd, Rm, Rs); }
- inline void SMULBT(int cc, int Rd, int Rm, int Rs) {
- SMUL(cc, xyBT, Rd, Rm, Rs); }
- inline void SMULTT(int cc, int Rd, int Rm, int Rs) {
- SMUL(cc, xyTT, Rd, Rm, Rs); }
-
- inline void SMULWB(int cc, int Rd, int Rm, int Rs) {
- SMULW(cc, yB, Rd, Rm, Rs); }
- inline void SMULWT(int cc, int Rd, int Rm, int Rs) {
- SMULW(cc, yT, Rd, Rm, Rs); }
-
- inline void
- SMLABB(int cc, int Rd, int Rm, int Rs, int Rn) {
- SMLA(cc, xyBB, Rd, Rm, Rs, Rn); }
- inline void
- SMLATB(int cc, int Rd, int Rm, int Rs, int Rn) {
- SMLA(cc, xyTB, Rd, Rm, Rs, Rn); }
- inline void
- SMLABT(int cc, int Rd, int Rm, int Rs, int Rn) {
- SMLA(cc, xyBT, Rd, Rm, Rs, Rn); }
- inline void
- SMLATT(int cc, int Rd, int Rm, int Rs, int Rn) {
- SMLA(cc, xyTT, Rd, Rm, Rs, Rn); }
-
- inline void
- SMLALBB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
- SMLAL(cc, xyBB, RdHi, RdLo, Rs, Rm); }
- inline void
- SMLALTB(int cc, int RdHi, int RdLo, int Rs, int Rm) {
- SMLAL(cc, xyTB, RdHi, RdLo, Rs, Rm); }
- inline void
- SMLALBT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
- SMLAL(cc, xyBT, RdHi, RdLo, Rs, Rm); }
- inline void
- SMLALTT(int cc, int RdHi, int RdLo, int Rs, int Rm) {
- SMLAL(cc, xyTT, RdHi, RdLo, Rs, Rm); }
-
- inline void
- SMLAWB(int cc, int Rd, int Rm, int Rs, int Rn) {
- SMLAW(cc, yB, Rd, Rm, Rs, Rn); }
- inline void
- SMLAWT(int cc, int Rd, int Rm, int Rs, int Rn) {
- SMLAW(cc, yT, Rd, Rm, Rs, Rn); }
-
- // Address loading/storing/manipulation
- virtual void ADDR_LDR(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void ADDR_STR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void ADDR_ADD(int cc, int s, int Rd,
- int Rn, uint32_t Op2);
- virtual void ADDR_SUB(int cc, int s, int Rd,
- int Rn, uint32_t Op2);
-};
-
-}; // namespace android
-
-#endif //ANDROID_ARMASSEMBLER_INTERFACE_H
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp b/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
deleted file mode 100644
index 816de48..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerProxy.cpp
-**
-** Copyright 2006, 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/types.h>
-
-#include "ARMAssemblerProxy.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-ARMAssemblerProxy::ARMAssemblerProxy()
- : mTarget(0)
-{
-}
-
-ARMAssemblerProxy::ARMAssemblerProxy(ARMAssemblerInterface* target)
- : mTarget(target)
-{
-}
-
-ARMAssemblerProxy::~ARMAssemblerProxy()
-{
- delete mTarget;
-}
-
-void ARMAssemblerProxy::setTarget(ARMAssemblerInterface* target)
-{
- delete mTarget;
- mTarget = target;
-}
-
-void ARMAssemblerProxy::reset() {
- mTarget->reset();
-}
-int ARMAssemblerProxy::generate(const char* name) {
- return mTarget->generate(name);
-}
-void ARMAssemblerProxy::disassemble(const char* name) {
- return mTarget->disassemble(name);
-}
-int ARMAssemblerProxy::getCodegenArch()
-{
- return mTarget->getCodegenArch();
-}
-void ARMAssemblerProxy::prolog() {
- mTarget->prolog();
-}
-void ARMAssemblerProxy::epilog(uint32_t touched) {
- mTarget->epilog(touched);
-}
-void ARMAssemblerProxy::comment(const char* string) {
- mTarget->comment(string);
-}
-
-
-
-// addressing modes
-
-bool ARMAssemblerProxy::isValidImmediate(uint32_t immed)
-{
- return mTarget->isValidImmediate(immed);
-}
-
-int ARMAssemblerProxy::buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm)
-{
- return mTarget->buildImmediate(i, rot, imm);
-}
-
-
-
-uint32_t ARMAssemblerProxy::imm(uint32_t immediate)
-{
- return mTarget->imm(immediate);
-}
-
-uint32_t ARMAssemblerProxy::reg_imm(int Rm, int type, uint32_t shift)
-{
- return mTarget->reg_imm(Rm, type, shift);
-}
-
-uint32_t ARMAssemblerProxy::reg_rrx(int Rm)
-{
- return mTarget->reg_rrx(Rm);
-}
-
-uint32_t ARMAssemblerProxy::reg_reg(int Rm, int type, int Rs)
-{
- return mTarget->reg_reg(Rm, type, Rs);
-}
-
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD
-// (immediate and Rm can be negative, which indicates U=0)
-uint32_t ARMAssemblerProxy::immed12_pre(int32_t immed12, int W)
-{
- return mTarget->immed12_pre(immed12, W);
-}
-
-uint32_t ARMAssemblerProxy::immed12_post(int32_t immed12)
-{
- return mTarget->immed12_post(immed12);
-}
-
-uint32_t ARMAssemblerProxy::reg_scale_pre(int Rm, int type, uint32_t shift, int W)
-{
- return mTarget->reg_scale_pre(Rm, type, shift, W);
-}
-
-uint32_t ARMAssemblerProxy::reg_scale_post(int Rm, int type, uint32_t shift)
-{
- return mTarget->reg_scale_post(Rm, type, shift);
-}
-
-
-// LDRH/LDRSB/LDRSH/STRH
-// (immediate and Rm can be negative, which indicates U=0)
-uint32_t ARMAssemblerProxy::immed8_pre(int32_t immed8, int W)
-{
- return mTarget->immed8_pre(immed8, W);
-}
-
-uint32_t ARMAssemblerProxy::immed8_post(int32_t immed8)
-{
- return mTarget->immed8_post(immed8);
-}
-
-uint32_t ARMAssemblerProxy::reg_pre(int Rm, int W)
-{
- return mTarget->reg_pre(Rm, W);
-}
-
-uint32_t ARMAssemblerProxy::reg_post(int Rm)
-{
- return mTarget->reg_post(Rm);
-}
-
-
-//------------------------------------------------------------------------
-
-
-
-void ARMAssemblerProxy::dataProcessing( int opcode, int cc, int s,
- int Rd, int Rn, uint32_t Op2)
-{
- mTarget->dataProcessing(opcode, cc, s, Rd, Rn, Op2);
-}
-
-void ARMAssemblerProxy::MLA(int cc, int s, int Rd, int Rm, int Rs, int Rn) {
- mTarget->MLA(cc, s, Rd, Rm, Rs, Rn);
-}
-void ARMAssemblerProxy::MUL(int cc, int s, int Rd, int Rm, int Rs) {
- mTarget->MUL(cc, s, Rd, Rm, Rs);
-}
-void ARMAssemblerProxy::UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- mTarget->UMULL(cc, s, RdLo, RdHi, Rm, Rs);
-}
-void ARMAssemblerProxy::UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- mTarget->UMUAL(cc, s, RdLo, RdHi, Rm, Rs);
-}
-void ARMAssemblerProxy::SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- mTarget->SMULL(cc, s, RdLo, RdHi, Rm, Rs);
-}
-void ARMAssemblerProxy::SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- mTarget->SMUAL(cc, s, RdLo, RdHi, Rm, Rs);
-}
-
-void ARMAssemblerProxy::B(int cc, uint32_t* pc) {
- mTarget->B(cc, pc);
-}
-void ARMAssemblerProxy::BL(int cc, uint32_t* pc) {
- mTarget->BL(cc, pc);
-}
-void ARMAssemblerProxy::BX(int cc, int Rn) {
- mTarget->BX(cc, Rn);
-}
-void ARMAssemblerProxy::label(const char* theLabel) {
- mTarget->label(theLabel);
-}
-void ARMAssemblerProxy::B(int cc, const char* label) {
- mTarget->B(cc, label);
-}
-void ARMAssemblerProxy::BL(int cc, const char* label) {
- mTarget->BL(cc, label);
-}
-
-uint32_t* ARMAssemblerProxy::pcForLabel(const char* label) {
- return mTarget->pcForLabel(label);
-}
-
-void ARMAssemblerProxy::LDR(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->LDR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRB(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->LDRB(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::STR(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->STR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::STRB(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->STRB(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRH(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->LDRH(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRSB(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->LDRSB(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDRSH(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->LDRSH(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::STRH(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->STRH(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::LDM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
- mTarget->LDM(cc, dir, Rn, W, reg_list);
-}
-void ARMAssemblerProxy::STM(int cc, int dir, int Rn, int W, uint32_t reg_list) {
- mTarget->STM(cc, dir, Rn, W, reg_list);
-}
-
-void ARMAssemblerProxy::SWP(int cc, int Rn, int Rd, int Rm) {
- mTarget->SWP(cc, Rn, Rd, Rm);
-}
-void ARMAssemblerProxy::SWPB(int cc, int Rn, int Rd, int Rm) {
- mTarget->SWPB(cc, Rn, Rd, Rm);
-}
-void ARMAssemblerProxy::SWI(int cc, uint32_t comment) {
- mTarget->SWI(cc, comment);
-}
-
-
-void ARMAssemblerProxy::PLD(int Rn, uint32_t offset) {
- mTarget->PLD(Rn, offset);
-}
-void ARMAssemblerProxy::CLZ(int cc, int Rd, int Rm) {
- mTarget->CLZ(cc, Rd, Rm);
-}
-void ARMAssemblerProxy::QADD(int cc, int Rd, int Rm, int Rn) {
- mTarget->QADD(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::QDADD(int cc, int Rd, int Rm, int Rn) {
- mTarget->QDADD(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::QSUB(int cc, int Rd, int Rm, int Rn) {
- mTarget->QSUB(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::QDSUB(int cc, int Rd, int Rm, int Rn) {
- mTarget->QDSUB(cc, Rd, Rm, Rn);
-}
-void ARMAssemblerProxy::SMUL(int cc, int xy, int Rd, int Rm, int Rs) {
- mTarget->SMUL(cc, xy, Rd, Rm, Rs);
-}
-void ARMAssemblerProxy::SMULW(int cc, int y, int Rd, int Rm, int Rs) {
- mTarget->SMULW(cc, y, Rd, Rm, Rs);
-}
-void ARMAssemblerProxy::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn) {
- mTarget->SMLA(cc, xy, Rd, Rm, Rs, Rn);
-}
-void ARMAssemblerProxy::SMLAL( int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm) {
- mTarget->SMLAL(cc, xy, RdHi, RdLo, Rs, Rm);
-}
-void ARMAssemblerProxy::SMLAW(int cc, int y, int Rd, int Rm, int Rs, int Rn) {
- mTarget->SMLAW(cc, y, Rd, Rm, Rs, Rn);
-}
-
-void ARMAssemblerProxy::UXTB16(int cc, int Rd, int Rm, int rotate) {
- mTarget->UXTB16(cc, Rd, Rm, rotate);
-}
-
-void ARMAssemblerProxy::UBFX(int cc, int Rd, int Rn, int lsb, int width) {
- mTarget->UBFX(cc, Rd, Rn, lsb, width);
-}
-
-void ARMAssemblerProxy::ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->ADDR_LDR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::ADDR_STR(int cc, int Rd, int Rn, uint32_t offset) {
- mTarget->ADDR_STR(cc, Rd, Rn, offset);
-}
-void ARMAssemblerProxy::ADDR_ADD(int cc, int s, int Rd, int Rn, uint32_t Op2){
- mTarget->ADDR_ADD(cc, s, Rd, Rn, Op2);
-}
-void ARMAssemblerProxy::ADDR_SUB(int cc, int s, int Rd, int Rn, uint32_t Op2){
- mTarget->ADDR_SUB(cc, s, Rd, Rn, Op2);
-}
-
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/ARMAssemblerProxy.h b/libpixelflinger/codeflinger/ARMAssemblerProxy.h
deleted file mode 100644
index 10d0390..0000000
--- a/libpixelflinger/codeflinger/ARMAssemblerProxy.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/* libs/pixelflinger/codeflinger/ARMAssemblerProxy.h
-**
-** Copyright 2006, 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 ANDROID_ARMASSEMBLER_PROXY_H
-#define ANDROID_ARMASSEMBLER_PROXY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "ARMAssemblerInterface.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ARMAssemblerProxy : public ARMAssemblerInterface
-{
-public:
- // ARMAssemblerProxy take ownership of the target
-
- ARMAssemblerProxy();
- explicit ARMAssemblerProxy(ARMAssemblerInterface* target);
- virtual ~ARMAssemblerProxy();
-
- void setTarget(ARMAssemblerInterface* target);
-
- virtual void reset();
- virtual int generate(const char* name);
- virtual void disassemble(const char* name);
- virtual int getCodegenArch();
-
- virtual void prolog();
- virtual void epilog(uint32_t touched);
- virtual void comment(const char* string);
-
- // -----------------------------------------------------------------------
- // shifters and addressing modes
- // -----------------------------------------------------------------------
-
- virtual bool isValidImmediate(uint32_t immed);
- virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
-
- virtual uint32_t imm(uint32_t immediate);
- virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
- virtual uint32_t reg_rrx(int Rm);
- virtual uint32_t reg_reg(int Rm, int type, int Rs);
-
- // addressing modes...
- // LDR(B)/STR(B)/PLD
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed12_pre(int32_t immed12, int W=0);
- virtual uint32_t immed12_post(int32_t immed12);
- virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
- virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
-
- // LDRH/LDRSB/LDRSH/STRH
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed8_pre(int32_t immed8, int W=0);
- virtual uint32_t immed8_post(int32_t immed8);
- virtual uint32_t reg_pre(int Rm, int W=0);
- virtual uint32_t reg_post(int Rm);
-
-
- virtual void dataProcessing(int opcode, int cc, int s,
- int Rd, int Rn,
- uint32_t Op2);
- virtual void MLA(int cc, int s,
- int Rd, int Rm, int Rs, int Rn);
- virtual void MUL(int cc, int s,
- int Rd, int Rm, int Rs);
- virtual void UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
-
- virtual void B(int cc, uint32_t* pc);
- virtual void BL(int cc, uint32_t* pc);
- virtual void BX(int cc, int Rn);
- virtual void label(const char* theLabel);
- virtual void B(int cc, const char* label);
- virtual void BL(int cc, const char* label);
-
- uint32_t* pcForLabel(const char* label);
-
- virtual void LDR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void LDRB(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void STR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void STRB(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void LDRH (int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
- virtual void LDRSB(int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
- virtual void LDRSH(int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
- virtual void STRH (int cc, int Rd,
- int Rn, uint32_t offset = __immed8_pre(0));
- virtual void LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
- virtual void STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
-
- virtual void SWP(int cc, int Rn, int Rd, int Rm);
- virtual void SWPB(int cc, int Rn, int Rd, int Rm);
- virtual void SWI(int cc, uint32_t comment);
-
- virtual void PLD(int Rn, uint32_t offset);
- virtual void CLZ(int cc, int Rd, int Rm);
- virtual void QADD(int cc, int Rd, int Rm, int Rn);
- virtual void QDADD(int cc, int Rd, int Rm, int Rn);
- virtual void QSUB(int cc, int Rd, int Rm, int Rn);
- virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
- virtual void SMUL(int cc, int xy,
- int Rd, int Rm, int Rs);
- virtual void SMULW(int cc, int y,
- int Rd, int Rm, int Rs);
- virtual void SMLA(int cc, int xy,
- int Rd, int Rm, int Rs, int Rn);
- virtual void SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm);
- virtual void SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn);
-
- virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
- virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
-
- virtual void ADDR_LDR(int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void ADDR_STR (int cc, int Rd,
- int Rn, uint32_t offset = __immed12_pre(0));
- virtual void ADDR_ADD(int cc, int s, int Rd,
- int Rn, uint32_t Op2);
- virtual void ADDR_SUB(int cc, int s, int Rd,
- int Rn, uint32_t Op2);
-
-private:
- ARMAssemblerInterface* mTarget;
-};
-
-}; // namespace android
-
-#endif //ANDROID_ARMASSEMBLER_PROXY_H
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.cpp b/libpixelflinger/codeflinger/Arm64Assembler.cpp
deleted file mode 100644
index 8926776..0000000
--- a/libpixelflinger/codeflinger/Arm64Assembler.cpp
+++ /dev/null
@@ -1,1240 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#define LOG_TAG "ArmToArm64Assembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "codeflinger/Arm64Assembler.h"
-#include "codeflinger/Arm64Disassembler.h"
-#include "codeflinger/CodeCache.h"
-
-/*
-** --------------------------------------------
-** Support for Arm64 in GGLAssembler JIT
-** --------------------------------------------
-**
-** Approach
-** - GGLAssembler and associated files are largely un-changed.
-** - A translator class maps ArmAssemblerInterface calls to
-** generate Arm64 instructions.
-**
-** ----------------------
-** ArmToArm64Assembler
-** ----------------------
-**
-** - Subclassed from ArmAssemblerInterface
-**
-** - Translates each ArmAssemblerInterface call to generate
-** one or more Arm64 instructions as necessary.
-**
-** - Does not implement ArmAssemblerInterface portions unused by GGLAssembler
-** It calls NOT_IMPLEMENTED() for such cases, which in turn logs
-** a fatal message.
-**
-** - Uses A64_.. series of functions to generate instruction machine code
-** for Arm64 instructions. These functions also log the instruction
-** to LOG, if ARM64_ASM_DEBUG define is set to 1
-**
-** - Dumps machine code and eqvt assembly if "debug.pf.disasm" option is set
-** It uses arm64_disassemble to perform disassembly
-**
-** - Uses register 13 (SP in ARM), 15 (PC in ARM), 16, 17 for storing
-** intermediate results. GGLAssembler does not use SP and PC as these
-** registers are marked as reserved. The temporary registers are not
-** saved/restored on stack as these are caller-saved registers in Arm64
-**
-** - Uses CSEL instruction to support conditional execution. The result is
-** stored in a temporary register and then copied to the target register
-** if the condition is true.
-**
-** - In the case of conditional data transfer instructions, conditional
-** branch is used to skip over instruction, if the condition is false
-**
-** - Wherever possible, immediate values are transferred to temporary
-** register prior to processing. This simplifies overall implementation
-** as instructions requiring immediate values are converted to
-** move immediate instructions followed by register-register instruction.
-**
-** --------------------------------------------
-** ArmToArm64Assembler unit test bench
-** --------------------------------------------
-**
-** - Tests ArmToArm64Assembler interface for all the possible
-** ways in which GGLAssembler uses ArmAssemblerInterface interface.
-**
-** - Uses test jacket (written in assembly) to set the registers,
-** condition flags prior to calling generated instruction. It also
-** copies registers and flags at the end of execution. Caller then
-** checks if generated code performed correct operation based on
-** output registers and flags.
-**
-** - Broadly contains three type of tests, (i) data operation tests
-** (ii) data transfer tests and (iii) LDM/STM tests.
-**
-** ----------------------
-** Arm64 disassembler
-** ----------------------
-** - This disassembler disassembles only those machine codes which can be
-** generated by ArmToArm64Assembler. It has a unit testbench which
-** tests all the instructions supported by the disassembler.
-**
-** ------------------------------------------------------------------
-** ARMAssembler/ARMAssemblerInterface/ARMAssemblerProxy changes
-** ------------------------------------------------------------------
-**
-** - In existing code, addresses were being handled as 32 bit values at
-** certain places.
-**
-** - Added a new set of functions for address load/store/manipulation.
-** These are ADDR_LDR, ADDR_STR, ADDR_ADD, ADDR_SUB and they map to
-** default 32 bit implementations in ARMAssemblerInterface.
-**
-** - ArmToArm64Assembler maps these functions to appropriate 64 bit
-** functions.
-**
-** ----------------------
-** GGLAssembler changes
-** ----------------------
-** - Since ArmToArm64Assembler can generate 4 Arm64 instructions for
-** each call in worst case, the memory required is set to 4 times
-** ARM memory
-**
-** - Address load/store/manipulation were changed to use new functions
-** added in the ARMAssemblerInterface.
-**
-*/
-
-
-#define NOT_IMPLEMENTED() LOG_FATAL("Arm instruction %s not yet implemented\n", __func__)
-
-#define ARM64_ASM_DEBUG 0
-
-#if ARM64_ASM_DEBUG
- #define LOG_INSTR(...) ALOGD("\t" __VA_ARGS__)
- #define LOG_LABEL(...) ALOGD(__VA_ARGS__)
-#else
- #define LOG_INSTR(...) ((void)0)
- #define LOG_LABEL(...) ((void)0)
-#endif
-
-namespace android {
-
-static __unused const char* shift_codes[] =
-{
- "LSL", "LSR", "ASR", "ROR"
-};
-static __unused const char *cc_codes[] =
-{
- "EQ", "NE", "CS", "CC", "MI",
- "PL", "VS", "VC", "HI", "LS",
- "GE", "LT", "GT", "LE", "AL", "NV"
-};
-
-ArmToArm64Assembler::ArmToArm64Assembler(const sp<Assembly>& assembly)
- : ARMAssemblerInterface(),
- mAssembly(assembly)
-{
- mBase = mPC = (uint32_t *)assembly->base();
- mDuration = ggl_system_time();
- mZeroReg = 13;
- mTmpReg1 = 15;
- mTmpReg2 = 16;
- mTmpReg3 = 17;
-}
-
-ArmToArm64Assembler::ArmToArm64Assembler(void *base)
- : ARMAssemblerInterface(), mAssembly(NULL)
-{
- mBase = mPC = (uint32_t *)base;
- mDuration = ggl_system_time();
- // Regs 13, 15, 16, 17 are used as temporary registers
- mZeroReg = 13;
- mTmpReg1 = 15;
- mTmpReg2 = 16;
- mTmpReg3 = 17;
-}
-
-ArmToArm64Assembler::~ArmToArm64Assembler()
-{
-}
-
-uint32_t* ArmToArm64Assembler::pc() const
-{
- return mPC;
-}
-
-uint32_t* ArmToArm64Assembler::base() const
-{
- return mBase;
-}
-
-void ArmToArm64Assembler::reset()
-{
- if(mAssembly == NULL)
- mPC = mBase;
- else
- mBase = mPC = (uint32_t *)mAssembly->base();
- mBranchTargets.clear();
- mLabels.clear();
- mLabelsInverseMapping.clear();
- mComments.clear();
-#if ARM64_ASM_DEBUG
- ALOGI("RESET\n");
-#endif
-}
-
-int ArmToArm64Assembler::getCodegenArch()
-{
- return CODEGEN_ARCH_ARM64;
-}
-
-// ----------------------------------------------------------------------------
-
-void ArmToArm64Assembler::disassemble(const char* name)
-{
- if(name)
- {
- printf("%s:\n", name);
- }
- size_t count = pc()-base();
- uint32_t* i = base();
- while (count--)
- {
- ssize_t label = mLabelsInverseMapping.indexOfKey(i);
- if (label >= 0)
- {
- printf("%s:\n", mLabelsInverseMapping.valueAt(label));
- }
- ssize_t comment = mComments.indexOfKey(i);
- if (comment >= 0)
- {
- printf("; %s\n", mComments.valueAt(comment));
- }
- printf("%p: %08x ", i, uint32_t(i[0]));
- {
- char instr[256];
- ::arm64_disassemble(*i, instr);
- printf("%s\n", instr);
- }
- i++;
- }
-}
-
-void ArmToArm64Assembler::comment(const char* string)
-{
- mComments.add(mPC, string);
- LOG_INSTR("//%s\n", string);
-}
-
-void ArmToArm64Assembler::label(const char* theLabel)
-{
- mLabels.add(theLabel, mPC);
- mLabelsInverseMapping.add(mPC, theLabel);
- LOG_LABEL("%s:\n", theLabel);
-}
-
-void ArmToArm64Assembler::B(int cc, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- LOG_INSTR("B%s %s\n", cc_codes[cc], label );
- *mPC++ = (0x54 << 24) | cc;
-}
-
-void ArmToArm64Assembler::BL(int /*cc*/, const char* /*label*/)
-{
- NOT_IMPLEMENTED(); //Not Required
-}
-
-// ----------------------------------------------------------------------------
-//Prolog/Epilog & Generate...
-// ----------------------------------------------------------------------------
-
-void ArmToArm64Assembler::prolog()
-{
- // write prolog code
- mPrologPC = mPC;
- *mPC++ = A64_MOVZ_X(mZeroReg,0,0);
-}
-
-void ArmToArm64Assembler::epilog(uint32_t /*touched*/)
-{
- // write epilog code
- static const int XLR = 30;
- *mPC++ = A64_RET(XLR);
-}
-
-int ArmToArm64Assembler::generate(const char* name)
-{
- // fixup all the branches
- size_t count = mBranchTargets.size();
- while (count--)
- {
- const branch_target_t& bt = mBranchTargets[count];
- uint32_t* target_pc = mLabels.valueFor(bt.label);
- LOG_ALWAYS_FATAL_IF(!target_pc,
- "error resolving branch targets, target_pc is null");
- int32_t offset = int32_t(target_pc - bt.pc);
- *bt.pc |= (offset & 0x7FFFF) << 5;
- }
-
- if(mAssembly != NULL)
- mAssembly->resize( int(pc()-base())*4 );
-
- // the instruction cache is flushed by CodeCache
- const int64_t duration = ggl_system_time() - mDuration;
- const char * const format = "generated %s (%d ins) at [%p:%p] in %ld ns\n";
- ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-
-
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.pf.disasm", value, "0");
- if (atoi(value) != 0)
- {
- printf(format, name, int(pc()-base()), base(), pc(), duration);
- disassemble(name);
- }
- return OK;
-}
-
-uint32_t* ArmToArm64Assembler::pcForLabel(const char* label)
-{
- return mLabels.valueFor(label);
-}
-
-// ----------------------------------------------------------------------------
-// Data Processing...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::dataProcessingCommon(int opcode,
- int s, int Rd, int Rn, uint32_t Op2)
-{
- if(opcode != opSUB && s == 1)
- {
- NOT_IMPLEMENTED(); //Not required
- return;
- }
-
- if(opcode != opSUB && opcode != opADD && opcode != opAND &&
- opcode != opORR && opcode != opMVN)
- {
- NOT_IMPLEMENTED(); //Not required
- return;
- }
-
- if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_shift > 31)
- {
- NOT_IMPLEMENTED();
- return;
- }
-
- //Store immediate in temporary register and convert
- //immediate operation into register operation
- if(Op2 == OPERAND_IMM)
- {
- int imm = mAddrMode.immediate;
- *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0x0000FFFF, 0);
- *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
- Op2 = mTmpReg2;
- }
-
-
- {
- uint32_t shift;
- uint32_t amount;
- uint32_t Rm;
-
- if(Op2 == OPERAND_REG_IMM)
- {
- shift = mAddrMode.reg_imm_type;
- amount = mAddrMode.reg_imm_shift;
- Rm = mAddrMode.reg_imm_Rm;
- }
- else if(Op2 < OPERAND_REG)
- {
- shift = 0;
- amount = 0;
- Rm = Op2;
- }
- else
- {
- NOT_IMPLEMENTED(); //Not required
- return;
- }
-
- switch(opcode)
- {
- case opADD: *mPC++ = A64_ADD_W(Rd, Rn, Rm, shift, amount); break;
- case opAND: *mPC++ = A64_AND_W(Rd, Rn, Rm, shift, amount); break;
- case opORR: *mPC++ = A64_ORR_W(Rd, Rn, Rm, shift, amount); break;
- case opMVN: *mPC++ = A64_ORN_W(Rd, Rn, Rm, shift, amount); break;
- case opSUB: *mPC++ = A64_SUB_W(Rd, Rn, Rm, shift, amount, s);break;
- };
-
- }
-}
-
-void ArmToArm64Assembler::dataProcessing(int opcode, int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
- uint32_t Wd;
-
- if(cc != AL)
- Wd = mTmpReg1;
- else
- Wd = Rd;
-
- if(opcode == opADD || opcode == opAND || opcode == opORR ||opcode == opSUB)
- {
- dataProcessingCommon(opcode, s, Wd, Rn, Op2);
- }
- else if(opcode == opCMP)
- {
- dataProcessingCommon(opSUB, 1, mTmpReg3, Rn, Op2);
- }
- else if(opcode == opRSB)
- {
- dataProcessingCommon(opSUB, s, Wd, Rn, Op2);
- dataProcessingCommon(opSUB, s, Wd, mZeroReg, Wd);
- }
- else if(opcode == opMOV)
- {
- dataProcessingCommon(opORR, 0, Wd, mZeroReg, Op2);
- if(s == 1)
- {
- dataProcessingCommon(opSUB, 1, mTmpReg3, Wd, mZeroReg);
- }
- }
- else if(opcode == opMVN)
- {
- dataProcessingCommon(opMVN, s, Wd, mZeroReg, Op2);
- }
- else if(opcode == opBIC)
- {
- dataProcessingCommon(opMVN, s, mTmpReg3, mZeroReg, Op2);
- dataProcessingCommon(opAND, s, Wd, Rn, mTmpReg3);
- }
- else
- {
- NOT_IMPLEMENTED();
- return;
- }
-
- if(cc != AL)
- {
- *mPC++ = A64_CSEL_W(Rd, mTmpReg1, Rd, cc);
- }
-}
-// ----------------------------------------------------------------------------
-// Address Processing...
-// ----------------------------------------------------------------------------
-
-void ArmToArm64Assembler::ADDR_ADD(int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
- if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
-
-
- if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSL)
- {
- int Rm = mAddrMode.reg_imm_Rm;
- int amount = mAddrMode.reg_imm_shift;
- *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
- }
- else if(Op2 < OPERAND_REG)
- {
- int Rm = Op2;
- int amount = 0;
- *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
- }
- else if(Op2 == OPERAND_IMM)
- {
- int imm = mAddrMode.immediate;
- *mPC++ = A64_MOVZ_W(mTmpReg1, imm & 0x0000FFFF, 0);
- *mPC++ = A64_MOVK_W(mTmpReg1, (imm >> 16) & 0x0000FFFF, 16);
-
- int Rm = mTmpReg1;
- int amount = 0;
- *mPC++ = A64_ADD_X_Wm_SXTW(Rd, Rn, Rm, amount);
- }
- else
- {
- NOT_IMPLEMENTED(); //Not required
- }
-}
-
-void ArmToArm64Assembler::ADDR_SUB(int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
- if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
-
- if(Op2 == OPERAND_REG_IMM && mAddrMode.reg_imm_type == LSR)
- {
- *mPC++ = A64_ADD_W(mTmpReg1, mZeroReg, mAddrMode.reg_imm_Rm,
- LSR, mAddrMode.reg_imm_shift);
- *mPC++ = A64_SUB_X_Wm_SXTW(Rd, Rn, mTmpReg1, 0);
- }
- else
- {
- NOT_IMPLEMENTED(); //Not required
- }
-}
-
-// ----------------------------------------------------------------------------
-// multiply...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::MLA(int cc, int s,int Rd, int Rm, int Rs, int Rn)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
-
- *mPC++ = A64_MADD_W(Rd, Rm, Rs, Rn);
- if(s == 1)
- dataProcessingCommon(opSUB, 1, mTmpReg1, Rd, mZeroReg);
-}
-void ArmToArm64Assembler::MUL(int cc, int s, int Rd, int Rm, int Rs)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
- if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
- *mPC++ = A64_MADD_W(Rd, Rm, Rs, mZeroReg);
-}
-void ArmToArm64Assembler::UMULL(int /*cc*/, int /*s*/,
- int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::UMUAL(int /*cc*/, int /*s*/,
- int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SMULL(int /*cc*/, int /*s*/,
- int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SMUAL(int /*cc*/, int /*s*/,
- int /*RdLo*/, int /*RdHi*/, int /*Rm*/, int /*Rs*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// branches relative to PC...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::B(int /*cc*/, uint32_t* /*pc*/){
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::BL(int /*cc*/, uint32_t* /*pc*/){
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::BX(int /*cc*/, int /*Rn*/){
- NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// data transfer...
-// ----------------------------------------------------------------------------
-enum dataTransferOp
-{
- opLDR,opLDRB,opLDRH,opSTR,opSTRB,opSTRH
-};
-
-void ArmToArm64Assembler::dataTransfer(int op, int cc,
- int Rd, int Rn, uint32_t op_type, uint32_t size)
-{
- const int XSP = 31;
- if(Rn == SP)
- Rn = XSP;
-
- if(op_type == OPERAND_IMM)
- {
- int addrReg;
- int imm = mAddrMode.immediate;
- if(imm >= 0 && imm < (1<<12))
- *mPC++ = A64_ADD_IMM_X(mTmpReg1, mZeroReg, imm, 0);
- else if(imm < 0 && -imm < (1<<12))
- *mPC++ = A64_SUB_IMM_X(mTmpReg1, mZeroReg, -imm, 0);
- else
- {
- NOT_IMPLEMENTED();
- return;
- }
-
- addrReg = Rn;
- if(mAddrMode.preindex == true || mAddrMode.postindex == true)
- {
- *mPC++ = A64_ADD_X(mTmpReg2, addrReg, mTmpReg1);
- if(mAddrMode.preindex == true)
- addrReg = mTmpReg2;
- }
-
- if(cc != AL)
- *mPC++ = A64_B_COND(cc^1, 8);
-
- *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, addrReg, mZeroReg);
-
- if(mAddrMode.writeback == true)
- *mPC++ = A64_CSEL_X(Rn, mTmpReg2, Rn, cc);
- }
- else if(op_type == OPERAND_REG_OFFSET)
- {
- if(cc != AL)
- *mPC++ = A64_B_COND(cc^1, 8);
- *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mAddrMode.reg_offset);
-
- }
- else if(op_type > OPERAND_UNSUPPORTED)
- {
- if(cc != AL)
- *mPC++ = A64_B_COND(cc^1, 8);
- *mPC++ = A64_LDRSTR_Wm_SXTW_0(op, size, Rd, Rn, mZeroReg);
- }
- else
- {
- NOT_IMPLEMENTED(); // Not required
- }
- return;
-
-}
-void ArmToArm64Assembler::ADDR_LDR(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opLDR, cc, Rd, Rn, op_type, 64);
-}
-void ArmToArm64Assembler::ADDR_STR(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opSTR, cc, Rd, Rn, op_type, 64);
-}
-void ArmToArm64Assembler::LDR(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opLDR, cc, Rd, Rn, op_type);
-}
-void ArmToArm64Assembler::LDRB(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opLDRB, cc, Rd, Rn, op_type);
-}
-void ArmToArm64Assembler::STR(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opSTR, cc, Rd, Rn, op_type);
-}
-
-void ArmToArm64Assembler::STRB(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opSTRB, cc, Rd, Rn, op_type);
-}
-
-void ArmToArm64Assembler::LDRH(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opLDRH, cc, Rd, Rn, op_type);
-}
-void ArmToArm64Assembler::LDRSB(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::LDRSH(int /*cc*/, int /*Rd*/, int /*Rn*/, uint32_t /*offset*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::STRH(int cc, int Rd, int Rn, uint32_t op_type)
-{
- return dataTransfer(opSTRH, cc, Rd, Rn, op_type);
-}
-
-// ----------------------------------------------------------------------------
-// block data transfer...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list)
-{
- const int XSP = 31;
- if(cc != AL || dir != IA || W == 0 || Rn != SP)
- {
- NOT_IMPLEMENTED();
- return;
- }
-
- for(int i = 0; i < 32; ++i)
- {
- if((reg_list & (1 << i)))
- {
- int reg = i;
- int size = 16;
- *mPC++ = A64_LDR_IMM_PostIndex(reg, XSP, size);
- }
- }
-}
-
-void ArmToArm64Assembler::STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list)
-{
- const int XSP = 31;
- if(cc != AL || dir != DB || W == 0 || Rn != SP)
- {
- NOT_IMPLEMENTED();
- return;
- }
-
- for(int i = 31; i >= 0; --i)
- {
- if((reg_list & (1 << i)))
- {
- int size = -16;
- int reg = i;
- *mPC++ = A64_STR_IMM_PreIndex(reg, XSP, size);
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-// special...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::SWP(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SWPB(int /*cc*/, int /*Rn*/, int /*Rd*/, int /*Rm*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-void ArmToArm64Assembler::SWI(int /*cc*/, uint32_t /*comment*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// DSP instructions...
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::PLD(int /*Rn*/, uint32_t /*offset*/) {
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::CLZ(int /*cc*/, int /*Rd*/, int /*Rm*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QDADD(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-void ArmToArm64Assembler::QDSUB(int /*cc*/, int /*Rd*/, int /*Rm*/, int /*Rn*/)
-{
- NOT_IMPLEMENTED(); //Not required
-}
-
-// ----------------------------------------------------------------------------
-// 16 x 16 multiplication
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::SMUL(int cc, int xy,
- int Rd, int Rm, int Rs)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
-
- if (xy & xyTB)
- *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 16, 31);
- else
- *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
-
- if (xy & xyBT)
- *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 16, 31);
- else
- *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
-
- *mPC++ = A64_MADD_W(Rd,mTmpReg1,mTmpReg2, mZeroReg);
-}
-// ----------------------------------------------------------------------------
-// 32 x 16 multiplication
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::SMULW(int cc, int y, int Rd, int Rm, int Rs)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
-
- if (y & yT)
- *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 16, 31);
- else
- *mPC++ = A64_SBFM_W(mTmpReg1, Rs, 0, 15);
-
- *mPC++ = A64_SBFM_W(mTmpReg2, Rm, 0, 31);
- *mPC++ = A64_SMADDL(mTmpReg3,mTmpReg1,mTmpReg2, mZeroReg);
- *mPC++ = A64_UBFM_X(Rd,mTmpReg3, 16, 47);
-}
-// ----------------------------------------------------------------------------
-// 16 x 16 multiplication and accumulate
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::SMLA(int cc, int xy, int Rd, int Rm, int Rs, int Rn)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
- if(xy != xyBB) { NOT_IMPLEMENTED(); return;} //Not required
-
- *mPC++ = A64_SBFM_W(mTmpReg1, Rm, 0, 15);
- *mPC++ = A64_SBFM_W(mTmpReg2, Rs, 0, 15);
- *mPC++ = A64_MADD_W(Rd, mTmpReg1, mTmpReg2, Rn);
-}
-
-void ArmToArm64Assembler::SMLAL(int /*cc*/, int /*xy*/,
- int /*RdHi*/, int /*RdLo*/, int /*Rs*/, int /*Rm*/)
-{
- NOT_IMPLEMENTED(); //Not required
- return;
-}
-
-void ArmToArm64Assembler::SMLAW(int /*cc*/, int /*y*/,
- int /*Rd*/, int /*Rm*/, int /*Rs*/, int /*Rn*/)
-{
- NOT_IMPLEMENTED(); //Not required
- return;
-}
-
-// ----------------------------------------------------------------------------
-// Byte/half word extract and extend
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::UXTB16(int cc, int Rd, int Rm, int rotate)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
-
- *mPC++ = A64_EXTR_W(mTmpReg1, Rm, Rm, rotate * 8);
-
- uint32_t imm = 0x00FF00FF;
- *mPC++ = A64_MOVZ_W(mTmpReg2, imm & 0xFFFF, 0);
- *mPC++ = A64_MOVK_W(mTmpReg2, (imm >> 16) & 0x0000FFFF, 16);
- *mPC++ = A64_AND_W(Rd,mTmpReg1, mTmpReg2);
-}
-
-// ----------------------------------------------------------------------------
-// Bit manipulation
-// ----------------------------------------------------------------------------
-void ArmToArm64Assembler::UBFX(int cc, int Rd, int Rn, int lsb, int width)
-{
- if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
- *mPC++ = A64_UBFM_W(Rd, Rn, lsb, lsb + width - 1);
-}
-// ----------------------------------------------------------------------------
-// Shifters...
-// ----------------------------------------------------------------------------
-int ArmToArm64Assembler::buildImmediate(
- uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
- rot = 0;
- imm = immediate;
- return 0; // Always true
-}
-
-
-bool ArmToArm64Assembler::isValidImmediate(uint32_t immediate)
-{
- uint32_t rot, imm;
- return buildImmediate(immediate, rot, imm) == 0;
-}
-
-uint32_t ArmToArm64Assembler::imm(uint32_t immediate)
-{
- mAddrMode.immediate = immediate;
- mAddrMode.writeback = false;
- mAddrMode.preindex = false;
- mAddrMode.postindex = false;
- return OPERAND_IMM;
-
-}
-
-uint32_t ArmToArm64Assembler::reg_imm(int Rm, int type, uint32_t shift)
-{
- mAddrMode.reg_imm_Rm = Rm;
- mAddrMode.reg_imm_type = type;
- mAddrMode.reg_imm_shift = shift;
- return OPERAND_REG_IMM;
-}
-
-uint32_t ArmToArm64Assembler::reg_rrx(int /*Rm*/)
-{
- NOT_IMPLEMENTED();
- return OPERAND_UNSUPPORTED;
-}
-
-uint32_t ArmToArm64Assembler::reg_reg(int /*Rm*/, int /*type*/, int /*Rs*/)
-{
- NOT_IMPLEMENTED(); //Not required
- return OPERAND_UNSUPPORTED;
-}
-// ----------------------------------------------------------------------------
-// Addressing modes...
-// ----------------------------------------------------------------------------
-uint32_t ArmToArm64Assembler::immed12_pre(int32_t immed12, int W)
-{
- mAddrMode.immediate = immed12;
- mAddrMode.writeback = W;
- mAddrMode.preindex = true;
- mAddrMode.postindex = false;
- return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::immed12_post(int32_t immed12)
-{
- mAddrMode.immediate = immed12;
- mAddrMode.writeback = true;
- mAddrMode.preindex = false;
- mAddrMode.postindex = true;
- return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::reg_scale_pre(int Rm, int type,
- uint32_t shift, int W)
-{
- if(type != 0 || shift != 0 || W != 0)
- {
- NOT_IMPLEMENTED(); //Not required
- return OPERAND_UNSUPPORTED;
- }
- else
- {
- mAddrMode.reg_offset = Rm;
- return OPERAND_REG_OFFSET;
- }
-}
-
-uint32_t ArmToArm64Assembler::reg_scale_post(int /*Rm*/, int /*type*/, uint32_t /*shift*/)
-{
- NOT_IMPLEMENTED(); //Not required
- return OPERAND_UNSUPPORTED;
-}
-
-uint32_t ArmToArm64Assembler::immed8_pre(int32_t immed8, int W)
-{
- mAddrMode.immediate = immed8;
- mAddrMode.writeback = W;
- mAddrMode.preindex = true;
- mAddrMode.postindex = false;
- return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::immed8_post(int32_t immed8)
-{
- mAddrMode.immediate = immed8;
- mAddrMode.writeback = true;
- mAddrMode.preindex = false;
- mAddrMode.postindex = true;
- return OPERAND_IMM;
-}
-
-uint32_t ArmToArm64Assembler::reg_pre(int Rm, int W)
-{
- if(W != 0)
- {
- NOT_IMPLEMENTED(); //Not required
- return OPERAND_UNSUPPORTED;
- }
- else
- {
- mAddrMode.reg_offset = Rm;
- return OPERAND_REG_OFFSET;
- }
-}
-
-uint32_t ArmToArm64Assembler::reg_post(int /*Rm*/)
-{
- NOT_IMPLEMENTED(); //Not required
- return OPERAND_UNSUPPORTED;
-}
-
-// ----------------------------------------------------------------------------
-// A64 instructions
-// ----------------------------------------------------------------------------
-
-static __unused const char * dataTransferOpName[] =
-{
- "LDR","LDRB","LDRH","STR","STRB","STRH"
-};
-
-static const uint32_t dataTransferOpCode [] =
-{
- ((0xB8u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
- ((0x38u << 24) | (0x3 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
- ((0x78u << 24) | (0x3 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
- ((0xB8u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11)),
- ((0x38u << 24) | (0x1 << 21) | (0x6 << 13) | (0x1 << 12) |(0x1 << 11)),
- ((0x78u << 24) | (0x1 << 21) | (0x6 << 13) | (0x0 << 12) |(0x1 << 11))
-};
-uint32_t ArmToArm64Assembler::A64_LDRSTR_Wm_SXTW_0(uint32_t op,
- uint32_t size, uint32_t Rt,
- uint32_t Rn, uint32_t Rm)
-{
- if(size == 32)
- {
- LOG_INSTR("%s W%d, [X%d, W%d, SXTW #0]\n",
- dataTransferOpName[op], Rt, Rn, Rm);
- return(dataTransferOpCode[op] | (Rm << 16) | (Rn << 5) | Rt);
- }
- else
- {
- LOG_INSTR("%s X%d, [X%d, W%d, SXTW #0]\n",
- dataTransferOpName[op], Rt, Rn, Rm);
- return(dataTransferOpCode[op] | (0x1<<30) | (Rm<<16) | (Rn<<5)|Rt);
- }
-}
-
-uint32_t ArmToArm64Assembler::A64_STR_IMM_PreIndex(uint32_t Rt,
- uint32_t Rn, int32_t simm)
-{
- if(Rn == 31)
- LOG_INSTR("STR W%d, [SP, #%d]!\n", Rt, simm);
- else
- LOG_INSTR("STR W%d, [X%d, #%d]!\n", Rt, Rn, simm);
-
- uint32_t imm9 = (unsigned)(simm) & 0x01FF;
- return (0xB8 << 24) | (imm9 << 12) | (0x3 << 10) | (Rn << 5) | Rt;
-}
-
-uint32_t ArmToArm64Assembler::A64_LDR_IMM_PostIndex(uint32_t Rt,
- uint32_t Rn, int32_t simm)
-{
- if(Rn == 31)
- LOG_INSTR("LDR W%d, [SP], #%d\n",Rt,simm);
- else
- LOG_INSTR("LDR W%d, [X%d], #%d\n",Rt, Rn, simm);
-
- uint32_t imm9 = (unsigned)(simm) & 0x01FF;
- return (0xB8 << 24) | (0x1 << 22) |
- (imm9 << 12) | (0x1 << 10) | (Rn << 5) | Rt;
-
-}
-uint32_t ArmToArm64Assembler::A64_ADD_X_Wm_SXTW(uint32_t Rd,
- uint32_t Rn,
- uint32_t Rm,
- uint32_t amount)
-{
- LOG_INSTR("ADD X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
- return ((0x8B << 24) | (0x1 << 21) |(Rm << 16) |
- (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
-
-}
-
-uint32_t ArmToArm64Assembler::A64_SUB_X_Wm_SXTW(uint32_t Rd,
- uint32_t Rn,
- uint32_t Rm,
- uint32_t amount)
-{
- LOG_INSTR("SUB X%d, X%d, W%d, SXTW #%d\n", Rd, Rn, Rm, amount);
- return ((0xCB << 24) | (0x1 << 21) |(Rm << 16) |
- (0x6 << 13) | (amount << 10) | (Rn << 5) | Rd);
-
-}
-
-uint32_t ArmToArm64Assembler::A64_B_COND(uint32_t cc, uint32_t offset)
-{
- LOG_INSTR("B.%s #.+%d\n", cc_codes[cc], offset);
- return (0x54 << 24) | ((offset/4) << 5) | (cc);
-
-}
-uint32_t ArmToArm64Assembler::A64_ADD_X(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift,
- uint32_t amount)
-{
- LOG_INSTR("ADD X%d, X%d, X%d, %s #%d\n",
- Rd, Rn, Rm, shift_codes[shift], amount);
- return ((0x8B << 24) | (shift << 22) | ( Rm << 16) |
- (amount << 10) |(Rn << 5) | Rd);
-}
-uint32_t ArmToArm64Assembler::A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
- uint32_t imm, uint32_t shift)
-{
- LOG_INSTR("ADD X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
- return (0x91 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
-}
-
-uint32_t ArmToArm64Assembler::A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
- uint32_t imm, uint32_t shift)
-{
- LOG_INSTR("SUB X%d, X%d, #%d, LSL #%d\n", Rd, Rn, imm, shift);
- return (0xD1 << 24) | ((shift/12) << 22) | (imm << 10) | (Rn << 5) | Rd;
-}
-
-uint32_t ArmToArm64Assembler::A64_ADD_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift,
- uint32_t amount)
-{
- LOG_INSTR("ADD W%d, W%d, W%d, %s #%d\n",
- Rd, Rn, Rm, shift_codes[shift], amount);
- return ((0x0B << 24) | (shift << 22) | ( Rm << 16) |
- (amount << 10) |(Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_SUB_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift,
- uint32_t amount,
- uint32_t setflag)
-{
- if(setflag == 0)
- {
- LOG_INSTR("SUB W%d, W%d, W%d, %s #%d\n",
- Rd, Rn, Rm, shift_codes[shift], amount);
- return ((0x4B << 24) | (shift << 22) | ( Rm << 16) |
- (amount << 10) |(Rn << 5) | Rd);
- }
- else
- {
- LOG_INSTR("SUBS W%d, W%d, W%d, %s #%d\n",
- Rd, Rn, Rm, shift_codes[shift], amount);
- return ((0x6B << 24) | (shift << 22) | ( Rm << 16) |
- (amount << 10) |(Rn << 5) | Rd);
- }
-}
-
-uint32_t ArmToArm64Assembler::A64_AND_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift,
- uint32_t amount)
-{
- LOG_INSTR("AND W%d, W%d, W%d, %s #%d\n",
- Rd, Rn, Rm, shift_codes[shift], amount);
- return ((0x0A << 24) | (shift << 22) | ( Rm << 16) |
- (amount << 10) |(Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_ORR_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift,
- uint32_t amount)
-{
- LOG_INSTR("ORR W%d, W%d, W%d, %s #%d\n",
- Rd, Rn, Rm, shift_codes[shift], amount);
- return ((0x2A << 24) | (shift << 22) | ( Rm << 16) |
- (amount << 10) |(Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_ORN_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift,
- uint32_t amount)
-{
- LOG_INSTR("ORN W%d, W%d, W%d, %s #%d\n",
- Rd, Rn, Rm, shift_codes[shift], amount);
- return ((0x2A << 24) | (shift << 22) | (0x1 << 21) | ( Rm << 16) |
- (amount << 10) |(Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_CSEL_X(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t cond)
-{
- LOG_INSTR("CSEL X%d, X%d, X%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
- return ((0x9A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_CSEL_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t cond)
-{
- LOG_INSTR("CSEL W%d, W%d, W%d, %s\n", Rd, Rn, Rm, cc_codes[cond]);
- return ((0x1A << 24)|(0x1 << 23)|(Rm << 16) |(cond << 12)| (Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_RET(uint32_t Rn)
-{
- LOG_INSTR("RET X%d\n", Rn);
- return ((0xD6 << 24) | (0x1 << 22) | (0x1F << 16) | (Rn << 5));
-}
-
-uint32_t ArmToArm64Assembler::A64_MOVZ_X(uint32_t Rd, uint32_t imm,
- uint32_t shift)
-{
- LOG_INSTR("MOVZ X%d, #0x%x, LSL #%d\n", Rd, imm, shift);
- return(0xD2 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
-}
-
-uint32_t ArmToArm64Assembler::A64_MOVK_W(uint32_t Rd, uint32_t imm,
- uint32_t shift)
-{
- LOG_INSTR("MOVK W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
- return (0x72 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
-}
-
-uint32_t ArmToArm64Assembler::A64_MOVZ_W(uint32_t Rd, uint32_t imm,
- uint32_t shift)
-{
- LOG_INSTR("MOVZ W%d, #0x%x, LSL #%d\n", Rd, imm, shift);
- return(0x52 << 24) | (0x1 << 23) | ((shift/16) << 21) | (imm << 5) | Rd;
-}
-
-uint32_t ArmToArm64Assembler::A64_SMADDL(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t Ra)
-{
- LOG_INSTR("SMADDL X%d, W%d, W%d, X%d\n",Rd, Rn, Rm, Ra);
- return ((0x9B << 24) | (0x1 << 21) | (Rm << 16)|(Ra << 10)|(Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_MADD_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t Ra)
-{
- LOG_INSTR("MADD W%d, W%d, W%d, W%d\n",Rd, Rn, Rm, Ra);
- return ((0x1B << 24) | (Rm << 16) | (Ra << 10) |(Rn << 5) | Rd);
-}
-
-uint32_t ArmToArm64Assembler::A64_SBFM_W(uint32_t Rd, uint32_t Rn,
- uint32_t immr, uint32_t imms)
-{
- LOG_INSTR("SBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
- return ((0x13 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
-
-}
-uint32_t ArmToArm64Assembler::A64_UBFM_W(uint32_t Rd, uint32_t Rn,
- uint32_t immr, uint32_t imms)
-{
- LOG_INSTR("UBFM W%d, W%d, #%d, #%d\n", Rd, Rn, immr, imms);
- return ((0x53 << 24) | (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
-
-}
-uint32_t ArmToArm64Assembler::A64_UBFM_X(uint32_t Rd, uint32_t Rn,
- uint32_t immr, uint32_t imms)
-{
- LOG_INSTR("UBFM X%d, X%d, #%d, #%d\n", Rd, Rn, immr, imms);
- return ((0xD3 << 24) | (0x1 << 22) |
- (immr << 16) | (imms << 10) | (Rn << 5) | Rd);
-
-}
-uint32_t ArmToArm64Assembler::A64_EXTR_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t lsb)
-{
- LOG_INSTR("EXTR W%d, W%d, W%d, #%d\n", Rd, Rn, Rm, lsb);
- return (0x13 << 24)|(0x1 << 23) | (Rm << 16) | (lsb << 10)|(Rn << 5) | Rd;
-}
-
-}; // namespace android
diff --git a/libpixelflinger/codeflinger/Arm64Assembler.h b/libpixelflinger/codeflinger/Arm64Assembler.h
deleted file mode 100644
index 527c757..0000000
--- a/libpixelflinger/codeflinger/Arm64Assembler.h
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef ANDROID_ARMTOARM64ASSEMBLER_H
-#define ANDROID_ARMTOARM64ASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "tinyutils/smartpointer.h"
-#include "utils/Vector.h"
-#include "utils/KeyedVector.h"
-
-#include "tinyutils/smartpointer.h"
-#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/CodeCache.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class ArmToArm64Assembler : public ARMAssemblerInterface
-{
-public:
- explicit ArmToArm64Assembler(const sp<Assembly>& assembly);
- explicit ArmToArm64Assembler(void *base);
- virtual ~ArmToArm64Assembler();
-
- uint32_t* base() const;
- uint32_t* pc() const;
-
-
- void disassemble(const char* name);
-
- // ------------------------------------------------------------------------
- // ARMAssemblerInterface...
- // ------------------------------------------------------------------------
-
- virtual void reset();
-
- virtual int generate(const char* name);
- virtual int getCodegenArch();
-
- virtual void prolog();
- virtual void epilog(uint32_t touched);
- virtual void comment(const char* string);
-
-
- // -----------------------------------------------------------------------
- // shifters and addressing modes
- // -----------------------------------------------------------------------
-
- // shifters...
- virtual bool isValidImmediate(uint32_t immed);
- virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
-
- virtual uint32_t imm(uint32_t immediate);
- virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
- virtual uint32_t reg_rrx(int Rm);
- virtual uint32_t reg_reg(int Rm, int type, int Rs);
-
- // addressing modes...
- virtual uint32_t immed12_pre(int32_t immed12, int W=0);
- virtual uint32_t immed12_post(int32_t immed12);
- virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
- virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
- virtual uint32_t immed8_pre(int32_t immed8, int W=0);
- virtual uint32_t immed8_post(int32_t immed8);
- virtual uint32_t reg_pre(int Rm, int W=0);
- virtual uint32_t reg_post(int Rm);
-
-
- virtual void dataProcessing(int opcode, int cc, int s,
- int Rd, int Rn,
- uint32_t Op2);
- virtual void MLA(int cc, int s,
- int Rd, int Rm, int Rs, int Rn);
- virtual void MUL(int cc, int s,
- int Rd, int Rm, int Rs);
- virtual void UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
-
- virtual void B(int cc, uint32_t* pc);
- virtual void BL(int cc, uint32_t* pc);
- virtual void BX(int cc, int Rn);
- virtual void label(const char* theLabel);
- virtual void B(int cc, const char* label);
- virtual void BL(int cc, const char* label);
-
- virtual uint32_t* pcForLabel(const char* label);
-
- virtual void ADDR_LDR(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void ADDR_ADD(int cc, int s, int Rd,
- int Rn, uint32_t Op2);
- virtual void ADDR_SUB(int cc, int s, int Rd,
- int Rn, uint32_t Op2);
- virtual void ADDR_STR (int cc, int Rd,
- int Rn, uint32_t offset = 0);
-
- virtual void LDR (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STR (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STRB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRH (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRSB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRSH(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STRH (int cc, int Rd,
- int Rn, uint32_t offset = 0);
-
-
- virtual void LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
- virtual void STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
-
- virtual void SWP(int cc, int Rn, int Rd, int Rm);
- virtual void SWPB(int cc, int Rn, int Rd, int Rm);
- virtual void SWI(int cc, uint32_t comment);
-
- virtual void PLD(int Rn, uint32_t offset);
- virtual void CLZ(int cc, int Rd, int Rm);
- virtual void QADD(int cc, int Rd, int Rm, int Rn);
- virtual void QDADD(int cc, int Rd, int Rm, int Rn);
- virtual void QSUB(int cc, int Rd, int Rm, int Rn);
- virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
- virtual void SMUL(int cc, int xy,
- int Rd, int Rm, int Rs);
- virtual void SMULW(int cc, int y,
- int Rd, int Rm, int Rs);
- virtual void SMLA(int cc, int xy,
- int Rd, int Rm, int Rs, int Rn);
- virtual void SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm);
- virtual void SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn);
- virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
- virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
-
-private:
- ArmToArm64Assembler(const ArmToArm64Assembler& rhs);
- ArmToArm64Assembler& operator = (const ArmToArm64Assembler& rhs);
-
- // -----------------------------------------------------------------------
- // helper functions
- // -----------------------------------------------------------------------
-
- void dataTransfer(int operation, int cc, int Rd, int Rn,
- uint32_t operand_type, uint32_t size = 32);
- void dataProcessingCommon(int opcode, int s,
- int Rd, int Rn, uint32_t Op2);
-
- // -----------------------------------------------------------------------
- // Arm64 instructions
- // -----------------------------------------------------------------------
- uint32_t A64_B_COND(uint32_t cc, uint32_t offset);
- uint32_t A64_RET(uint32_t Rn);
-
- uint32_t A64_LDRSTR_Wm_SXTW_0(uint32_t operation,
- uint32_t size, uint32_t Rt,
- uint32_t Rn, uint32_t Rm);
-
- uint32_t A64_STR_IMM_PreIndex(uint32_t Rt, uint32_t Rn, int32_t simm);
- uint32_t A64_LDR_IMM_PostIndex(uint32_t Rt,uint32_t Rn, int32_t simm);
-
- uint32_t A64_ADD_X_Wm_SXTW(uint32_t Rd, uint32_t Rn, uint32_t Rm,
- uint32_t amount);
- uint32_t A64_SUB_X_Wm_SXTW(uint32_t Rd, uint32_t Rn, uint32_t Rm,
- uint32_t amount);
-
- uint32_t A64_ADD_IMM_X(uint32_t Rd, uint32_t Rn,
- uint32_t imm, uint32_t shift = 0);
- uint32_t A64_SUB_IMM_X(uint32_t Rd, uint32_t Rn,
- uint32_t imm, uint32_t shift = 0);
-
- uint32_t A64_ADD_X(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
- uint32_t A64_ADD_W(uint32_t Rd, uint32_t Rn, uint32_t Rm,
- uint32_t shift = 0, uint32_t amount = 0);
- uint32_t A64_SUB_W(uint32_t Rd, uint32_t Rn, uint32_t Rm,
- uint32_t shift = 0, uint32_t amount = 0,
- uint32_t setflag = 0);
- uint32_t A64_AND_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
- uint32_t A64_ORR_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
- uint32_t A64_ORN_W(uint32_t Rd, uint32_t Rn,
- uint32_t Rm, uint32_t shift = 0, uint32_t amount = 0);
-
- uint32_t A64_MOVZ_W(uint32_t Rd, uint32_t imm, uint32_t shift);
- uint32_t A64_MOVZ_X(uint32_t Rd, uint32_t imm, uint32_t shift);
- uint32_t A64_MOVK_W(uint32_t Rd, uint32_t imm, uint32_t shift);
-
- uint32_t A64_SMADDL(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t Ra);
- uint32_t A64_MADD_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t Ra);
-
- uint32_t A64_SBFM_W(uint32_t Rd, uint32_t Rn,
- uint32_t immr, uint32_t imms);
- uint32_t A64_UBFM_W(uint32_t Rd, uint32_t Rn,
- uint32_t immr, uint32_t imms);
- uint32_t A64_UBFM_X(uint32_t Rd, uint32_t Rn,
- uint32_t immr, uint32_t imms);
-
- uint32_t A64_EXTR_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t lsb);
- uint32_t A64_CSEL_X(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t cond);
- uint32_t A64_CSEL_W(uint32_t Rd, uint32_t Rn, uint32_t Rm, uint32_t cond);
-
- uint32_t* mBase;
- uint32_t* mPC;
- uint32_t* mPrologPC;
- int64_t mDuration;
- uint32_t mTmpReg1, mTmpReg2, mTmpReg3, mZeroReg;
-
- struct branch_target_t {
- inline branch_target_t() : label(0), pc(0) { }
- inline branch_target_t(const char* l, uint32_t* p)
- : label(l), pc(p) { }
- const char* label;
- uint32_t* pc;
- };
-
- sp<Assembly> mAssembly;
- Vector<branch_target_t> mBranchTargets;
- KeyedVector< const char*, uint32_t* > mLabels;
- KeyedVector< uint32_t*, const char* > mLabelsInverseMapping;
- KeyedVector< uint32_t*, const char* > mComments;
-
- enum operand_type_t
- {
- OPERAND_REG = 0x20,
- OPERAND_IMM,
- OPERAND_REG_IMM,
- OPERAND_REG_OFFSET,
- OPERAND_UNSUPPORTED
- };
-
- struct addr_mode_t {
- int32_t immediate;
- bool writeback;
- bool preindex;
- bool postindex;
- int32_t reg_imm_Rm;
- int32_t reg_imm_type;
- uint32_t reg_imm_shift;
- int32_t reg_offset;
- } mAddrMode;
-
-};
-
-}; // namespace android
-
-#endif //ANDROID_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/Arm64Disassembler.cpp b/libpixelflinger/codeflinger/Arm64Disassembler.cpp
deleted file mode 100644
index 70f1ff1..0000000
--- a/libpixelflinger/codeflinger/Arm64Disassembler.cpp
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-
-struct disasm_table_entry_t
-{
- uint32_t mask;
- uint32_t value;
- const char* instr_template;
-};
-
-
-static disasm_table_entry_t disasm_table[] =
-{
- {0xff000000, 0x91000000, "add <xd|sp>, <xn|sp>, #<imm1>, <shift1>"},
- {0xff000000, 0xd1000000, "sub <xd|sp>, <xn|sp>, #<imm1>, <shift1>"},
- {0xff200000, 0x8b000000, "add <xd>, <xn>, <xm>, <shift2> #<amt1>"},
- {0xff200000, 0x0b000000, "add <wd>, <wn>, <wm>, <shift2> #<amt1>"},
- {0xff200000, 0x4b000000, "sub <wd>, <wn>, <wm>, <shift2> #<amt1>"},
- {0xff200000, 0x6b000000, "subs <wd>, <wn>, <wm>, <shift2> #<amt1>"},
- {0xff200000, 0x0a000000, "and <wd>, <wn>, <wm>, <shift2> #<amt1>"},
- {0xff200000, 0x2a000000, "orr <wd>, <wn>, <wm>, <shift2> #<amt1>"},
- {0xff200000, 0x2a200000, "orn <wd>, <wn>, <wm>, <shift2> #<amt1>"},
- {0xff800000, 0x72800000, "movk <wd>, #<imm2>, lsl #<shift3>"},
- {0xff800000, 0x52800000, "movz <wd>, #<imm2>, lsl #<shift3>"},
- {0xff800000, 0xd2800000, "movz <xd>, #<imm2>, lsl #<shift3>"},
- {0xffe00c00, 0x1a800000, "csel <wd>, <wn>, <wm>, <cond1>"},
- {0xffe00c00, 0x9a800000, "csel <xd>, <xn>, <xm>, <cond1>"},
- {0xffe00c00, 0x5a800000, "csinv <wd>, <wn>, <wm>, <cond1>"},
- {0xffe08000, 0x1b000000, "madd <wd>, <wn>, <wm>, <wa>"},
- {0xffe08000, 0x9b200000, "smaddl <xd>, <wn>, <wm>, <xa>"},
- {0xffe04c00, 0xb8604800, "ldr <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt2>]"},
- {0xffe04c00, 0xb8204800, "str <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt2>]"},
- {0xffe04c00, 0xf8604800, "ldr <xt>, [<xn|sp>, <r1><m1>, <ext1> #<amt3>]"},
- {0xffe04c00, 0xf8204800, "str <xt>, [<xn|sp>, <r1><m1>, <ext1> #<amt3>]"},
- {0xffe04c00, 0x38604800, "ldrb <wt>, [<xn|sp>, <r1><m1>, <ext1> <amt5>]"},
- {0xffe04c00, 0x38204800, "strb <wt>, [<xn|sp>, <r1><m1>, <ext1> <amt5>]"},
- {0xffe04c00, 0x78604800, "ldrh <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt6>]"},
- {0xffe04c00, 0x78204800, "strh <wt>, [<xn|sp>, <r1><m1>, <ext1> #<amt6>]"},
- {0xffe00c00, 0xb8400400, "ldr <wt>, [<xn|sp>], #<simm1>"},
- {0xffe00c00, 0xb8000c00, "str <wt>, [<xn|sp>, #<simm1>]!"},
- {0xffc00000, 0x13000000, "sbfm <wd>, <wn>, #<immr1>, #<imms1>"},
- {0xffc00000, 0x53000000, "ubfm <wd>, <wn>, #<immr1>, #<imms1>"},
- {0xffc00000, 0xd3400000, "ubfm <xd>, <xn>, #<immr1>, #<imms1>"},
- {0xffe00000, 0x13800000, "extr <wd>, <wn>, <wm>, #<lsb1>"},
- {0xff000000, 0x54000000, "b.<cond2> <label1>"},
- {0xfffffc1f, 0xd65f0000, "ret <xn>"},
- {0xffe00000, 0x8b200000, "add <xd|sp>, <xn|sp>, <r2><m1>, <ext2> #<amt4>"},
- {0xffe00000, 0xcb200000, "sub <xd|sp>, <xn|sp>, <r2><m1>, <ext2> #<amt4>"}
-};
-
-static int32_t bits_signed(uint32_t instr, uint32_t msb, uint32_t lsb)
-{
- int32_t value;
- value = ((int32_t)instr) << (31 - msb);
- value >>= (31 - msb);
- value >>= lsb;
- return value;
-}
-static uint32_t bits_unsigned(uint32_t instr, uint32_t msb, uint32_t lsb)
-{
- uint32_t width = msb - lsb + 1;
- uint32_t mask = (1 << width) - 1;
- return ((instr >> lsb) & mask);
-}
-
-static void get_token(const char *instr, uint32_t index, char *token)
-{
- uint32_t i, j;
- for(i = index, j = 0; i < strlen(instr); ++i)
- {
- if(instr[index] == '<' && instr[i] == '>')
- {
- token[j++] = instr[i];
- break;
- }
- else if(instr[index] != '<' && instr[i] == '<')
- {
- break;
- }
- else
- {
- token[j++] = instr[i];
- }
- }
- token[j] = '\0';
- return;
-}
-
-
-static const char * token_cc_table[] =
-{
- "eq", "ne", "cs", "cc", "mi",
- "pl", "vs", "vc", "hi", "ls",
- "ge", "lt", "gt", "le", "al", "nv"
-};
-
-static void decode_rx_zr_token(uint32_t reg, const char *prefix, char *instr_part)
-{
- if(reg == 31)
- sprintf(instr_part, "%s%s", prefix, "zr");
- else
- sprintf(instr_part, "%s%d", prefix, reg);
-}
-
-static void decode_token(uint32_t code, char *token, char *instr_part)
-{
- if(strcmp(token, "<imm1>") == 0)
- sprintf(instr_part, "0x%x", bits_unsigned(code, 21,10));
- else if(strcmp(token, "<imm2>") == 0)
- sprintf(instr_part, "0x%x", bits_unsigned(code, 20,5));
- else if(strcmp(token, "<shift1>") == 0)
- sprintf(instr_part, "lsl #%d", bits_unsigned(code, 23,22) * 12);
- else if(strcmp(token, "<shift2>") == 0)
- {
- static const char * shift2_table[] = { "lsl", "lsr", "asr", "ror"};
- sprintf(instr_part, "%s", shift2_table[bits_unsigned(code, 23,22)]);
- }
- else if(strcmp(token, "<shift3>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 22,21) * 16);
- else if(strcmp(token, "<amt1>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
- else if(strcmp(token, "<amt2>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 12,12) * 2);
- else if(strcmp(token, "<amt3>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 12,12) * 3);
- else if(strcmp(token, "<amt4>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 12,10));
- else if(strcmp(token, "<amt5>") == 0)
- {
- static const char * amt5_table[] = {"", "#0"};
- sprintf(instr_part, "%s", amt5_table[bits_unsigned(code, 12,12)]);
- }
- else if(strcmp(token, "<amt6>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 12,12));
- else if(strcmp(token, "<simm1>") == 0)
- sprintf(instr_part, "%d", bits_signed(code, 20,12));
- else if(strcmp(token, "<immr1>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 21,16));
- else if(strcmp(token, "<imms1>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
- else if(strcmp(token, "<lsb1>") == 0)
- sprintf(instr_part, "%d", bits_unsigned(code, 15,10));
- else if(strcmp(token, "<cond1>") == 0)
- sprintf(instr_part, "%s", token_cc_table[bits_unsigned(code, 15,12)]);
- else if(strcmp(token, "<cond2>") == 0)
- sprintf(instr_part, "%s", token_cc_table[bits_unsigned(code, 4,0)]);
- else if(strcmp(token, "<r1>") == 0)
- {
- const char * token_r1_table[] =
- {
- "reserved", "reserved", "w", "x",
- "reserved", "reserved", "w", "x"
- };
- sprintf(instr_part, "%s", token_r1_table[bits_unsigned(code, 15,13)]);
- }
- else if(strcmp(token, "<r2>") == 0)
- {
- static const char * token_r2_table[] =
- {
- "w","w","w", "x", "w", "w", "w", "x"
- };
- sprintf(instr_part, "%s", token_r2_table[bits_unsigned(code, 15,13)]);
- }
- else if(strcmp(token, "<m1>") == 0)
- {
- uint32_t reg = bits_unsigned(code, 20,16);
- if(reg == 31)
- sprintf(instr_part, "%s", "zr");
- else
- sprintf(instr_part, "%d", reg);
- }
- else if(strcmp(token, "<ext1>") == 0)
- {
- static const char * token_ext1_table[] =
- {
- "reserved","reserved","uxtw", "lsl",
- "reserved","reserved", "sxtw", "sxtx"
- };
- sprintf(instr_part, "%s", token_ext1_table[bits_unsigned(code, 15,13)]);
- }
- else if(strcmp(token, "<ext2>") == 0)
- {
- static const char * token_ext2_table[] =
- {
- "uxtb","uxth","uxtw","uxtx",
- "sxtb","sxth","sxtw","sxtx"
- };
- sprintf(instr_part, "%s", token_ext2_table[bits_unsigned(code, 15,13)]);
- }
- else if (strcmp(token, "<label1>") == 0)
- {
- int32_t offset = bits_signed(code, 23,5) * 4;
- if(offset > 0)
- sprintf(instr_part, "#.+%d", offset);
- else
- sprintf(instr_part, "#.-%d", -offset);
- }
- else if (strcmp(token, "<xn|sp>") == 0)
- {
- uint32_t reg = bits_unsigned(code, 9, 5);
- if(reg == 31)
- sprintf(instr_part, "%s", "sp");
- else
- sprintf(instr_part, "x%d", reg);
- }
- else if (strcmp(token, "<xd|sp>") == 0)
- {
- uint32_t reg = bits_unsigned(code, 4, 0);
- if(reg == 31)
- sprintf(instr_part, "%s", "sp");
- else
- sprintf(instr_part, "x%d", reg);
- }
- else if (strcmp(token, "<xn>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 9, 5), "x", instr_part);
- else if (strcmp(token, "<xd>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 4, 0), "x", instr_part);
- else if (strcmp(token, "<xm>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 20, 16), "x", instr_part);
- else if (strcmp(token, "<xa>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 14, 10), "x", instr_part);
- else if (strcmp(token, "<xt>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 4, 0), "x", instr_part);
- else if (strcmp(token, "<wn>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 9, 5), "w", instr_part);
- else if (strcmp(token, "<wd>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 4, 0), "w", instr_part);
- else if (strcmp(token, "<wm>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 20, 16), "w", instr_part);
- else if (strcmp(token, "<wa>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 14, 10), "w", instr_part);
- else if (strcmp(token, "<wt>") == 0)
- decode_rx_zr_token(bits_unsigned(code, 4, 0), "w", instr_part);
- else
- {
- sprintf(instr_part, "error");
- }
- return;
-}
-
-int arm64_disassemble(uint32_t code, char* instr)
-{
- uint32_t i;
- char token[256];
- char instr_part[256];
-
- if(instr == NULL)
- return -1;
-
- bool matched = false;
- disasm_table_entry_t *entry = NULL;
- for(i = 0; i < sizeof(disasm_table)/sizeof(disasm_table_entry_t); ++i)
- {
- entry = &disasm_table[i];
- if((code & entry->mask) == entry->value)
- {
- matched = true;
- break;
- }
- }
- if(matched == false)
- {
- strcpy(instr, "Unknown Instruction");
- return -1;
- }
- else
- {
- uint32_t index = 0;
- uint32_t length = strlen(entry->instr_template);
- instr[0] = '\0';
- do
- {
- get_token(entry->instr_template, index, token);
- if(token[0] == '<')
- {
- decode_token(code, token, instr_part);
- strcat(instr, instr_part);
- }
- else
- {
- strcat(instr, token);
- }
- index += strlen(token);
- }while(index < length);
- return 0;
- }
-}
diff --git a/libpixelflinger/codeflinger/Arm64Disassembler.h b/libpixelflinger/codeflinger/Arm64Disassembler.h
deleted file mode 100644
index 86f3aba..0000000
--- a/libpixelflinger/codeflinger/Arm64Disassembler.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef ANDROID_ARM64DISASSEMBLER_H
-#define ANDROID_ARM64DISASSEMBLER_H
-
-#include <inttypes.h>
-int arm64_disassemble(uint32_t code, char* instr);
-
-#endif //ANDROID_ARM64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/CodeCache.cpp b/libpixelflinger/codeflinger/CodeCache.cpp
deleted file mode 100644
index 32691a3..0000000
--- a/libpixelflinger/codeflinger/CodeCache.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/* libs/pixelflinger/codeflinger/CodeCache.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "CodeCache"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <cutils/ashmem.h>
-#include <log/log.h>
-
-#include "CodeCache.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-#if defined(__arm__) || defined(__aarch64__)
-#include <unistd.h>
-#include <errno.h>
-#endif
-
-#if defined(__mips__)
-#include <asm/cachectl.h>
-#include <errno.h>
-#endif
-
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-
-// A dlmalloc mspace is used to manage the code cache over a mmaped region.
-#define HAVE_MMAP 0
-#define HAVE_MREMAP 0
-#define HAVE_MORECORE 0
-#define MALLOC_ALIGNMENT 16
-#define MSPACES 1
-#define NO_MALLINFO 1
-#define ONLY_MSPACES 1
-// Custom heap error handling.
-#define PROCEED_ON_ERROR 0
-static void heap_error(const char* msg, const char* function, void* p);
-#define CORRUPTION_ERROR_ACTION(m) \
- heap_error("HEAP MEMORY CORRUPTION", __FUNCTION__, NULL)
-#define USAGE_ERROR_ACTION(m,p) \
- heap_error("ARGUMENT IS INVALID HEAP ADDRESS", __FUNCTION__, p)
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wexpansion-to-defined"
-#pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
-#include "../../../../external/dlmalloc/malloc.c"
-#pragma GCC diagnostic pop
-
-static void heap_error(const char* msg, const char* function, void* p) {
- ALOG(LOG_FATAL, LOG_TAG, "@@@ ABORTING: CODE FLINGER: %s IN %s addr=%p",
- msg, function, p);
- /* So that we can get a memory dump around p */
- *((int **) 0xdeadbaad) = (int *) p;
-}
-
-// ----------------------------------------------------------------------------
-
-static void* gExecutableStore = NULL;
-static mspace gMspace = NULL;
-const size_t kMaxCodeCacheCapacity = 1024 * 1024;
-
-static mspace getMspace()
-{
- if (gExecutableStore == NULL) {
- int fd = ashmem_create_region("CodeFlinger code cache",
- kMaxCodeCacheCapacity);
- LOG_ALWAYS_FATAL_IF(fd < 0,
- "Creating code cache, ashmem_create_region "
- "failed with error '%s'", strerror(errno));
- gExecutableStore = mmap(NULL, kMaxCodeCacheCapacity,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE, fd, 0);
- LOG_ALWAYS_FATAL_IF(gExecutableStore == MAP_FAILED,
- "Creating code cache, mmap failed with error "
- "'%s'", strerror(errno));
- close(fd);
- gMspace = create_mspace_with_base(gExecutableStore, kMaxCodeCacheCapacity,
- /*locked=*/ false);
- mspace_set_footprint_limit(gMspace, kMaxCodeCacheCapacity);
- }
- return gMspace;
-}
-
-Assembly::Assembly(size_t size)
- : mCount(0), mSize(0)
-{
- mBase = (uint32_t*)mspace_malloc(getMspace(), size);
- LOG_ALWAYS_FATAL_IF(mBase == NULL,
- "Failed to create Assembly of size %zd in executable "
- "store of size %zd", size, kMaxCodeCacheCapacity);
- mSize = size;
-}
-
-Assembly::~Assembly()
-{
- mspace_free(getMspace(), mBase);
-}
-
-void Assembly::incStrong(const void*) const
-{
- mCount.fetch_add(1, std::memory_order_relaxed);
-}
-
-void Assembly::decStrong(const void*) const
-{
- if (mCount.fetch_sub(1, std::memory_order_acq_rel) == 1) {
- delete this;
- }
-}
-
-ssize_t Assembly::size() const
-{
- if (!mBase) return NO_MEMORY;
- return mSize;
-}
-
-uint32_t* Assembly::base() const
-{
- return mBase;
-}
-
-ssize_t Assembly::resize(size_t newSize)
-{
- mBase = (uint32_t*)mspace_realloc(getMspace(), mBase, newSize);
- LOG_ALWAYS_FATAL_IF(mBase == NULL,
- "Failed to resize Assembly to %zd in code cache "
- "of size %zd", newSize, kMaxCodeCacheCapacity);
- mSize = newSize;
- return size();
-}
-
-// ----------------------------------------------------------------------------
-
-CodeCache::CodeCache(size_t size)
- : mCacheSize(size), mCacheInUse(0)
-{
- pthread_mutex_init(&mLock, 0);
-}
-
-CodeCache::~CodeCache()
-{
- pthread_mutex_destroy(&mLock);
-}
-
-sp<Assembly> CodeCache::lookup(const AssemblyKeyBase& keyBase) const
-{
- pthread_mutex_lock(&mLock);
- sp<Assembly> r;
- ssize_t index = mCacheData.indexOfKey(key_t(keyBase));
- if (index >= 0) {
- const cache_entry_t& e = mCacheData.valueAt(index);
- e.when = mWhen++;
- r = e.entry;
- }
- pthread_mutex_unlock(&mLock);
- return r;
-}
-
-int CodeCache::cache( const AssemblyKeyBase& keyBase,
- const sp<Assembly>& assembly)
-{
- pthread_mutex_lock(&mLock);
-
- const ssize_t assemblySize = assembly->size();
- while (mCacheInUse + assemblySize > mCacheSize) {
- // evict the LRU
- size_t lru = 0;
- size_t count = mCacheData.size();
- for (size_t i=0 ; i<count ; i++) {
- const cache_entry_t& e = mCacheData.valueAt(i);
- if (e.when < mCacheData.valueAt(lru).when) {
- lru = i;
- }
- }
- const cache_entry_t& e = mCacheData.valueAt(lru);
- mCacheInUse -= e.entry->size();
- mCacheData.removeItemsAt(lru);
- }
-
- ssize_t err = mCacheData.add(key_t(keyBase), cache_entry_t(assembly, mWhen));
- if (err >= 0) {
- mCacheInUse += assemblySize;
- mWhen++;
- // synchronize caches...
- char* base = reinterpret_cast<char*>(assembly->base());
- char* curr = reinterpret_cast<char*>(base + assembly->size());
- __builtin___clear_cache(base, curr);
- }
-
- pthread_mutex_unlock(&mLock);
- return err;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
diff --git a/libpixelflinger/codeflinger/CodeCache.h b/libpixelflinger/codeflinger/CodeCache.h
deleted file mode 100644
index 9326453..0000000
--- a/libpixelflinger/codeflinger/CodeCache.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/* libs/pixelflinger/codeflinger/CodeCache.h
-**
-** Copyright 2006, 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 ANDROID_CODECACHE_H
-#define ANDROID_CODECACHE_H
-
-#include <atomic>
-#include <stdint.h>
-#include <pthread.h>
-#include <sys/types.h>
-
-#include "utils/KeyedVector.h"
-#include "tinyutils/smartpointer.h"
-
-namespace android {
-
-using namespace tinyutils;
-
-// ----------------------------------------------------------------------------
-
-class AssemblyKeyBase {
-public:
- virtual ~AssemblyKeyBase() { }
- virtual int compare_type(const AssemblyKeyBase& key) const = 0;
-};
-
-template <typename T>
-class AssemblyKey : public AssemblyKeyBase
-{
-public:
- explicit AssemblyKey(const T& rhs) : mKey(rhs) { }
- virtual int compare_type(const AssemblyKeyBase& key) const {
- const T& rhs = static_cast<const AssemblyKey&>(key).mKey;
- return android::compare_type(mKey, rhs);
- }
-private:
- T mKey;
-};
-
-// ----------------------------------------------------------------------------
-
-class Assembly
-{
-public:
- explicit Assembly(size_t size);
- virtual ~Assembly();
-
- ssize_t size() const;
- uint32_t* base() const;
- ssize_t resize(size_t size);
-
- // protocol for sp<>
- void incStrong(const void* id) const;
- void decStrong(const void* id) const;
- typedef void weakref_type;
-
-private:
- mutable std::atomic<int32_t> mCount;
- uint32_t* mBase;
- size_t mSize;
-};
-
-// ----------------------------------------------------------------------------
-
-class CodeCache
-{
-public:
-// pretty simple cache API...
- explicit CodeCache(size_t size);
- ~CodeCache();
-
- sp<Assembly> lookup(const AssemblyKeyBase& key) const;
-
- int cache(const AssemblyKeyBase& key,
- const sp<Assembly>& assembly);
-
-private:
- // nothing to see here...
- struct cache_entry_t {
- inline cache_entry_t() { }
- inline cache_entry_t(const sp<Assembly>& a, int64_t w)
- : entry(a), when(w) { }
- sp<Assembly> entry;
- mutable int64_t when;
- };
-
- class key_t {
- friend int compare_type(
- const key_value_pair_t<key_t, cache_entry_t>&,
- const key_value_pair_t<key_t, cache_entry_t>&);
- const AssemblyKeyBase* mKey;
- public:
- key_t() { };
- explicit key_t(const AssemblyKeyBase& k) : mKey(&k) { }
- };
-
- mutable pthread_mutex_t mLock;
- mutable int64_t mWhen;
- size_t mCacheSize;
- size_t mCacheInUse;
- KeyedVector<key_t, cache_entry_t> mCacheData;
-
- friend int compare_type(
- const key_value_pair_t<key_t, cache_entry_t>&,
- const key_value_pair_t<key_t, cache_entry_t>&);
-};
-
-// KeyedVector uses compare_type(), which is more efficient, than
-// just using operator < ()
-inline int compare_type(
- const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& lhs,
- const key_value_pair_t<CodeCache::key_t, CodeCache::cache_entry_t>& rhs)
-{
- return lhs.key.mKey->compare_type(*(rhs.key.mKey));
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif //ANDROID_CODECACHE_H
diff --git a/libpixelflinger/codeflinger/GGLAssembler.cpp b/libpixelflinger/codeflinger/GGLAssembler.cpp
deleted file mode 100644
index 04e285d..0000000
--- a/libpixelflinger/codeflinger/GGLAssembler.cpp
+++ /dev/null
@@ -1,1195 +0,0 @@
-/* libs/pixelflinger/codeflinger/GGLAssembler.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "GGLAssembler"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-GGLAssembler::GGLAssembler(ARMAssemblerInterface* target)
- : ARMAssemblerProxy(target),
- RegisterAllocator(ARMAssemblerProxy::getCodegenArch()), mOptLevel(7)
-{
-}
-
-GGLAssembler::~GGLAssembler()
-{
-}
-
-void GGLAssembler::prolog()
-{
- ARMAssemblerProxy::prolog();
-}
-
-void GGLAssembler::epilog(uint32_t touched)
-{
- ARMAssemblerProxy::epilog(touched);
-}
-
-void GGLAssembler::reset(int opt_level)
-{
- ARMAssemblerProxy::reset();
- RegisterAllocator::reset();
- mOptLevel = opt_level;
-}
-
-// ---------------------------------------------------------------------------
-
-int GGLAssembler::scanline(const needs_t& needs, context_t const* c)
-{
- int err = 0;
- int opt_level = mOptLevel;
- while (opt_level >= 0) {
- reset(opt_level);
- err = scanline_core(needs, c);
- if (err == 0)
- break;
- opt_level--;
- }
-
- // XXX: in theory, pcForLabel is not valid before generate()
- uint32_t* fragment_start_pc = pcForLabel("fragment_loop");
- uint32_t* fragment_end_pc = pcForLabel("epilog");
- const int per_fragment_ops = int(fragment_end_pc - fragment_start_pc);
-
- // build a name for our pipeline
- char name[64];
- sprintf(name,
- "scanline__%08X:%08X_%08X_%08X [%3d ipp]",
- needs.p, needs.n, needs.t[0], needs.t[1], per_fragment_ops);
-
- if (err) {
- ALOGE("Error while generating ""%s""\n", name);
- disassemble(name);
- return -1;
- }
-
- return generate(name);
-}
-
-int GGLAssembler::scanline_core(const needs_t& needs, context_t const* c)
-{
- mBlendFactorCached = 0;
- mBlending = 0;
- mMasking = 0;
- mAA = GGL_READ_NEEDS(P_AA, needs.p);
- mDithering = GGL_READ_NEEDS(P_DITHER, needs.p);
- mAlphaTest = GGL_READ_NEEDS(P_ALPHA_TEST, needs.p) + GGL_NEVER;
- mDepthTest = GGL_READ_NEEDS(P_DEPTH_TEST, needs.p) + GGL_NEVER;
- mFog = GGL_READ_NEEDS(P_FOG, needs.p) != 0;
- mSmooth = GGL_READ_NEEDS(SHADE, needs.n) != 0;
- mBuilderContext.needs = needs;
- mBuilderContext.c = c;
- mBuilderContext.Rctx = reserveReg(R0); // context always in R0
- mCbFormat = c->formats[ GGL_READ_NEEDS(CB_FORMAT, needs.n) ];
-
- // ------------------------------------------------------------------------
-
- decodeLogicOpNeeds(needs);
-
- decodeTMUNeeds(needs, c);
-
- mBlendSrc = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRC, needs.n));
- mBlendDst = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DST, needs.n));
- mBlendSrcA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_SRCA, needs.n));
- mBlendDstA = ggl_needs_to_blendfactor(GGL_READ_NEEDS(BLEND_DSTA, needs.n));
-
- if (!mCbFormat.c[GGLFormat::ALPHA].h) {
- if ((mBlendSrc == GGL_ONE_MINUS_DST_ALPHA) ||
- (mBlendSrc == GGL_DST_ALPHA)) {
- mBlendSrc = GGL_ONE;
- }
- if ((mBlendSrcA == GGL_ONE_MINUS_DST_ALPHA) ||
- (mBlendSrcA == GGL_DST_ALPHA)) {
- mBlendSrcA = GGL_ONE;
- }
- if ((mBlendDst == GGL_ONE_MINUS_DST_ALPHA) ||
- (mBlendDst == GGL_DST_ALPHA)) {
- mBlendDst = GGL_ONE;
- }
- if ((mBlendDstA == GGL_ONE_MINUS_DST_ALPHA) ||
- (mBlendDstA == GGL_DST_ALPHA)) {
- mBlendDstA = GGL_ONE;
- }
- }
-
- // if we need the framebuffer, read it now
- const int blending = blending_codes(mBlendSrc, mBlendDst) |
- blending_codes(mBlendSrcA, mBlendDstA);
-
- // XXX: handle special cases, destination not modified...
- if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
- (mBlendDst==GGL_ONE) && (mBlendDstA==GGL_ONE)) {
- // Destination unmodified (beware of logic ops)
- } else if ((mBlendSrc==GGL_ZERO) && (mBlendSrcA==GGL_ZERO) &&
- (mBlendDst==GGL_ZERO) && (mBlendDstA==GGL_ZERO)) {
- // Destination is zero (beware of logic ops)
- }
-
- int fbComponents = 0;
- const int masking = GGL_READ_NEEDS(MASK_ARGB, needs.n);
- for (int i=0 ; i<4 ; i++) {
- const int mask = 1<<i;
- component_info_t& info = mInfo[i];
- int fs = i==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
- int fd = i==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
- if (fs==GGL_SRC_ALPHA_SATURATE && i==GGLFormat::ALPHA)
- fs = GGL_ONE;
- info.masked = !!(masking & mask);
- info.inDest = !info.masked && mCbFormat.c[i].h &&
- ((mLogicOp & LOGIC_OP_SRC) || (!mLogicOp));
- if (mCbFormat.components >= GGL_LUMINANCE &&
- (i==GGLFormat::GREEN || i==GGLFormat::BLUE)) {
- info.inDest = false;
- }
- info.needed = (i==GGLFormat::ALPHA) &&
- (isAlphaSourceNeeded() || mAlphaTest != GGL_ALWAYS);
- info.replaced = !!(mTextureMachine.replaced & mask);
- info.iterated = (!info.replaced && (info.inDest || info.needed));
- info.smooth = mSmooth && info.iterated;
- info.fog = mFog && info.inDest && (i != GGLFormat::ALPHA);
- info.blend = (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
-
- mBlending |= (info.blend ? mask : 0);
- mMasking |= (mCbFormat.c[i].h && info.masked) ? mask : 0;
- fbComponents |= mCbFormat.c[i].h ? mask : 0;
- }
-
- mAllMasked = (mMasking == fbComponents);
- if (mAllMasked) {
- mDithering = 0;
- }
-
- fragment_parts_t parts;
-
- // ------------------------------------------------------------------------
- prolog();
- // ------------------------------------------------------------------------
-
- build_scanline_prolog(parts, needs);
-
- if (registerFile().status())
- return registerFile().status();
-
- // ------------------------------------------------------------------------
- label("fragment_loop");
- // ------------------------------------------------------------------------
- {
- Scratch regs(registerFile());
-
- if (mDithering) {
- // update the dither index.
- MOV(AL, 0, parts.count.reg,
- reg_imm(parts.count.reg, ROR, GGL_DITHER_ORDER_SHIFT));
- ADD(AL, 0, parts.count.reg, parts.count.reg,
- imm( 1 << (32 - GGL_DITHER_ORDER_SHIFT)));
- MOV(AL, 0, parts.count.reg,
- reg_imm(parts.count.reg, ROR, 32 - GGL_DITHER_ORDER_SHIFT));
- }
-
- // XXX: could we do an early alpha-test here in some cases?
- // It would probaly be used only with smooth-alpha and no texture
- // (or no alpha component in the texture).
-
- // Early z-test
- if (mAlphaTest==GGL_ALWAYS) {
- build_depth_test(parts, Z_TEST|Z_WRITE);
- } else {
- // we cannot do the z-write here, because
- // it might be killed by the alpha-test later
- build_depth_test(parts, Z_TEST);
- }
-
- { // texture coordinates
- Scratch scratches(registerFile());
-
- // texel generation
- build_textures(parts, regs);
- if (registerFile().status())
- return registerFile().status();
- }
-
- if ((blending & (FACTOR_DST|BLEND_DST)) ||
- (mMasking && !mAllMasked) ||
- (mLogicOp & LOGIC_OP_DST))
- {
- // blending / logic_op / masking need the framebuffer
- mDstPixel.setTo(regs.obtain(), &mCbFormat);
-
- // load the framebuffer pixel
- comment("fetch color-buffer");
- load(parts.cbPtr, mDstPixel);
- }
-
- if (registerFile().status())
- return registerFile().status();
-
- pixel_t pixel;
- int directTex = mTextureMachine.directTexture;
- if (directTex | parts.packed) {
- // note: we can't have both here
- // iterated color or direct texture
- pixel = directTex ? parts.texel[directTex-1] : parts.iterated;
- pixel.flags &= ~CORRUPTIBLE;
- } else {
- if (mDithering) {
- const int ctxtReg = mBuilderContext.Rctx;
- const int mask = GGL_DITHER_SIZE-1;
- parts.dither = reg_t(regs.obtain());
- AND(AL, 0, parts.dither.reg, parts.count.reg, imm(mask));
- ADDR_ADD(AL, 0, parts.dither.reg, ctxtReg, parts.dither.reg);
- LDRB(AL, parts.dither.reg, parts.dither.reg,
- immed12_pre(GGL_OFFSETOF(ditherMatrix)));
- }
-
- // allocate a register for the resulting pixel
- pixel.setTo(regs.obtain(), &mCbFormat, FIRST);
-
- build_component(pixel, parts, GGLFormat::ALPHA, regs);
-
- if (mAlphaTest!=GGL_ALWAYS) {
- // only handle the z-write part here. We know z-test
- // was successful, as well as alpha-test.
- build_depth_test(parts, Z_WRITE);
- }
-
- build_component(pixel, parts, GGLFormat::RED, regs);
- build_component(pixel, parts, GGLFormat::GREEN, regs);
- build_component(pixel, parts, GGLFormat::BLUE, regs);
-
- pixel.flags |= CORRUPTIBLE;
- }
-
- if (registerFile().status())
- return registerFile().status();
-
- if (pixel.reg == -1) {
- // be defensive here. if we're here it's probably
- // that this whole fragment is a no-op.
- pixel = mDstPixel;
- }
-
- if (!mAllMasked) {
- // logic operation
- build_logic_op(pixel, regs);
-
- // masking
- build_masking(pixel, regs);
-
- comment("store");
- store(parts.cbPtr, pixel, WRITE_BACK);
- }
- }
-
- if (registerFile().status())
- return registerFile().status();
-
- // update the iterated color...
- if (parts.reload != 3) {
- build_smooth_shade(parts);
- }
-
- // update iterated z
- build_iterate_z(parts);
-
- // update iterated fog
- build_iterate_f(parts);
-
- SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
- B(PL, "fragment_loop");
- label("epilog");
- epilog(registerFile().touched());
-
- if ((mAlphaTest!=GGL_ALWAYS) || (mDepthTest!=GGL_ALWAYS)) {
- if (mDepthTest!=GGL_ALWAYS) {
- label("discard_before_textures");
- build_iterate_texture_coordinates(parts);
- }
- label("discard_after_textures");
- build_smooth_shade(parts);
- build_iterate_z(parts);
- build_iterate_f(parts);
- if (!mAllMasked) {
- ADDR_ADD(AL, 0, parts.cbPtr.reg, parts.cbPtr.reg, imm(parts.cbPtr.size>>3));
- }
- SUB(AL, S, parts.count.reg, parts.count.reg, imm(1<<16));
- B(PL, "fragment_loop");
- epilog(registerFile().touched());
- }
-
- return registerFile().status();
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_scanline_prolog(
- fragment_parts_t& parts, const needs_t& needs)
-{
- Scratch scratches(registerFile());
-
- // compute count
- comment("compute ct (# of pixels to process)");
- parts.count.setTo(obtainReg());
- int Rx = scratches.obtain();
- int Ry = scratches.obtain();
- CONTEXT_LOAD(Rx, iterators.xl);
- CONTEXT_LOAD(parts.count.reg, iterators.xr);
- CONTEXT_LOAD(Ry, iterators.y);
-
- // parts.count = iterators.xr - Rx
- SUB(AL, 0, parts.count.reg, parts.count.reg, Rx);
- SUB(AL, 0, parts.count.reg, parts.count.reg, imm(1));
-
- if (mDithering) {
- // parts.count.reg = 0xNNNNXXDD
- // NNNN = count-1
- // DD = dither offset
- // XX = 0xxxxxxx (x = garbage)
- Scratch scratches(registerFile());
- int tx = scratches.obtain();
- int ty = scratches.obtain();
- AND(AL, 0, tx, Rx, imm(GGL_DITHER_MASK));
- AND(AL, 0, ty, Ry, imm(GGL_DITHER_MASK));
- ADD(AL, 0, tx, tx, reg_imm(ty, LSL, GGL_DITHER_ORDER_SHIFT));
- ORR(AL, 0, parts.count.reg, tx, reg_imm(parts.count.reg, LSL, 16));
- } else {
- // parts.count.reg = 0xNNNN0000
- // NNNN = count-1
- MOV(AL, 0, parts.count.reg, reg_imm(parts.count.reg, LSL, 16));
- }
-
- if (!mAllMasked) {
- // compute dst ptr
- comment("compute color-buffer pointer");
- const int cb_bits = mCbFormat.size*8;
- int Rs = scratches.obtain();
- parts.cbPtr.setTo(obtainReg(), cb_bits);
- CONTEXT_LOAD(Rs, state.buffers.color.stride);
- CONTEXT_ADDR_LOAD(parts.cbPtr.reg, state.buffers.color.data);
- SMLABB(AL, Rs, Ry, Rs, Rx); // Rs = Rx + Ry*Rs
- base_offset(parts.cbPtr, parts.cbPtr, Rs);
- scratches.recycle(Rs);
- }
-
- // init fog
- const int need_fog = GGL_READ_NEEDS(P_FOG, needs.p);
- if (need_fog) {
- comment("compute initial fog coordinate");
- Scratch scratches(registerFile());
- int dfdx = scratches.obtain();
- int ydfdy = scratches.obtain();
- int f = ydfdy;
- CONTEXT_LOAD(dfdx, generated_vars.dfdx);
- CONTEXT_LOAD(ydfdy, iterators.ydfdy);
- MLA(AL, 0, f, Rx, dfdx, ydfdy);
- CONTEXT_STORE(f, generated_vars.f);
- }
-
- // init Z coordinate
- if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
- parts.z = reg_t(obtainReg());
- comment("compute initial Z coordinate");
- Scratch scratches(registerFile());
- int dzdx = scratches.obtain();
- int ydzdy = parts.z.reg;
- CONTEXT_LOAD(dzdx, generated_vars.dzdx); // 1.31 fixed-point
- CONTEXT_LOAD(ydzdy, iterators.ydzdy); // 1.31 fixed-point
- MLA(AL, 0, parts.z.reg, Rx, dzdx, ydzdy);
-
- // we're going to index zbase of parts.count
- // zbase = base + (xl-count + stride*y)*2
- int Rs = dzdx;
- int zbase = scratches.obtain();
- CONTEXT_LOAD(Rs, state.buffers.depth.stride);
- CONTEXT_ADDR_LOAD(zbase, state.buffers.depth.data);
- SMLABB(AL, Rs, Ry, Rs, Rx);
- ADD(AL, 0, Rs, Rs, reg_imm(parts.count.reg, LSR, 16));
- ADDR_ADD(AL, 0, zbase, zbase, reg_imm(Rs, LSL, 1));
- CONTEXT_ADDR_STORE(zbase, generated_vars.zbase);
- }
-
- // init texture coordinates
- init_textures(parts.coords, reg_t(Rx), reg_t(Ry));
- scratches.recycle(Ry);
-
- // iterated color
- init_iterated_color(parts, reg_t(Rx));
-
- // init coverage factor application (anti-aliasing)
- if (mAA) {
- parts.covPtr.setTo(obtainReg(), 16);
- CONTEXT_ADDR_LOAD(parts.covPtr.reg, state.buffers.coverage);
- ADDR_ADD(AL, 0, parts.covPtr.reg, parts.covPtr.reg, reg_imm(Rx, LSL, 1));
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_component( pixel_t& pixel,
- const fragment_parts_t& parts,
- int component,
- Scratch& regs)
-{
- static char const * comments[] = {"alpha", "red", "green", "blue"};
- comment(comments[component]);
-
- // local register file
- Scratch scratches(registerFile());
- const int dst_component_size = pixel.component_size(component);
-
- component_t temp(-1);
- build_incoming_component( temp, dst_component_size,
- parts, component, scratches, regs);
-
- if (mInfo[component].inDest) {
-
- // blending...
- build_blending( temp, mDstPixel, component, scratches );
-
- // downshift component and rebuild pixel...
- downshift(pixel, component, temp, parts.dither);
- }
-}
-
-void GGLAssembler::build_incoming_component(
- component_t& temp,
- int dst_size,
- const fragment_parts_t& parts,
- int component,
- Scratch& scratches,
- Scratch& global_regs)
-{
- const uint32_t component_mask = 1<<component;
-
- // Figure out what we need for the blending stage...
- int fs = component==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
- int fd = component==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
- if (fs==GGL_SRC_ALPHA_SATURATE && component==GGLFormat::ALPHA) {
- fs = GGL_ONE;
- }
-
- // Figure out what we need to extract and for what reason
- const int blending = blending_codes(fs, fd);
-
- // Are we actually going to blend?
- const int need_blending = (fs != int(GGL_ONE)) || (fd > int(GGL_ZERO));
-
- // expand the source if the destination has more bits
- int need_expander = false;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT-1 ; i++) {
- texture_unit_t& tmu = mTextureMachine.tmu[i];
- if ((tmu.format_idx) &&
- (parts.texel[i].component_size(component) < dst_size)) {
- need_expander = true;
- }
- }
-
- // do we need to extract this component?
- const bool multiTexture = mTextureMachine.activeUnits > 1;
- const int blend_needs_alpha_source = (component==GGLFormat::ALPHA) &&
- (isAlphaSourceNeeded());
- int need_extract = mInfo[component].needed;
- if (mInfo[component].inDest)
- {
- need_extract |= ((need_blending ?
- (blending & (BLEND_SRC|FACTOR_SRC)) : need_expander));
- need_extract |= (mTextureMachine.mask != mTextureMachine.replaced);
- need_extract |= mInfo[component].smooth;
- need_extract |= mInfo[component].fog;
- need_extract |= mDithering;
- need_extract |= multiTexture;
- }
-
- if (need_extract) {
- Scratch& regs = blend_needs_alpha_source ? global_regs : scratches;
- component_t fragment;
-
- // iterated color
- build_iterated_color(fragment, parts, component, regs);
-
- // texture environement (decal, modulate, replace)
- build_texture_environment(fragment, parts, component, regs);
-
- // expand the source if the destination has more bits
- if (need_expander && (fragment.size() < dst_size)) {
- // we're here only if we fetched a texel
- // (so we know for sure fragment is CORRUPTIBLE)
- expand(fragment, fragment, dst_size);
- }
-
- // We have a few specific things to do for the alpha-channel
- if ((component==GGLFormat::ALPHA) &&
- (mInfo[component].needed || fragment.size()<dst_size))
- {
- // convert to integer_t first and make sure
- // we don't corrupt a needed register
- if (fragment.l) {
- component_t incoming(fragment);
- modify(fragment, regs);
- MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSR, incoming.l));
- fragment.h -= fragment.l;
- fragment.l = 0;
- }
-
- // coverage factor application
- build_coverage_application(fragment, parts, regs);
-
- // alpha-test
- build_alpha_test(fragment, parts);
-
- if (blend_needs_alpha_source) {
- // We keep only 8 bits for the blending stage
- const int shift = fragment.h <= 8 ? 0 : fragment.h-8;
- if (fragment.flags & CORRUPTIBLE) {
- fragment.flags &= ~CORRUPTIBLE;
- mAlphaSource.setTo(fragment.reg,
- fragment.size(), fragment.flags);
- if (shift) {
- MOV(AL, 0, mAlphaSource.reg,
- reg_imm(mAlphaSource.reg, LSR, shift));
- }
- } else {
- // XXX: it would better to do this in build_blend_factor()
- // so we can avoid the extra MOV below.
- mAlphaSource.setTo(regs.obtain(),
- fragment.size(), CORRUPTIBLE);
- if (shift) {
- MOV(AL, 0, mAlphaSource.reg,
- reg_imm(fragment.reg, LSR, shift));
- } else {
- MOV(AL, 0, mAlphaSource.reg, fragment.reg);
- }
- }
- mAlphaSource.s -= shift;
- }
- }
-
- // fog...
- build_fog( fragment, component, regs );
-
- temp = fragment;
- } else {
- if (mInfo[component].inDest) {
- // extraction not needed and replace
- // we just select the right component
- if ((mTextureMachine.replaced & component_mask) == 0) {
- // component wasn't replaced, so use it!
- temp = component_t(parts.iterated, component);
- }
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- const texture_unit_t& tmu = mTextureMachine.tmu[i];
- if ((tmu.mask & component_mask) &&
- ((tmu.replaced & component_mask) == 0)) {
- temp = component_t(parts.texel[i], component);
- }
- }
- }
- }
-}
-
-bool GGLAssembler::isAlphaSourceNeeded() const
-{
- // XXX: also needed for alpha-test
- const int bs = mBlendSrc;
- const int bd = mBlendDst;
- return bs==GGL_SRC_ALPHA_SATURATE ||
- bs==GGL_SRC_ALPHA || bs==GGL_ONE_MINUS_SRC_ALPHA ||
- bd==GGL_SRC_ALPHA || bd==GGL_ONE_MINUS_SRC_ALPHA ;
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_smooth_shade(const fragment_parts_t& parts)
-{
- if (mSmooth && !parts.iterated_packed) {
- // update the iterated color in a pipelined way...
- comment("update iterated color");
- Scratch scratches(registerFile());
-
- const int reload = parts.reload;
- for (int i=0 ; i<4 ; i++) {
- if (!mInfo[i].iterated)
- continue;
-
- int c = parts.argb[i].reg;
- int dx = parts.argb_dx[i].reg;
-
- if (reload & 1) {
- c = scratches.obtain();
- CONTEXT_LOAD(c, generated_vars.argb[i].c);
- }
- if (reload & 2) {
- dx = scratches.obtain();
- CONTEXT_LOAD(dx, generated_vars.argb[i].dx);
- }
-
- if (mSmooth) {
- ADD(AL, 0, c, c, dx);
- }
-
- if (reload & 1) {
- CONTEXT_STORE(c, generated_vars.argb[i].c);
- scratches.recycle(c);
- }
- if (reload & 2) {
- scratches.recycle(dx);
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_coverage_application(component_t& fragment,
- const fragment_parts_t& parts, Scratch& regs)
-{
- // here fragment.l is guarenteed to be 0
- if (mAA) {
- // coverages are 1.15 fixed-point numbers
- comment("coverage application");
-
- component_t incoming(fragment);
- modify(fragment, regs);
-
- Scratch scratches(registerFile());
- int cf = scratches.obtain();
- LDRH(AL, cf, parts.covPtr.reg, immed8_post(2));
- if (fragment.h > 31) {
- fragment.h--;
- SMULWB(AL, fragment.reg, incoming.reg, cf);
- } else {
- MOV(AL, 0, fragment.reg, reg_imm(incoming.reg, LSL, 1));
- SMULWB(AL, fragment.reg, fragment.reg, cf);
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_alpha_test(component_t& fragment,
- const fragment_parts_t& /*parts*/)
-{
- if (mAlphaTest != GGL_ALWAYS) {
- comment("Alpha Test");
- Scratch scratches(registerFile());
- int ref = scratches.obtain();
- const int shift = GGL_COLOR_BITS-fragment.size();
- CONTEXT_LOAD(ref, state.alpha_test.ref);
- if (shift) CMP(AL, fragment.reg, reg_imm(ref, LSR, shift));
- else CMP(AL, fragment.reg, ref);
- int cc = NV;
- switch (mAlphaTest) {
- case GGL_NEVER: cc = NV; break;
- case GGL_LESS: cc = LT; break;
- case GGL_EQUAL: cc = EQ; break;
- case GGL_LEQUAL: cc = LS; break;
- case GGL_GREATER: cc = HI; break;
- case GGL_NOTEQUAL: cc = NE; break;
- case GGL_GEQUAL: cc = HS; break;
- }
- B(cc^1, "discard_after_textures");
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_depth_test(
- const fragment_parts_t& parts, uint32_t mask)
-{
- mask &= Z_TEST|Z_WRITE;
- const needs_t& needs = mBuilderContext.needs;
- const int zmask = GGL_READ_NEEDS(P_MASK_Z, needs.p);
- Scratch scratches(registerFile());
-
- if (mDepthTest != GGL_ALWAYS || zmask) {
- int cc=AL, ic=AL;
- switch (mDepthTest) {
- case GGL_LESS: ic = HI; break;
- case GGL_EQUAL: ic = EQ; break;
- case GGL_LEQUAL: ic = HS; break;
- case GGL_GREATER: ic = LT; break;
- case GGL_NOTEQUAL: ic = NE; break;
- case GGL_GEQUAL: ic = LS; break;
- case GGL_NEVER:
- // this never happens, because it's taken care of when
- // computing the needs. but we keep it for completness.
- comment("Depth Test (NEVER)");
- B(AL, "discard_before_textures");
- return;
- case GGL_ALWAYS:
- // we're here because zmask is enabled
- mask &= ~Z_TEST; // test always passes.
- break;
- }
-
- // inverse the condition
- cc = ic^1;
-
- if ((mask & Z_WRITE) && !zmask) {
- mask &= ~Z_WRITE;
- }
-
- if (!mask)
- return;
-
- comment("Depth Test");
-
- int zbase = scratches.obtain();
- int depth = scratches.obtain();
- int z = parts.z.reg;
-
- CONTEXT_ADDR_LOAD(zbase, generated_vars.zbase); // stall
- ADDR_SUB(AL, 0, zbase, zbase, reg_imm(parts.count.reg, LSR, 15));
- // above does zbase = zbase + ((count >> 16) << 1)
-
- if (mask & Z_TEST) {
- LDRH(AL, depth, zbase); // stall
- CMP(AL, depth, reg_imm(z, LSR, 16));
- B(cc, "discard_before_textures");
- }
- if (mask & Z_WRITE) {
- if (mask == Z_WRITE) {
- // only z-write asked, cc is meaningless
- ic = AL;
- }
- MOV(AL, 0, depth, reg_imm(z, LSR, 16));
- STRH(ic, depth, zbase);
- }
- }
-}
-
-void GGLAssembler::build_iterate_z(const fragment_parts_t& parts)
-{
- const needs_t& needs = mBuilderContext.needs;
- if ((mDepthTest != GGL_ALWAYS) || GGL_READ_NEEDS(P_MASK_Z, needs.p)) {
- Scratch scratches(registerFile());
- int dzdx = scratches.obtain();
- CONTEXT_LOAD(dzdx, generated_vars.dzdx); // stall
- ADD(AL, 0, parts.z.reg, parts.z.reg, dzdx);
- }
-}
-
-void GGLAssembler::build_iterate_f(const fragment_parts_t& /*parts*/)
-{
- const needs_t& needs = mBuilderContext.needs;
- if (GGL_READ_NEEDS(P_FOG, needs.p)) {
- Scratch scratches(registerFile());
- int dfdx = scratches.obtain();
- int f = scratches.obtain();
- CONTEXT_LOAD(f, generated_vars.f);
- CONTEXT_LOAD(dfdx, generated_vars.dfdx); // stall
- ADD(AL, 0, f, f, dfdx);
- CONTEXT_STORE(f, generated_vars.f);
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_logic_op(pixel_t& pixel, Scratch& regs)
-{
- const needs_t& needs = mBuilderContext.needs;
- const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
- if (opcode == GGL_COPY)
- return;
-
- comment("logic operation");
-
- pixel_t s(pixel);
- if (!(pixel.flags & CORRUPTIBLE)) {
- pixel.reg = regs.obtain();
- pixel.flags |= CORRUPTIBLE;
- }
-
- pixel_t d(mDstPixel);
- switch(opcode) {
- case GGL_CLEAR: MOV(AL, 0, pixel.reg, imm(0)); break;
- case GGL_AND: AND(AL, 0, pixel.reg, s.reg, d.reg); break;
- case GGL_AND_REVERSE: BIC(AL, 0, pixel.reg, s.reg, d.reg); break;
- case GGL_COPY: break;
- case GGL_AND_INVERTED: BIC(AL, 0, pixel.reg, d.reg, s.reg); break;
- case GGL_NOOP: MOV(AL, 0, pixel.reg, d.reg); break;
- case GGL_XOR: EOR(AL, 0, pixel.reg, s.reg, d.reg); break;
- case GGL_OR: ORR(AL, 0, pixel.reg, s.reg, d.reg); break;
- case GGL_NOR: ORR(AL, 0, pixel.reg, s.reg, d.reg);
- MVN(AL, 0, pixel.reg, pixel.reg); break;
- case GGL_EQUIV: EOR(AL, 0, pixel.reg, s.reg, d.reg);
- MVN(AL, 0, pixel.reg, pixel.reg); break;
- case GGL_INVERT: MVN(AL, 0, pixel.reg, d.reg); break;
- case GGL_OR_REVERSE: // s | ~d == ~(~s & d)
- BIC(AL, 0, pixel.reg, d.reg, s.reg);
- MVN(AL, 0, pixel.reg, pixel.reg); break;
- case GGL_COPY_INVERTED: MVN(AL, 0, pixel.reg, s.reg); break;
- case GGL_OR_INVERTED: // ~s | d == ~(s & ~d)
- BIC(AL, 0, pixel.reg, s.reg, d.reg);
- MVN(AL, 0, pixel.reg, pixel.reg); break;
- case GGL_NAND: AND(AL, 0, pixel.reg, s.reg, d.reg);
- MVN(AL, 0, pixel.reg, pixel.reg); break;
- case GGL_SET: MVN(AL, 0, pixel.reg, imm(0)); break;
- };
-}
-
-// ---------------------------------------------------------------------------
-
-static uint32_t find_bottom(uint32_t val)
-{
- uint32_t i = 0;
- while (!(val & (3<<i)))
- i+= 2;
- return i;
-}
-
-static void normalize(uint32_t& val, uint32_t& rot)
-{
- rot = 0;
- while (!(val&3) || (val & 0xFC000000)) {
- uint32_t newval;
- newval = val >> 2;
- newval |= (val&3) << 30;
- val = newval;
- rot += 2;
- if (rot == 32) {
- rot = 0;
- break;
- }
- }
-}
-
-void GGLAssembler::build_and_immediate(int d, int s, uint32_t mask, int bits)
-{
- uint32_t rot;
- uint32_t size = ((bits>=32) ? 0 : (1LU << bits)) - 1;
- mask &= size;
-
- if (mask == size) {
- if (d != s)
- MOV( AL, 0, d, s);
- return;
- }
-
- if ((getCodegenArch() == CODEGEN_ARCH_MIPS) ||
- (getCodegenArch() == CODEGEN_ARCH_MIPS64)) {
- // MIPS can do 16-bit imm in 1 instr, 32-bit in 3 instr
- // the below ' while (mask)' code is buggy on mips
- // since mips returns true on isValidImmediate()
- // then we get multiple AND instr (positive logic)
- AND( AL, 0, d, s, imm(mask) );
- return;
- }
- else if (getCodegenArch() == CODEGEN_ARCH_ARM64) {
- AND( AL, 0, d, s, imm(mask) );
- return;
- }
-
- int negative_logic = !isValidImmediate(mask);
- if (negative_logic) {
- mask = ~mask & size;
- }
- normalize(mask, rot);
-
- if (mask) {
- while (mask) {
- uint32_t bitpos = find_bottom(mask);
- int shift = rot + bitpos;
- uint32_t m = mask & (0xff << bitpos);
- mask &= ~m;
- m >>= bitpos;
- int32_t newMask = (m<<shift) | (m>>(32-shift));
- if (!negative_logic) {
- AND( AL, 0, d, s, imm(newMask) );
- } else {
- BIC( AL, 0, d, s, imm(newMask) );
- }
- s = d;
- }
- } else {
- MOV( AL, 0, d, imm(0));
- }
-}
-
-void GGLAssembler::build_masking(pixel_t& pixel, Scratch& regs)
-{
- if (!mMasking || mAllMasked) {
- return;
- }
-
- comment("color mask");
-
- pixel_t fb(mDstPixel);
- pixel_t s(pixel);
- if (!(pixel.flags & CORRUPTIBLE)) {
- pixel.reg = regs.obtain();
- pixel.flags |= CORRUPTIBLE;
- }
-
- int mask = 0;
- for (int i=0 ; i<4 ; i++) {
- const int component_mask = 1<<i;
- const int h = fb.format.c[i].h;
- const int l = fb.format.c[i].l;
- if (h && (!(mMasking & component_mask))) {
- mask |= ((1<<(h-l))-1) << l;
- }
- }
-
- // There is no need to clear the masked components of the source
- // (unless we applied a logic op), because they're already zeroed
- // by construction (masked components are not computed)
-
- if (mLogicOp) {
- const needs_t& needs = mBuilderContext.needs;
- const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
- if (opcode != GGL_CLEAR) {
- // clear masked component of source
- build_and_immediate(pixel.reg, s.reg, mask, fb.size());
- s = pixel;
- }
- }
-
- // clear non masked components of destination
- build_and_immediate(fb.reg, fb.reg, ~mask, fb.size());
-
- // or back the channels that were masked
- if (s.reg == fb.reg) {
- // this is in fact a MOV
- if (s.reg == pixel.reg) {
- // ugh. this in in fact a nop
- } else {
- MOV(AL, 0, pixel.reg, fb.reg);
- }
- } else {
- ORR(AL, 0, pixel.reg, s.reg, fb.reg);
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::base_offset(
- const pointer_t& d, const pointer_t& b, const reg_t& o)
-{
- switch (b.size) {
- case 32:
- ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 2));
- break;
- case 24:
- if (d.reg == b.reg) {
- ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
- ADDR_ADD(AL, 0, d.reg, d.reg, o.reg);
- } else {
- ADDR_ADD(AL, 0, d.reg, o.reg, reg_imm(o.reg, LSL, 1));
- ADDR_ADD(AL, 0, d.reg, d.reg, b.reg);
- }
- break;
- case 16:
- ADDR_ADD(AL, 0, d.reg, b.reg, reg_imm(o.reg, LSL, 1));
- break;
- case 8:
- ADDR_ADD(AL, 0, d.reg, b.reg, o.reg);
- break;
- }
-}
-
-// ----------------------------------------------------------------------------
-// cheezy register allocator...
-// ----------------------------------------------------------------------------
-
-// Modified to support MIPS processors, in a very simple way. We retain the
-// (Arm) limit of 16 total registers, but shift the mapping of those registers
-// from 0-15, to 2-17. Register 0 on Mips cannot be used as GP registers, and
-// register 1 has a traditional use as a temp).
-
-RegisterAllocator::RegisterAllocator(int arch) : mRegs(arch)
-{
-}
-
-void RegisterAllocator::reset()
-{
- mRegs.reset();
-}
-
-int RegisterAllocator::reserveReg(int reg)
-{
- return mRegs.reserve(reg);
-}
-
-int RegisterAllocator::obtainReg()
-{
- return mRegs.obtain();
-}
-
-void RegisterAllocator::recycleReg(int reg)
-{
- mRegs.recycle(reg);
-}
-
-RegisterAllocator::RegisterFile& RegisterAllocator::registerFile()
-{
- return mRegs;
-}
-
-// ----------------------------------------------------------------------------
-
-RegisterAllocator::RegisterFile::RegisterFile(int codegen_arch)
- : mRegs(0), mTouched(0), mStatus(0), mArch(codegen_arch), mRegisterOffset(0)
-{
- if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) ||
- (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) {
- mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17
- }
- reserve(ARMAssemblerInterface::SP);
- reserve(ARMAssemblerInterface::PC);
-}
-
-RegisterAllocator::RegisterFile::RegisterFile(const RegisterFile& rhs, int codegen_arch)
- : mRegs(rhs.mRegs), mTouched(rhs.mTouched), mArch(codegen_arch), mRegisterOffset(0)
-{
- if ((mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS) ||
- (mArch == ARMAssemblerInterface::CODEGEN_ARCH_MIPS64)) {
- mRegisterOffset = 2; // ARM has regs 0..15, MIPS offset to 2..17
- }
-}
-
-RegisterAllocator::RegisterFile::~RegisterFile()
-{
-}
-
-bool RegisterAllocator::RegisterFile::operator == (const RegisterFile& rhs) const
-{
- return (mRegs == rhs.mRegs);
-}
-
-void RegisterAllocator::RegisterFile::reset()
-{
- mRegs = mTouched = mStatus = 0;
- reserve(ARMAssemblerInterface::SP);
- reserve(ARMAssemblerInterface::PC);
-}
-
-// RegisterFile::reserve() take a register parameter in the
-// range 0-15 (Arm compatible), but on a Mips processor, will
-// return the actual allocated register in the range 2-17.
-int RegisterAllocator::RegisterFile::reserve(int reg)
-{
- reg += mRegisterOffset;
- LOG_ALWAYS_FATAL_IF(isUsed(reg),
- "reserving register %d, but already in use",
- reg);
- mRegs |= (1<<reg);
- mTouched |= mRegs;
- return reg;
-}
-
-// This interface uses regMask in range 2-17 on MIPS, no translation.
-void RegisterAllocator::RegisterFile::reserveSeveral(uint32_t regMask)
-{
- mRegs |= regMask;
- mTouched |= regMask;
-}
-
-int RegisterAllocator::RegisterFile::isUsed(int reg) const
-{
- LOG_ALWAYS_FATAL_IF(reg>=16+(int)mRegisterOffset, "invalid register %d", reg);
- return mRegs & (1<<reg);
-}
-
-int RegisterAllocator::RegisterFile::obtain()
-{
- const char priorityList[14] = { 0, 1, 2, 3,
- 12, 14, 4, 5,
- 6, 7, 8, 9,
- 10, 11 };
- const int nbreg = sizeof(priorityList);
- int i, r, reg;
- for (i=0 ; i<nbreg ; i++) {
- r = priorityList[i];
- if (!isUsed(r + mRegisterOffset)) {
- break;
- }
- }
- // this is not an error anymore because, we'll try again with
- // a lower optimization level.
- //ALOGE_IF(i >= nbreg, "pixelflinger ran out of registers\n");
- if (i >= nbreg) {
- mStatus |= OUT_OF_REGISTERS;
- // we return SP so we can more easily debug things
- // the code will never be run anyway.
- return ARMAssemblerInterface::SP;
- }
- reg = reserve(r); // Param in Arm range 0-15, returns range 2-17 on Mips.
- return reg;
-}
-
-bool RegisterAllocator::RegisterFile::hasFreeRegs() const
-{
- uint32_t regs = mRegs >> mRegisterOffset; // MIPS fix.
- return ((regs & 0xFFFF) == 0xFFFF) ? false : true;
-}
-
-int RegisterAllocator::RegisterFile::countFreeRegs() const
-{
- uint32_t regs = mRegs >> mRegisterOffset; // MIPS fix.
- int f = ~regs & 0xFFFF;
- // now count number of 1
- f = (f & 0x5555) + ((f>>1) & 0x5555);
- f = (f & 0x3333) + ((f>>2) & 0x3333);
- f = (f & 0x0F0F) + ((f>>4) & 0x0F0F);
- f = (f & 0x00FF) + ((f>>8) & 0x00FF);
- return f;
-}
-
-void RegisterAllocator::RegisterFile::recycle(int reg)
-{
- // commented out, since common failure of running out of regs
- // triggers this assertion. Since the code is not execectued
- // in that case, it does not matter. No reason to FATAL err.
- // LOG_FATAL_IF(!isUsed(reg),
- // "recycling unallocated register %d",
- // reg);
- mRegs &= ~(1<<reg);
-}
-
-void RegisterAllocator::RegisterFile::recycleSeveral(uint32_t regMask)
-{
- // commented out, since common failure of running out of regs
- // triggers this assertion. Since the code is not execectued
- // in that case, it does not matter. No reason to FATAL err.
- // LOG_FATAL_IF((mRegs & regMask)!=regMask,
- // "recycling unallocated registers "
- // "(recycle=%08x, allocated=%08x, unallocated=%08x)",
- // regMask, mRegs, mRegs®Mask);
- mRegs &= ~regMask;
-}
-
-uint32_t RegisterAllocator::RegisterFile::touched() const
-{
- return mTouched;
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/GGLAssembler.h b/libpixelflinger/codeflinger/GGLAssembler.h
deleted file mode 100644
index 47dbf3a..0000000
--- a/libpixelflinger/codeflinger/GGLAssembler.h
+++ /dev/null
@@ -1,572 +0,0 @@
-/* libs/pixelflinger/codeflinger/GGLAssembler.h
-**
-** Copyright 2006, 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 ANDROID_GGLASSEMBLER_H
-#define ANDROID_GGLASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include "ARMAssemblerProxy.h"
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-#define CONTEXT_ADDR_LOAD(REG, FIELD) \
- ADDR_LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
-
-#define CONTEXT_ADDR_STORE(REG, FIELD) \
- ADDR_STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
-
-#define CONTEXT_LOAD(REG, FIELD) \
- LDR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
-
-#define CONTEXT_STORE(REG, FIELD) \
- STR(AL, REG, mBuilderContext.Rctx, immed12_pre(GGL_OFFSETOF(FIELD)))
-
-
-class RegisterAllocator
-{
-public:
- class RegisterFile;
-
- RegisterAllocator(int arch); // NOLINT, implicit
- RegisterFile& registerFile();
- int reserveReg(int reg);
- int obtainReg();
- void recycleReg(int reg);
- void reset();
-
- class RegisterFile
- {
- public:
- RegisterFile(int arch); // NOLINT, implicit
- RegisterFile(const RegisterFile& rhs, int arch);
- ~RegisterFile();
-
- void reset();
-
- bool operator == (const RegisterFile& rhs) const;
- bool operator != (const RegisterFile& rhs) const {
- return !operator == (rhs);
- }
-
- int reserve(int reg);
- void reserveSeveral(uint32_t regMask);
-
- void recycle(int reg);
- void recycleSeveral(uint32_t regMask);
-
- int obtain();
- inline int isUsed(int reg) const;
-
- bool hasFreeRegs() const;
- int countFreeRegs() const;
-
- uint32_t touched() const;
- inline uint32_t status() const { return mStatus; }
-
- enum {
- OUT_OF_REGISTERS = 0x1
- };
-
- private:
- uint32_t mRegs;
- uint32_t mTouched;
- uint32_t mStatus;
- int mArch;
- uint32_t mRegisterOffset; // lets reg alloc use 2..17 for mips
- // while arm uses 0..15
- };
-
- class Scratch
- {
- public:
- explicit Scratch(RegisterFile& regFile)
- : mRegFile(regFile), mScratch(0) {
- }
- ~Scratch() {
- mRegFile.recycleSeveral(mScratch);
- }
- int obtain() {
- int reg = mRegFile.obtain();
- mScratch |= 1<<reg;
- return reg;
- }
- void recycle(int reg) {
- mRegFile.recycle(reg);
- mScratch &= ~(1<<reg);
- }
- bool isUsed(int reg) {
- return (mScratch & (1<<reg));
- }
- int countFreeRegs() {
- return mRegFile.countFreeRegs();
- }
- private:
- RegisterFile& mRegFile;
- uint32_t mScratch;
- };
-
- class Spill
- {
- public:
- Spill(RegisterFile& regFile, ARMAssemblerInterface& gen, uint32_t reglist)
- : mRegFile(regFile), mGen(gen), mRegList(reglist), mCount(0)
- {
- if (reglist) {
- int count = 0;
- while (reglist) {
- count++;
- reglist &= ~(1 << (31 - __builtin_clz(reglist)));
- }
- if (count == 1) {
- int reg = 31 - __builtin_clz(mRegList);
- mGen.STR(mGen.AL, reg, mGen.SP, mGen.immed12_pre(-4, 1));
- } else {
- mGen.STM(mGen.AL, mGen.DB, mGen.SP, 1, mRegList);
- }
- mRegFile.recycleSeveral(mRegList);
- mCount = count;
- }
- }
- ~Spill() {
- if (mRegList) {
- if (mCount == 1) {
- int reg = 31 - __builtin_clz(mRegList);
- mGen.LDR(mGen.AL, reg, mGen.SP, mGen.immed12_post(4));
- } else {
- mGen.LDM(mGen.AL, mGen.IA, mGen.SP, 1, mRegList);
- }
- mRegFile.reserveSeveral(mRegList);
- }
- }
- private:
- RegisterFile& mRegFile;
- ARMAssemblerInterface& mGen;
- uint32_t mRegList;
- int mCount;
- };
-
-private:
- RegisterFile mRegs;
-};
-
-// ----------------------------------------------------------------------------
-
-class GGLAssembler : public ARMAssemblerProxy, public RegisterAllocator
-{
-public:
-
- explicit GGLAssembler(ARMAssemblerInterface* target);
- virtual ~GGLAssembler();
-
- uint32_t* base() const { return 0; } // XXX
- uint32_t* pc() const { return 0; } // XXX
-
- void reset(int opt_level);
-
- virtual void prolog();
- virtual void epilog(uint32_t touched);
-
- // generate scanline code for given needs
- int scanline(const needs_t& needs, context_t const* c);
- int scanline_core(const needs_t& needs, context_t const* c);
-
- enum {
- CLEAR_LO = 0x0001,
- CLEAR_HI = 0x0002,
- CORRUPTIBLE = 0x0004,
- FIRST = 0x0008
- };
-
- enum { //load/store flags
- WRITE_BACK = 0x0001
- };
-
- struct reg_t {
- reg_t() : reg(-1), flags(0) {
- }
- reg_t(int r, int f=0) // NOLINT, implicit
- : reg(r), flags(f) {
- }
- void setTo(int r, int f=0) {
- reg=r; flags=f;
- }
- int reg;
- uint16_t flags;
- };
-
- struct integer_t : public reg_t {
- integer_t() : reg_t(), s(0) {
- }
- integer_t(int r, int sz=32, int f=0) // NOLINT, implicit
- : reg_t(r, f), s(sz) {
- }
- void setTo(int r, int sz=32, int f=0) {
- reg_t::setTo(r, f); s=sz;
- }
- int8_t s;
- inline int size() const { return s; }
- };
-
- struct pixel_t : public reg_t {
- pixel_t() : reg_t() {
- memset(&format, 0, sizeof(GGLFormat));
- }
- pixel_t(int r, const GGLFormat* fmt, int f=0)
- : reg_t(r, f), format(*fmt) {
- }
- void setTo(int r, const GGLFormat* fmt, int f=0) {
- reg_t::setTo(r, f); format = *fmt;
- }
- GGLFormat format;
- inline int hi(int c) const { return format.c[c].h; }
- inline int low(int c) const { return format.c[c].l; }
- inline int mask(int c) const { return ((1<<size(c))-1) << low(c); }
- inline int size() const { return format.size*8; }
- inline int size(int c) const { return component_size(c); }
- inline int component_size(int c) const { return hi(c) - low(c); }
- };
-
- struct component_t : public reg_t {
- component_t() : reg_t(), h(0), l(0) {
- }
- component_t(int r, int f=0) // NOLINT, implicit
- : reg_t(r, f), h(0), l(0) {
- }
- component_t(int r, int lo, int hi, int f=0)
- : reg_t(r, f), h(hi), l(lo) {
- }
- explicit component_t(const integer_t& rhs)
- : reg_t(rhs.reg, rhs.flags), h(rhs.s), l(0) {
- }
- explicit component_t(const pixel_t& rhs, int component) {
- setTo( rhs.reg,
- rhs.format.c[component].l,
- rhs.format.c[component].h,
- rhs.flags|CLEAR_LO|CLEAR_HI);
- }
- void setTo(int r, int lo=0, int hi=0, int f=0) {
- reg_t::setTo(r, f); h=hi; l=lo;
- }
- int8_t h;
- int8_t l;
- inline int size() const { return h-l; }
- };
-
- struct pointer_t : public reg_t {
- pointer_t() : reg_t(), size(0) {
- }
- pointer_t(int r, int s, int f=0)
- : reg_t(r, f), size(s) {
- }
- void setTo(int r, int s, int f=0) {
- reg_t::setTo(r, f); size=s;
- }
- int8_t size;
- };
-
-
-private:
- // GGLAssembler hides RegisterAllocator's and ARMAssemblerProxy's reset
- // methods by providing a reset method with a different parameter set. The
- // intent of GGLAssembler's reset method is to wrap the inherited reset
- // methods, so make these methods private in order to prevent direct calls
- // to these methods from clients.
- using RegisterAllocator::reset;
- using ARMAssemblerProxy::reset;
-
- struct tex_coord_t {
- reg_t s;
- reg_t t;
- pointer_t ptr;
- };
-
- struct fragment_parts_t {
- uint32_t packed : 1;
- uint32_t reload : 2;
- uint32_t iterated_packed : 1;
- pixel_t iterated;
- pointer_t cbPtr;
- pointer_t covPtr;
- reg_t count;
- reg_t argb[4];
- reg_t argb_dx[4];
- reg_t z;
- reg_t dither;
- pixel_t texel[GGL_TEXTURE_UNIT_COUNT];
- tex_coord_t coords[GGL_TEXTURE_UNIT_COUNT];
- };
-
- struct texture_unit_t {
- int format_idx;
- GGLFormat format;
- int bits;
- int swrap;
- int twrap;
- int env;
- int pot;
- int linear;
- uint8_t mask;
- uint8_t replaced;
- };
-
- struct texture_machine_t {
- texture_unit_t tmu[GGL_TEXTURE_UNIT_COUNT];
- uint8_t mask;
- uint8_t replaced;
- uint8_t directTexture;
- uint8_t activeUnits;
- };
-
- struct component_info_t {
- bool masked : 1;
- bool inDest : 1;
- bool needed : 1;
- bool replaced : 1;
- bool iterated : 1;
- bool smooth : 1;
- bool blend : 1;
- bool fog : 1;
- };
-
- struct builder_context_t {
- context_t const* c;
- needs_t needs;
- int Rctx;
- };
-
- template <typename T>
- void modify(T& r, Scratch& regs)
- {
- if (!(r.flags & CORRUPTIBLE)) {
- r.reg = regs.obtain();
- r.flags |= CORRUPTIBLE;
- }
- }
-
- // helpers
- void base_offset(const pointer_t& d, const pointer_t& b, const reg_t& o);
-
- // texture environement
- void modulate( component_t& dest,
- const component_t& incoming,
- const pixel_t& texel, int component);
-
- void decal( component_t& dest,
- const component_t& incoming,
- const pixel_t& texel, int component);
-
- void blend( component_t& dest,
- const component_t& incoming,
- const pixel_t& texel, int component, int tmu);
-
- void add( component_t& dest,
- const component_t& incoming,
- const pixel_t& texel, int component);
-
- // load/store stuff
- void store(const pointer_t& addr, const pixel_t& src, uint32_t flags=0);
- void load(const pointer_t& addr, const pixel_t& dest, uint32_t flags=0);
- void extract(integer_t& d, const pixel_t& s, int component);
- void extract(component_t& d, const pixel_t& s, int component);
- void extract(integer_t& d, int s, int h, int l, int bits=32);
- void expand(integer_t& d, const integer_t& s, int dbits);
- void expand(integer_t& d, const component_t& s, int dbits);
- void expand(component_t& d, const component_t& s, int dbits);
- void downshift(pixel_t& d, int component, component_t s, const reg_t& dither);
-
-
- void mul_factor( component_t& d,
- const integer_t& v,
- const integer_t& f);
-
- void mul_factor_add( component_t& d,
- const integer_t& v,
- const integer_t& f,
- const component_t& a);
-
- void component_add( component_t& d,
- const integer_t& dst,
- const integer_t& src);
-
- void component_sat( const component_t& v);
-
-
- void build_scanline_prolog( fragment_parts_t& parts,
- const needs_t& needs);
-
- void build_smooth_shade(const fragment_parts_t& parts);
-
- void build_component( pixel_t& pixel,
- const fragment_parts_t& parts,
- int component,
- Scratch& global_scratches);
-
- void build_incoming_component(
- component_t& temp,
- int dst_size,
- const fragment_parts_t& parts,
- int component,
- Scratch& scratches,
- Scratch& global_scratches);
-
- void init_iterated_color(fragment_parts_t& parts, const reg_t& x);
-
- void build_iterated_color( component_t& fragment,
- const fragment_parts_t& parts,
- int component,
- Scratch& regs);
-
- void decodeLogicOpNeeds(const needs_t& needs);
-
- void decodeTMUNeeds(const needs_t& needs, context_t const* c);
-
- void init_textures( tex_coord_t* coords,
- const reg_t& x,
- const reg_t& y);
-
- void build_textures( fragment_parts_t& parts,
- Scratch& regs);
-
- void filter8( const fragment_parts_t& parts,
- pixel_t& texel, const texture_unit_t& tmu,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS);
-
- void filter16( const fragment_parts_t& parts,
- pixel_t& texel, const texture_unit_t& tmu,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS);
-
- void filter24( const fragment_parts_t& parts,
- pixel_t& texel, const texture_unit_t& tmu,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS);
-
- void filter32( const fragment_parts_t& parts,
- pixel_t& texel, const texture_unit_t& tmu,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS);
-
- void build_texture_environment( component_t& fragment,
- const fragment_parts_t& parts,
- int component,
- Scratch& regs);
-
- void wrapping( int d,
- int coord, int size,
- int tx_wrap, int tx_linear);
-
- void build_fog( component_t& temp,
- int component,
- Scratch& parent_scratches);
-
- void build_blending( component_t& in_out,
- const pixel_t& pixel,
- int component,
- Scratch& parent_scratches);
-
- void build_blend_factor(
- integer_t& factor, int f, int component,
- const pixel_t& dst_pixel,
- integer_t& fragment,
- integer_t& fb,
- Scratch& scratches);
-
- void build_blendFOneMinusF( component_t& temp,
- const integer_t& factor,
- const integer_t& fragment,
- const integer_t& fb);
-
- void build_blendOneMinusFF( component_t& temp,
- const integer_t& factor,
- const integer_t& fragment,
- const integer_t& fb);
-
- void build_coverage_application(component_t& fragment,
- const fragment_parts_t& parts,
- Scratch& regs);
-
- void build_alpha_test(component_t& fragment, const fragment_parts_t& parts);
-
- enum { Z_TEST=1, Z_WRITE=2 };
- void build_depth_test(const fragment_parts_t& parts, uint32_t mask);
- void build_iterate_z(const fragment_parts_t& parts);
- void build_iterate_f(const fragment_parts_t& parts);
- void build_iterate_texture_coordinates(const fragment_parts_t& parts);
-
- void build_logic_op(pixel_t& pixel, Scratch& regs);
-
- void build_masking(pixel_t& pixel, Scratch& regs);
-
- void build_and_immediate(int d, int s, uint32_t mask, int bits);
-
- bool isAlphaSourceNeeded() const;
-
- enum {
- FACTOR_SRC=1, FACTOR_DST=2, BLEND_SRC=4, BLEND_DST=8
- };
-
- enum {
- LOGIC_OP=1, LOGIC_OP_SRC=2, LOGIC_OP_DST=4
- };
-
- static int blending_codes(int fs, int fd);
-
- builder_context_t mBuilderContext;
- texture_machine_t mTextureMachine;
- component_info_t mInfo[4];
- int mBlending;
- int mMasking;
- int mAllMasked;
- int mLogicOp;
- int mAlphaTest;
- int mAA;
- int mDithering;
- int mDepthTest;
-
- int mSmooth;
- int mFog;
- pixel_t mDstPixel;
-
- GGLFormat mCbFormat;
-
- int mBlendFactorCached;
- integer_t mAlphaSource;
-
- int mBaseRegister;
-
- int mBlendSrc;
- int mBlendDst;
- int mBlendSrcA;
- int mBlendDstA;
-
- int mOptLevel;
-};
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GGLASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
deleted file mode 100644
index d6d2156..0000000
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ /dev/null
@@ -1,1447 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPS64Assembler.cpp
-**
-** Copyright 2015, 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.
-*/
-
-
-/* MIPS64 assembler and ARM->MIPS64 assembly translator
-**
-** The approach is utilize MIPSAssembler generator, using inherited MIPS64Assembler
-** that overrides just the specific MIPS64r6 instructions.
-** For now ArmToMips64Assembler is copied over from ArmToMipsAssembler class,
-** changing some MIPS64r6 related stuff.
-**
-*/
-
-#define LOG_TAG "MIPS64Assembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "MIPS64Assembler.h"
-#include "CodeCache.h"
-#include "mips64_disassem.h"
-
-#define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
-#define __unused __attribute__((__unused__))
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark ArmToMips64Assembler...
-#endif
-
-ArmToMips64Assembler::ArmToMips64Assembler(const sp<Assembly>& assembly,
- char *abuf, int linesz, int instr_count)
- : ARMAssemblerInterface(),
- mArmDisassemblyBuffer(abuf),
- mArmLineLength(linesz),
- mArmInstrCount(instr_count),
- mInum(0),
- mAssembly(assembly)
-{
- mMips = new MIPS64Assembler(assembly, this);
- mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
- init_conditional_labels();
-}
-
-ArmToMips64Assembler::ArmToMips64Assembler(void* assembly)
- : ARMAssemblerInterface(),
- mArmDisassemblyBuffer(NULL),
- mInum(0),
- mAssembly(NULL)
-{
- mMips = new MIPS64Assembler(assembly, this);
- mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
- init_conditional_labels();
-}
-
-ArmToMips64Assembler::~ArmToMips64Assembler()
-{
- delete mMips;
- free((void *) mArmPC);
-}
-
-uint32_t* ArmToMips64Assembler::pc() const
-{
- return mMips->pc();
-}
-
-uint32_t* ArmToMips64Assembler::base() const
-{
- return mMips->base();
-}
-
-void ArmToMips64Assembler::reset()
-{
- cond.labelnum = 0;
- mInum = 0;
- mMips->reset();
-}
-
-int ArmToMips64Assembler::getCodegenArch()
-{
- return CODEGEN_ARCH_MIPS64;
-}
-
-void ArmToMips64Assembler::comment(const char* string)
-{
- mMips->comment(string);
-}
-
-void ArmToMips64Assembler::label(const char* theLabel)
-{
- mMips->label(theLabel);
-}
-
-void ArmToMips64Assembler::disassemble(const char* name)
-{
- mMips->disassemble(name);
-}
-
-void ArmToMips64Assembler::init_conditional_labels()
-{
- int i;
- for (i=0;i<99; ++i) {
- sprintf(cond.label[i], "cond_%d", i);
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Prolog/Epilog & Generate...
-#endif
-
-void ArmToMips64Assembler::prolog()
-{
- mArmPC[mInum++] = pc(); // save starting PC for this instr
-
- mMips->DADDIU(R_sp, R_sp, -(5 * 8));
- mMips->SD(R_s0, R_sp, 0);
- mMips->SD(R_s1, R_sp, 8);
- mMips->SD(R_s2, R_sp, 16);
- mMips->SD(R_s3, R_sp, 24);
- mMips->SD(R_s4, R_sp, 32);
- mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0)
-}
-
-void ArmToMips64Assembler::epilog(uint32_t touched __unused)
-{
- mArmPC[mInum++] = pc(); // save starting PC for this instr
-
- mMips->LD(R_s0, R_sp, 0);
- mMips->LD(R_s1, R_sp, 8);
- mMips->LD(R_s2, R_sp, 16);
- mMips->LD(R_s3, R_sp, 24);
- mMips->LD(R_s4, R_sp, 32);
- mMips->DADDIU(R_sp, R_sp, (5 * 8));
- mMips->JR(R_ra);
-
-}
-
-int ArmToMips64Assembler::generate(const char* name)
-{
- return mMips->generate(name);
-}
-
-void ArmToMips64Assembler::fix_branches()
-{
- mMips->fix_branches();
-}
-
-uint32_t* ArmToMips64Assembler::pcForLabel(const char* label)
-{
- return mMips->pcForLabel(label);
-}
-
-void ArmToMips64Assembler::set_condition(int mode, int R1, int R2) {
- if (mode == 2) {
- cond.type = SBIT_COND;
- } else {
- cond.type = CMP_COND;
- }
- cond.r1 = R1;
- cond.r2 = R2;
-}
-
-//----------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Addressing modes & shifters...
-#endif
-
-
-// do not need this for MIPS, but it is in the Interface (virtual)
-int ArmToMips64Assembler::buildImmediate(
- uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
- // for MIPS, any 32-bit immediate is OK
- rot = 0;
- imm = immediate;
- return 0;
-}
-
-// shifters...
-
-bool ArmToMips64Assembler::isValidImmediate(uint32_t immediate __unused)
-{
- // for MIPS, any 32-bit immediate is OK
- return true;
-}
-
-uint32_t ArmToMips64Assembler::imm(uint32_t immediate)
-{
- amode.value = immediate;
- return AMODE_IMM;
-}
-
-uint32_t ArmToMips64Assembler::reg_imm(int Rm, int type, uint32_t shift)
-{
- amode.reg = Rm;
- amode.stype = type;
- amode.value = shift;
- return AMODE_REG_IMM;
-}
-
-uint32_t ArmToMips64Assembler::reg_rrx(int Rm __unused)
-{
- // reg_rrx mode is not used in the GLLAssember code at this time
- return AMODE_UNSUPPORTED;
-}
-
-uint32_t ArmToMips64Assembler::reg_reg(int Rm __unused, int type __unused,
- int Rs __unused)
-{
- // reg_reg mode is not used in the GLLAssember code at this time
- return AMODE_UNSUPPORTED;
-}
-
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMips64Assembler::immed12_pre(int32_t immed12, int W)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
- "LDR(B)/STR(B)/PLD immediate too big (%08x)",
- immed12);
- amode.value = immed12;
- amode.writeback = W;
- return AMODE_IMM_12_PRE;
-}
-
-uint32_t ArmToMips64Assembler::immed12_post(int32_t immed12)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
- "LDR(B)/STR(B)/PLD immediate too big (%08x)",
- immed12);
-
- amode.value = immed12;
- return AMODE_IMM_12_POST;
-}
-
-uint32_t ArmToMips64Assembler::reg_scale_pre(int Rm, int type,
- uint32_t shift, int W)
-{
- LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented");
-
- amode.reg = Rm;
- // amode.stype = type; // more advanced modes not used in GGLAssembler yet
- // amode.value = shift;
- // amode.writeback = W;
- return AMODE_REG_SCALE_PRE;
-}
-
-uint32_t ArmToMips64Assembler::reg_scale_post(int Rm __unused, int type __unused,
- uint32_t shift __unused)
-{
- LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n");
- return AMODE_UNSUPPORTED;
-}
-
-// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMips64Assembler::immed8_pre(int32_t immed8, int W __unused)
-{
- LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n");
-
- LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
- "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
- immed8);
- return AMODE_IMM_8_PRE;
-}
-
-uint32_t ArmToMips64Assembler::immed8_post(int32_t immed8)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
- "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
- immed8);
- amode.value = immed8;
- return AMODE_IMM_8_POST;
-}
-
-uint32_t ArmToMips64Assembler::reg_pre(int Rm, int W)
-{
- LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented");
- amode.reg = Rm;
- return AMODE_REG_PRE;
-}
-
-uint32_t ArmToMips64Assembler::reg_post(int Rm __unused)
-{
- LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n");
- return AMODE_UNSUPPORTED;
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Data Processing...
-#endif
-
-// check if the operand registers from a previous CMP or S-bit instruction
-// would be overwritten by this instruction. If so, move the value to a
-// safe register.
-// Note that we cannot tell at _this_ instruction time if a future (conditional)
-// instruction will _also_ use this value (a defect of the simple 1-pass, one-
-// instruction-at-a-time translation). Therefore we must be conservative and
-// save the value before it is overwritten. This costs an extra MOVE instr.
-
-void ArmToMips64Assembler::protectConditionalOperands(int Rd)
-{
- if (Rd == cond.r1) {
- mMips->MOVE(R_cmp, cond.r1);
- cond.r1 = R_cmp;
- }
- if (cond.type == CMP_COND && Rd == cond.r2) {
- mMips->MOVE(R_cmp2, cond.r2);
- cond.r2 = R_cmp2;
- }
-}
-
-
-// interprets the addressing mode, and generates the common code
-// used by the majority of data-processing ops. Many MIPS instructions
-// have a register-based form and a different immediate form. See
-// opAND below for an example. (this could be inlined)
-//
-// this works with the imm(), reg_imm() methods above, which are directly
-// called by the GLLAssembler.
-// note: _signed parameter defaults to false (un-signed)
-// note: tmpReg parameter defaults to 1, MIPS register AT
-int ArmToMips64Assembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg)
-{
- if (op < AMODE_REG) {
- source = op;
- return SRC_REG;
- } else if (op == AMODE_IMM) {
- if ((!_signed && amode.value > 0xffff)
- || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) {
- mMips->LUI(tmpReg, (amode.value >> 16));
- if (amode.value & 0x0000ffff) {
- mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff));
- }
- source = tmpReg;
- return SRC_REG;
- } else {
- source = amode.value;
- return SRC_IMM;
- }
- } else if (op == AMODE_REG_IMM) {
- switch (amode.stype) {
- case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break;
- case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break;
- case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break;
- case ROR: mMips->ROTR(tmpReg, amode.reg, amode.value); break;
- }
- source = tmpReg;
- return SRC_REG;
- } else { // adr mode RRX is not used in GGL Assembler at this time
- // we are screwed, this should be exception, assert-fail or something
- LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n");
- return SRC_ERROR;
- }
-}
-
-
-void ArmToMips64Assembler::dataProcessing(int opcode, int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
- int src; // src is modified by dataProcAdrModes() - passed as int&
-
- if (cc != AL) {
- protectConditionalOperands(Rd);
- // the branch tests register(s) set by prev CMP or instr with 'S' bit set
- // inverse the condition to jump past this conditional instruction
- ArmToMips64Assembler::B(cc^1, cond.label[++cond.labelnum]);
- } else {
- mArmPC[mInum++] = pc(); // save starting PC for this instr
- }
-
- switch (opcode) {
- case opAND:
- if (dataProcAdrModes(Op2, src) == SRC_REG) {
- mMips->AND(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->ANDI(Rd, Rn, src);
- }
- break;
-
- case opADD:
- // set "signed" to true for adr modes
- if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
- mMips->ADDU(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->ADDIU(Rd, Rn, src);
- }
- break;
-
- case opSUB:
- // set "signed" to true for adr modes
- if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
- mMips->SUBU(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->SUBIU(Rd, Rn, src);
- }
- break;
-
- case opADD64:
- // set "signed" to true for adr modes
- if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
- mMips->DADDU(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->DADDIU(Rd, Rn, src);
- }
- break;
-
- case opSUB64:
- // set "signed" to true for adr modes
- if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
- mMips->DSUBU(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->DSUBIU(Rd, Rn, src);
- }
- break;
-
- case opEOR:
- if (dataProcAdrModes(Op2, src) == SRC_REG) {
- mMips->XOR(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->XORI(Rd, Rn, src);
- }
- break;
-
- case opORR:
- if (dataProcAdrModes(Op2, src) == SRC_REG) {
- mMips->OR(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->ORI(Rd, Rn, src);
- }
- break;
-
- case opBIC:
- if (dataProcAdrModes(Op2, src) == SRC_IMM) {
- // if we are 16-bit imnmediate, load to AT reg
- mMips->ORI(R_at, 0, src);
- src = R_at;
- }
- mMips->NOT(R_at, src);
- mMips->AND(Rd, Rn, R_at);
- break;
-
- case opRSB:
- if (dataProcAdrModes(Op2, src) == SRC_IMM) {
- // if we are 16-bit imnmediate, load to AT reg
- mMips->ORI(R_at, 0, src);
- src = R_at;
- }
- mMips->SUBU(Rd, src, Rn); // subu with the parameters reversed
- break;
-
- case opMOV:
- if (Op2 < AMODE_REG) { // op2 is reg # in this case
- mMips->MOVE(Rd, Op2);
- } else if (Op2 == AMODE_IMM) {
- if (amode.value > 0xffff) {
- mMips->LUI(Rd, (amode.value >> 16));
- if (amode.value & 0x0000ffff) {
- mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
- }
- } else {
- mMips->ORI(Rd, 0, amode.value);
- }
- } else if (Op2 == AMODE_REG_IMM) {
- switch (amode.stype) {
- case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
- case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
- case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
- case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break;
- }
- }
- else {
- // adr mode RRX is not used in GGL Assembler at this time
- mMips->UNIMPL();
- }
- break;
-
- case opMVN: // this is a 1's complement: NOT
- if (Op2 < AMODE_REG) { // op2 is reg # in this case
- mMips->NOR(Rd, Op2, 0); // NOT is NOR with 0
- break;
- } else if (Op2 == AMODE_IMM) {
- if (amode.value > 0xffff) {
- mMips->LUI(Rd, (amode.value >> 16));
- if (amode.value & 0x0000ffff) {
- mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
- }
- } else {
- mMips->ORI(Rd, 0, amode.value);
- }
- } else if (Op2 == AMODE_REG_IMM) {
- switch (amode.stype) {
- case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
- case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
- case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
- case ROR: mMips->ROTR(Rd, amode.reg, amode.value); break;
- }
- }
- else {
- // adr mode RRX is not used in GGL Assembler at this time
- mMips->UNIMPL();
- }
- mMips->NOR(Rd, Rd, 0); // NOT is NOR with 0
- break;
-
- case opCMP:
- // Either operand of a CMP instr could get overwritten by a subsequent
- // conditional instruction, which is ok, _UNLESS_ there is a _second_
- // conditional instruction. Under MIPS, this requires doing the comparison
- // again (SLT), and the original operands must be available. (and this
- // pattern of multiple conditional instructions from same CMP _is_ used
- // in GGL-Assembler)
- //
- // For now, if a conditional instr overwrites the operands, we will
- // move them to dedicated temp regs. This is ugly, and inefficient,
- // and should be optimized.
- //
- // WARNING: making an _Assumption_ that CMP operand regs will NOT be
- // trashed by intervening NON-conditional instructions. In the general
- // case this is legal, but it is NOT currently done in GGL-Assembler.
-
- cond.type = CMP_COND;
- cond.r1 = Rn;
- if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) {
- cond.r2 = src;
- } else { // adr mode was SRC_IMM
- mMips->ORI(R_cmp2, R_zero, src);
- cond.r2 = R_cmp2;
- }
-
- break;
-
-
- case opTST:
- case opTEQ:
- case opCMN:
- case opADC:
- case opSBC:
- case opRSC:
- mMips->UNIMPL(); // currently unused in GGL Assembler code
- break;
- }
-
- if (cc != AL) {
- mMips->label(cond.label[cond.labelnum]);
- }
- if (s && opcode != opCMP) {
- cond.type = SBIT_COND;
- cond.r1 = Rd;
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Multiply...
-#endif
-
-// multiply, accumulate
-void ArmToMips64Assembler::MLA(int cc __unused, int s,
- int Rd, int Rm, int Rs, int Rn) {
-
- //ALOGW("MLA");
- mArmPC[mInum++] = pc(); // save starting PC for this instr
-
- mMips->MUL(R_at, Rm, Rs);
- mMips->ADDU(Rd, R_at, Rn);
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = Rd;
- }
-}
-
-void ArmToMips64Assembler::MUL(int cc __unused, int s,
- int Rd, int Rm, int Rs) {
- mArmPC[mInum++] = pc();
- mMips->MUL(Rd, Rm, Rs);
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = Rd;
- }
-}
-
-void ArmToMips64Assembler::UMULL(int cc __unused, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- mArmPC[mInum++] = pc();
- mMips->MUH(RdHi, Rm, Rs);
- mMips->MUL(RdLo, Rm, Rs);
-
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
- }
-}
-
-void ArmToMips64Assembler::UMUAL(int cc __unused, int s,
- int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- // *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
- // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
- }
-}
-
-void ArmToMips64Assembler::SMULL(int cc __unused, int s,
- int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
- // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n");
- }
-}
-void ArmToMips64Assembler::SMUAL(int cc __unused, int s,
- int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
- // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n");
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Branches...
-#endif
-
-// branches...
-
-void ArmToMips64Assembler::B(int cc, const char* label)
-{
- mArmPC[mInum++] = pc();
- if (cond.type == SBIT_COND) { cond.r2 = R_zero; }
-
- switch(cc) {
- case EQ: mMips->BEQ(cond.r1, cond.r2, label); break;
- case NE: mMips->BNE(cond.r1, cond.r2, label); break;
- case HS: mMips->BGEU(cond.r1, cond.r2, label); break;
- case LO: mMips->BLTU(cond.r1, cond.r2, label); break;
- case MI: mMips->BLT(cond.r1, cond.r2, label); break;
- case PL: mMips->BGE(cond.r1, cond.r2, label); break;
-
- case HI: mMips->BGTU(cond.r1, cond.r2, label); break;
- case LS: mMips->BLEU(cond.r1, cond.r2, label); break;
- case GE: mMips->BGE(cond.r1, cond.r2, label); break;
- case LT: mMips->BLT(cond.r1, cond.r2, label); break;
- case GT: mMips->BGT(cond.r1, cond.r2, label); break;
- case LE: mMips->BLE(cond.r1, cond.r2, label); break;
- case AL: mMips->B(label); break;
- case NV: /* B Never - no instruction */ break;
-
- case VS:
- case VC:
- default:
- LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc);
- break;
- }
-}
-
-void ArmToMips64Assembler::BL(int cc __unused, const char* label __unused)
-{
- LOG_ALWAYS_FATAL("branch-and-link not supported yet\n");
- mArmPC[mInum++] = pc();
-}
-
-// no use for Branches with integer PC, but they're in the Interface class ....
-void ArmToMips64Assembler::B(int cc __unused, uint32_t* to_pc __unused)
-{
- LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
- mArmPC[mInum++] = pc();
-}
-
-void ArmToMips64Assembler::BL(int cc __unused, uint32_t* to_pc __unused)
-{
- LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
- mArmPC[mInum++] = pc();
-}
-
-void ArmToMips64Assembler::BX(int cc __unused, int Rn __unused)
-{
- LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
- mArmPC[mInum++] = pc();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Data Transfer...
-#endif
-
-// data transfer...
-void ArmToMips64Assembler::LDR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP
- }
- mMips->LW(Rd, Rn, amode.value);
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- mMips->DADDIU(Rn, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP
- }
- mMips->LW(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->DADDU(R_at, Rn, amode.reg);
- mMips->LW(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMips64Assembler::LDRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- mMips->LBU(Rd, Rn, amode.value);
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- mMips->DADDIU(Rn, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- mMips->LBU(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->DADDU(R_at, Rn, amode.reg);
- mMips->LBU(Rd, R_at, 0);
- break;
- }
-
-}
-
-void ArmToMips64Assembler::STR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP
- }
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- // If we will writeback, then update the index reg, then store.
- // This correctly handles stack-push case.
- mMips->DADDIU(Rn, Rn, amode.value);
- mMips->SW(Rd, Rn, 0);
- } else {
- // No writeback so store offset by value
- mMips->SW(Rd, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- mMips->SW(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->DADDU(R_at, Rn, amode.reg);
- mMips->SW(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMips64Assembler::STRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- mMips->SB(Rd, Rn, amode.value);
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- mMips->DADDIU(Rn, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- mMips->SB(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->DADDU(R_at, Rn, amode.reg);
- mMips->SB(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMips64Assembler::LDRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed8_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- // fall thru to next case ....
- case AMODE_IMM_8_PRE: // no support yet for writeback
- mMips->LHU(Rd, Rn, amode.value);
- break;
- case AMODE_IMM_8_POST:
- mMips->LHU(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_PRE:
- // we only support simple base +/- index
- if (amode.reg >= 0) {
- mMips->DADDU(R_at, Rn, amode.reg);
- } else {
- mMips->DSUBU(R_at, Rn, abs(amode.reg));
- }
- mMips->LHU(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMips64Assembler::LDRSB(int cc __unused, int Rd __unused,
- int Rn __unused, uint32_t offset __unused)
-{
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::LDRSH(int cc __unused, int Rd __unused,
- int Rn __unused, uint32_t offset __unused)
-{
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::STRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed8_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- // fall thru to next case ....
- case AMODE_IMM_8_PRE: // no support yet for writeback
- mMips->SH(Rd, Rn, amode.value);
- break;
- case AMODE_IMM_8_POST:
- mMips->SH(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_PRE:
- // we only support simple base +/- index
- if (amode.reg >= 0) {
- mMips->DADDU(R_at, Rn, amode.reg);
- } else {
- mMips->DSUBU(R_at, Rn, abs(amode.reg));
- }
- mMips->SH(Rd, R_at, 0);
- break;
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Block Data Transfer...
-#endif
-
-// block data transfer...
-void ArmToMips64Assembler::LDM(int cc __unused, int dir __unused,
- int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{ // ED FD EA FA IB IA DB DA
- // const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
- // const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
- // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
- // (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::STM(int cc __unused, int dir __unused,
- int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{ // FA EA FD ED IB IA DB DA
- // const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
- // const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
- // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
- // (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Special...
-#endif
-
-// special...
-void ArmToMips64Assembler::SWP(int cc __unused, int Rn __unused,
- int Rd __unused, int Rm __unused) {
- // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::SWPB(int cc __unused, int Rn __unused,
- int Rd __unused, int Rm __unused) {
- // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::SWI(int cc __unused, uint32_t comment __unused) {
- // *mPC++ = (cc<<28) | (0xF<<24) | comment;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark DSP instructions...
-#endif
-
-// DSP instructions...
-void ArmToMips64Assembler::PLD(int Rn __unused, uint32_t offset) {
- LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
- "PLD only P=1, W=0");
- // *mPC++ = 0xF550F000 | (Rn<<16) | offset;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::CLZ(int cc __unused, int Rd, int Rm)
-{
- mArmPC[mInum++] = pc();
- mMips->CLZ(Rd, Rm);
-}
-
-void ArmToMips64Assembler::QADD(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::QDADD(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::QSUB(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::QDSUB(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-// 16 x 16 signed multiply (like SMLAxx without the accumulate)
-void ArmToMips64Assembler::SMUL(int cc __unused, int xy,
- int Rd, int Rm, int Rs)
-{
- mArmPC[mInum++] = pc();
-
- // the 16 bits may be in the top or bottom half of 32-bit source reg,
- // as defined by the codes BB, BT, TB, TT (compressed param xy)
- // where x corresponds to Rm and y to Rs
-
- // select half-reg for Rm
- if (xy & xyTB) {
- // use top 16-bits
- mMips->SRA(R_at, Rm, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- mMips->SEH(R_at, Rm);
- }
- // select half-reg for Rs
- if (xy & xyBT) {
- // use top 16-bits
- mMips->SRA(R_at2, Rs, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- mMips->SEH(R_at2, Rs);
- }
- mMips->MUL(Rd, R_at, R_at2);
-}
-
-// signed 32b x 16b multiple, save top 32-bits of 48-bit result
-void ArmToMips64Assembler::SMULW(int cc __unused, int y,
- int Rd, int Rm, int Rs)
-{
- mArmPC[mInum++] = pc();
-
- // the selector yT or yB refers to reg Rs
- if (y & yT) {
- // zero the bottom 16-bits, with 2 shifts, it can affect result
- mMips->SRL(R_at, Rs, 16);
- mMips->SLL(R_at, R_at, 16);
-
- } else {
- // move low 16-bit half, to high half
- mMips->SLL(R_at, Rs, 16);
- }
- mMips->MUH(Rd, Rm, R_at);
-}
-
-// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn
-void ArmToMips64Assembler::SMLA(int cc __unused, int xy,
- int Rd, int Rm, int Rs, int Rn)
-{
- mArmPC[mInum++] = pc();
-
- // the 16 bits may be in the top or bottom half of 32-bit source reg,
- // as defined by the codes BB, BT, TB, TT (compressed param xy)
- // where x corresponds to Rm and y to Rs
-
- // select half-reg for Rm
- if (xy & xyTB) {
- // use top 16-bits
- mMips->SRA(R_at, Rm, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- mMips->SEH(R_at, Rm);
- }
- // select half-reg for Rs
- if (xy & xyBT) {
- // use top 16-bits
- mMips->SRA(R_at2, Rs, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- mMips->SEH(R_at2, Rs);
- }
-
- mMips->MUL(R_at, R_at, R_at2);
- mMips->ADDU(Rd, R_at, Rn);
-}
-
-void ArmToMips64Assembler::SMLAL(int cc __unused, int xy __unused,
- int RdHi __unused, int RdLo __unused,
- int Rs __unused, int Rm __unused)
-{
- // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMips64Assembler::SMLAW(int cc __unused, int y __unused,
- int Rd __unused, int Rm __unused,
- int Rs __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-// used by ARMv6 version of GGLAssembler::filter32
-void ArmToMips64Assembler::UXTB16(int cc __unused, int Rd, int Rm, int rotate)
-{
- mArmPC[mInum++] = pc();
-
- //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]),
- //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3.
-
- mMips->ROTR(R_at2, Rm, rotate * 8);
- mMips->LUI(R_at, 0xFF);
- mMips->ORI(R_at, R_at, 0xFF);
- mMips->AND(Rd, R_at2, R_at);
-}
-
-void ArmToMips64Assembler::UBFX(int cc __unused, int Rd __unused, int Rn __unused,
- int lsb __unused, int width __unused)
-{
- /* Placeholder for UBFX */
- mArmPC[mInum++] = pc();
-
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-// ----------------------------------------------------------------------------
-// Address Processing...
-// ----------------------------------------------------------------------------
-
-void ArmToMips64Assembler::ADDR_ADD(int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
-// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
-// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
- dataProcessing(opADD64, cc, s, Rd, Rn, Op2);
-}
-
-void ArmToMips64Assembler::ADDR_SUB(int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
-// if(cc != AL){ NOT_IMPLEMENTED(); return;} //Not required
-// if(s != 0) { NOT_IMPLEMENTED(); return;} //Not required
- dataProcessing(opSUB64, cc, s, Rd, Rn, Op2);
-}
-
-void ArmToMips64Assembler::ADDR_LDR(int cc __unused, int Rd,
- int Rn, uint32_t offset) {
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP
- }
- mMips->LD(Rd, Rn, amode.value);
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- mMips->DADDIU(Rn, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP
- }
- mMips->LD(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->DADDU(R_at, Rn, amode.reg);
- mMips->LD(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMips64Assembler::ADDR_STR(int cc __unused, int Rd,
- int Rn, uint32_t offset) {
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP
- }
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- // If we will writeback, then update the index reg, then store.
- // This correctly handles stack-push case.
- mMips->DADDIU(Rn, Rn, amode.value);
- mMips->SD(Rd, Rn, 0);
- } else {
- // No writeback so store offset by value
- mMips->SD(Rd, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- mMips->SD(Rd, Rn, 0);
- mMips->DADDIU(Rn, Rn, amode.value); // post index always writes back
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->DADDU(R_at, Rn, amode.reg);
- mMips->SD(Rd, R_at, 0);
- break;
- }
-}
-
-#if 0
-#pragma mark -
-#pragma mark MIPS Assembler...
-#endif
-
-
-//**************************************************************************
-//**************************************************************************
-//**************************************************************************
-
-
-/* MIPS64 assembler
-** this is a subset of mips64r6, targeted specifically at ARM instruction
-** replacement in the pixelflinger/codeflinger code.
-**
-** This class is extended from MIPSAssembler class and overrides only
-** MIPS64r6 specific stuff.
-*/
-
-MIPS64Assembler::MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent)
- : MIPSAssembler::MIPSAssembler(assembly, NULL), mParent(parent)
-{
-}
-
-MIPS64Assembler::MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent)
- : MIPSAssembler::MIPSAssembler(assembly), mParent(parent)
-{
-}
-
-MIPS64Assembler::~MIPS64Assembler()
-{
-}
-
-void MIPS64Assembler::reset()
-{
- if (mAssembly != NULL) {
- mBase = mPC = (uint32_t *)mAssembly->base();
- } else {
- mPC = mBase = base();
- }
- mBranchTargets.clear();
- mLabels.clear();
- mLabelsInverseMapping.clear();
- mComments.clear();
-}
-
-
-void MIPS64Assembler::disassemble(const char* name __unused)
-{
- char di_buf[140];
-
- bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true;
-
- typedef char dstr[40];
- dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer;
-
- if (mParent->mArmDisassemblyBuffer != NULL) {
- for (int i=0; i<mParent->mArmInstrCount; ++i) {
- string_detab(lines[i]);
- }
- }
-
- size_t count = pc()-base();
- uint32_t* mipsPC = base();
-
- while (count--) {
- ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC);
- if (label >= 0) {
- ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label));
- }
- ssize_t comment = mComments.indexOfKey(mipsPC);
- if (comment >= 0) {
- ALOGW("; %s\n", mComments.valueAt(comment));
- }
- ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt);
- string_detab(di_buf);
- string_pad(di_buf, 30);
- ALOGW("%08lx: %08x %s", uintptr_t(mipsPC), uint32_t(*mipsPC), di_buf);
- mipsPC++;
- }
-}
-
-void MIPS64Assembler::fix_branches()
-{
- // fixup all the branches
- size_t count = mBranchTargets.size();
- while (count--) {
- const branch_target_t& bt = mBranchTargets[count];
- uint32_t* target_pc = mLabels.valueFor(bt.label);
- LOG_ALWAYS_FATAL_IF(!target_pc,
- "error resolving branch targets, target_pc is null");
- int32_t offset = int32_t(target_pc - (bt.pc+1));
- *bt.pc |= offset & 0x00FFFF;
- }
-}
-
-void MIPS64Assembler::DADDU(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (daddu_fn<<FUNC_SHF)
- | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPS64Assembler::DADDIU(int Rt, int Rs, int16_t imm)
-{
- *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-void MIPS64Assembler::DSUBU(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (dsubu_fn<<FUNC_SHF) |
- (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPS64Assembler::DSUBIU(int Rt, int Rs, int16_t imm) // really addiu(d, s, -j)
-{
- *mPC++ = (daddiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16);
-}
-
-void MIPS64Assembler::MUL(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (mul_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) |
- (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPS64Assembler::MUH(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (muh_fn<<RE_SHF) | (sop30_fn<<FUNC_SHF) |
- (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPS64Assembler::CLO(int Rd, int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (17<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF);
-}
-
-void MIPS64Assembler::CLZ(int Rd, int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (16<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (1<<RE_SHF);
-}
-
-void MIPS64Assembler::LD(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (ld_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPS64Assembler::SD(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (sd_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPS64Assembler::LUI(int Rt, int16_t offset)
-{
- *mPC++ = (aui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-
-void MIPS64Assembler::JR(int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jalr_fn << FUNC_SHF);
- MIPS64Assembler::NOP();
-}
-
-}; // namespace android:
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.h b/libpixelflinger/codeflinger/MIPS64Assembler.h
deleted file mode 100644
index b43e5da..0000000
--- a/libpixelflinger/codeflinger/MIPS64Assembler.h
+++ /dev/null
@@ -1,404 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPS64Assembler.h
-**
-** Copyright 2015, 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 ANDROID_MIPS64ASSEMBLER_H
-#define ANDROID_MIPS64ASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "utils/KeyedVector.h"
-#include "utils/Vector.h"
-#include "tinyutils/smartpointer.h"
-
-#include "ARMAssemblerInterface.h"
-#include "MIPSAssembler.h"
-#include "CodeCache.h"
-
-namespace android {
-
-class MIPS64Assembler; // forward reference
-
-// this class mimics ARMAssembler interface
-// intent is to translate each ARM instruction to 1 or more MIPS instr
-// implementation calls MIPS64Assembler class to generate mips code
-class ArmToMips64Assembler : public ARMAssemblerInterface
-{
-public:
- ArmToMips64Assembler(const sp<Assembly>& assembly,
- char *abuf = 0, int linesz = 0, int instr_count = 0);
- ArmToMips64Assembler(void* assembly);
- virtual ~ArmToMips64Assembler();
-
- uint32_t* base() const;
- uint32_t* pc() const;
- void disassemble(const char* name);
-
- virtual void reset();
-
- virtual int generate(const char* name);
- virtual int getCodegenArch();
-
- virtual void prolog();
- virtual void epilog(uint32_t touched);
- virtual void comment(const char* string);
- // for testing purposes
- void fix_branches();
- void set_condition(int mode, int R1, int R2);
-
-
- // -----------------------------------------------------------------------
- // shifters and addressing modes
- // -----------------------------------------------------------------------
-
- // shifters...
- virtual bool isValidImmediate(uint32_t immed);
- virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
-
- virtual uint32_t imm(uint32_t immediate);
- virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
- virtual uint32_t reg_rrx(int Rm);
- virtual uint32_t reg_reg(int Rm, int type, int Rs);
-
- // addressing modes...
- // LDR(B)/STR(B)/PLD
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed12_pre(int32_t immed12, int W=0);
- virtual uint32_t immed12_post(int32_t immed12);
- virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
- virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
-
- // LDRH/LDRSB/LDRSH/STRH
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed8_pre(int32_t immed8, int W=0);
- virtual uint32_t immed8_post(int32_t immed8);
- virtual uint32_t reg_pre(int Rm, int W=0);
- virtual uint32_t reg_post(int Rm);
-
-
-
-
- virtual void dataProcessing(int opcode, int cc, int s,
- int Rd, int Rn,
- uint32_t Op2);
- virtual void MLA(int cc, int s,
- int Rd, int Rm, int Rs, int Rn);
- virtual void MUL(int cc, int s,
- int Rd, int Rm, int Rs);
- virtual void UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
-
- virtual void B(int cc, uint32_t* pc);
- virtual void BL(int cc, uint32_t* pc);
- virtual void BX(int cc, int Rn);
- virtual void label(const char* theLabel);
- virtual void B(int cc, const char* label);
- virtual void BL(int cc, const char* label);
-
- virtual uint32_t* pcForLabel(const char* label);
-
- virtual void LDR (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STR (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STRB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRH (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRSB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRSH(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STRH (int cc, int Rd,
- int Rn, uint32_t offset = 0);
-
- virtual void LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
- virtual void STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
-
- virtual void SWP(int cc, int Rn, int Rd, int Rm);
- virtual void SWPB(int cc, int Rn, int Rd, int Rm);
- virtual void SWI(int cc, uint32_t comment);
-
- virtual void PLD(int Rn, uint32_t offset);
- virtual void CLZ(int cc, int Rd, int Rm);
- virtual void QADD(int cc, int Rd, int Rm, int Rn);
- virtual void QDADD(int cc, int Rd, int Rm, int Rn);
- virtual void QSUB(int cc, int Rd, int Rm, int Rn);
- virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
- virtual void SMUL(int cc, int xy,
- int Rd, int Rm, int Rs);
- virtual void SMULW(int cc, int y,
- int Rd, int Rm, int Rs);
- virtual void SMLA(int cc, int xy,
- int Rd, int Rm, int Rs, int Rn);
- virtual void SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm);
- virtual void SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn);
-
- // byte/half word extract...
- virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
-
- // bit manipulation...
- virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
-
- // Address loading/storing/manipulation
- virtual void ADDR_LDR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0));
- virtual void ADDR_STR(int cc, int Rd, int Rn, uint32_t offset = __immed12_pre(0));
- virtual void ADDR_ADD(int cc, int s, int Rd, int Rn, uint32_t Op2);
- virtual void ADDR_SUB(int cc, int s, int Rd, int Rn, uint32_t Op2);
-
- // this is some crap to share is MIPS64Assembler class for debug
- char * mArmDisassemblyBuffer;
- int mArmLineLength;
- int mArmInstrCount;
-
- int mInum; // current arm instuction number (0..n)
- uint32_t** mArmPC; // array: PC for 1st mips instr of
- // each translated ARM instr
-
-
-private:
- ArmToMips64Assembler(const ArmToMips64Assembler& rhs);
- ArmToMips64Assembler& operator = (const ArmToMips64Assembler& rhs);
-
- void init_conditional_labels(void);
-
- void protectConditionalOperands(int Rd);
-
- // reg__tmp set to MIPS AT, reg 1
- int dataProcAdrModes(int op, int& source, bool sign = false, int reg_tmp = 1);
-
- sp<Assembly> mAssembly;
- MIPS64Assembler* mMips;
-
-
- enum misc_constants_t {
- ARM_MAX_INSTUCTIONS = 512 // based on ASSEMBLY_SCRATCH_SIZE
- };
-
- enum {
- SRC_REG = 0,
- SRC_IMM,
- SRC_ERROR = -1
- };
-
- enum addr_modes {
- // start above the range of legal mips reg #'s (0-31)
- AMODE_REG = 0x20,
- AMODE_IMM, AMODE_REG_IMM, // for data processing
- AMODE_IMM_12_PRE, AMODE_IMM_12_POST, // for load/store
- AMODE_REG_SCALE_PRE, AMODE_IMM_8_PRE,
- AMODE_IMM_8_POST, AMODE_REG_PRE,
- AMODE_UNSUPPORTED
- };
-
- struct addr_mode_t { // address modes for current ARM instruction
- int reg;
- int stype;
- uint32_t value;
- bool writeback; // writeback the adr reg after modification
- } amode;
-
- enum cond_types {
- CMP_COND = 1,
- SBIT_COND
- };
-
- struct cond_mode_t { // conditional-execution info for current ARM instruction
- cond_types type;
- int r1;
- int r2;
- int labelnum;
- char label[100][10];
- } cond;
-};
-
-
-
-
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-
-// This is the basic MIPS64 assembler, which just creates the opcodes in memory.
-// All the more complicated work is done in ArmToMips64Assember above.
-// Inherits MIPSAssembler class, and overrides only MIPS64r6 specific stuff
-
-class MIPS64Assembler : public MIPSAssembler
-{
-public:
- MIPS64Assembler(const sp<Assembly>& assembly, ArmToMips64Assembler *parent);
- MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent);
- virtual ~MIPS64Assembler();
-
- virtual void reset();
- virtual void disassemble(const char* name);
-
- void fix_branches();
-
- // ------------------------------------------------------------------------
- // MIPS64AssemblerInterface...
- // ------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Arithmetic...
-#endif
-
- void DADDU(int Rd, int Rs, int Rt);
- void DADDIU(int Rt, int Rs, int16_t imm);
- void DSUBU(int Rd, int Rs, int Rt);
- void DSUBIU(int Rt, int Rs, int16_t imm);
- virtual void MUL(int Rd, int Rs, int Rt);
- void MUH(int Rd, int Rs, int Rt);
-
-#if 0
-#pragma mark -
-#pragma mark Logical...
-#endif
-
- virtual void CLO(int Rd, int Rs);
- virtual void CLZ(int Rd, int Rs);
-
-#if 0
-#pragma mark -
-#pragma mark Load/store...
-#endif
-
- void LD(int Rt, int Rbase, int16_t offset);
- void SD(int Rt, int Rbase, int16_t offset);
- virtual void LUI(int Rt, int16_t offset);
-
-#if 0
-#pragma mark -
-#pragma mark Branch...
-#endif
-
- void JR(int Rs);
-
-
-protected:
- ArmToMips64Assembler *mParent;
-
- // opcode field of all instructions
- enum opcode_field {
- spec_op, regimm_op, j_op, jal_op, // 0x00 - 0x03
- beq_op, bne_op, pop06_op, pop07_op, // 0x04 - 0x07
- pop10_op, addiu_op, slti_op, sltiu_op, // 0x08 - 0x0b
- andi_op, ori_op, xori_op, aui_op, // 0x0c - 0x0f
- cop0_op, cop1_op, cop2_op, rsrv_opc_0, // 0x10 - 0x13
- rsrv_opc_1, rsrv_opc_2, pop26_op, pop27_op, // 0x14 - 0x17
- pop30_op, daddiu_op, rsrv_opc_3, rsrv_opc_4, // 0x18 - 0x1b
- rsrv_opc_5, daui_op, msa_op, spec3_op, // 0x1c - 0x1f
- lb_op, lh_op, rsrv_opc_6, lw_op, // 0x20 - 0x23
- lbu_op, lhu_op, rsrv_opc_7, lwu_op, // 0x24 - 0x27
- sb_op, sh_op, rsrv_opc_8, sw_op, // 0x28 - 0x2b
- rsrv_opc_9, rsrv_opc_10, rsrv_opc_11, rsrv_opc_12, // 0x2c - 0x2f
- rsrv_opc_13, lwc1_op, bc_op, rsrv_opc_14, // 0x2c - 0x2f
- rsrv_opc_15, ldc1_op, pop66_op, ld_op, // 0x30 - 0x33
- rsrv_opc_16, swc1_op, balc_op, pcrel_op, // 0x34 - 0x37
- rsrv_opc_17, sdc1_op, pop76_op, sd_op // 0x38 - 0x3b
- };
-
-
- // func field for special opcode
- enum func_spec_op {
- sll_fn, rsrv_spec_0, srl_fn, sra_fn,
- sllv_fn, lsa_fn, srlv_fn, srav_fn,
- rsrv_spec_1, jalr_fn, rsrv_spec_2, rsrv_spec_3,
- syscall_fn, break_fn, sdbbp_fn, sync_fn,
- clz_fn, clo_fn, dclz_fn, dclo_fn,
- dsllv_fn, dlsa_fn, dsrlv_fn, dsrav_fn,
- sop30_fn, sop31_fn, sop32_fn, sop33_fn,
- sop34_fn, sop35_fn, sop36_fn, sop37_fn,
- add_fn, addu_fn, sub_fn, subu_fn,
- and_fn, or_fn, xor_fn, nor_fn,
- rsrv_spec_4, rsrv_spec_5, slt_fn, sltu_fn,
- dadd_fn, daddu_fn, dsub_fn, dsubu_fn,
- tge_fn, tgeu_fn, tlt_fn, tltu_fn,
- teq_fn, seleqz_fn, tne_fn, selnez_fn,
- dsll_fn, rsrv_spec_6, dsrl_fn, dsra_fn,
- dsll32_fn, rsrv_spec_7, dsrl32_fn, dsra32_fn
- };
-
- // func field for spec3 opcode
- enum func_spec3_op {
- ext_fn, dextm_fn, dextu_fn, dext_fn,
- ins_fn, dinsm_fn, dinsu_fn, dins_fn,
- cachee_fn = 0x1b, sbe_fn, she_fn, sce_fn, swe_fn,
- bshfl_fn, prefe_fn = 0x23, dbshfl_fn, cache_fn, sc_fn, scd_fn,
- lbue_fn, lhue_fn, lbe_fn = 0x2c, lhe_fn, lle_fn, lwe_fn,
- pref_fn = 0x35, ll_fn, lld_fn, rdhwr_fn = 0x3b
- };
-
- // sa field for spec3 opcodes, with BSHFL function
- enum func_spec3_bshfl {
- bitswap_fn,
- wsbh_fn = 0x02,
- dshd_fn = 0x05,
- seb_fn = 0x10,
- seh_fn = 0x18
- };
-
- // rt field of regimm opcodes.
- enum regimm_fn {
- bltz_fn, bgez_fn,
- dahi_fn = 0x6,
- nal_fn = 0x10, bal_fn, bltzall_fn, bgezall_fn,
- sigrie_fn = 0x17,
- dati_fn = 0x1e, synci_fn
- };
-
- enum muldiv_fn {
- mul_fn = 0x02, muh_fn
- };
-
- enum mips_inst_shifts {
- OP_SHF = 26,
- JTARGET_SHF = 0,
- RS_SHF = 21,
- RT_SHF = 16,
- RD_SHF = 11,
- RE_SHF = 6,
- SA_SHF = RE_SHF, // synonym
- IMM_SHF = 0,
- FUNC_SHF = 0,
-
- // mask values
- MSK_16 = 0xffff,
-
-
- CACHEOP_SHF = 18,
- CACHESEL_SHF = 16,
- };
-};
-
-
-}; // namespace android
-
-#endif //ANDROID_MIPS64ASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
deleted file mode 100644
index 7de8cc1..0000000
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ /dev/null
@@ -1,1955 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPSAssembler.cpp
-**
-** Copyright 2012, 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.
-*/
-
-
-/* MIPS assembler and ARM->MIPS assembly translator
-**
-** The approach is to leave the GGLAssembler and associated files largely
-** un-changed, still utilizing all Arm instruction generation. Via the
-** ArmToMipsAssembler (subclassed from ArmAssemblerInterface) each Arm
-** instruction is translated to one or more Mips instructions as necessary. This
-** is clearly less efficient than a direct implementation within the
-** GGLAssembler, but is far cleaner, more maintainable, and has yielded very
-** significant performance gains on Mips compared to the generic pixel pipeline.
-**
-**
-** GGLAssembler changes
-**
-** - The register allocator has been modified to re-map Arm registers 0-15 to mips
-** registers 2-17. Mips register 0 cannot be used as general-purpose register,
-** and register 1 has traditional uses as a short-term temporary.
-**
-** - Added some early bailouts for OUT_OF_REGISTERS in texturing.cpp and
-** GGLAssembler.cpp, since this is not fatal, and can be retried at lower
-** optimization level.
-**
-**
-** ARMAssembler and ARMAssemblerInterface changes
-**
-** Refactored ARM address-mode static functions (imm(), reg_imm(), imm12_pre(), etc.)
-** to virtual, so they can be overridden in MIPSAssembler. The implementation of these
-** functions on ARM is moved from ARMAssemblerInterface.cpp to ARMAssembler.cpp, and
-** is unchanged from the original. (This required duplicating 2 of these as static
-** functions in ARMAssemblerInterface.cpp so they could be used as static initializers).
-*/
-
-#define LOG_TAG "MIPSAssembler"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include <cutils/properties.h>
-#include <log/log.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "CodeCache.h"
-#include "MIPSAssembler.h"
-#include "mips_disassem.h"
-
-#define __unused __attribute__((__unused__))
-
-// Choose MIPS arch variant following gcc flags
-#if defined(__mips__) && __mips==32 && __mips_isa_rev>=2
-#define mips32r2 1
-#else
-#define mips32r2 0
-#endif
-
-
-#define NOT_IMPLEMENTED() LOG_ALWAYS_FATAL("Arm instruction %s not yet implemented\n", __func__)
-
-
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark ArmToMipsAssembler...
-#endif
-
-ArmToMipsAssembler::ArmToMipsAssembler(const sp<Assembly>& assembly,
- char *abuf, int linesz, int instr_count)
- : ARMAssemblerInterface(),
- mArmDisassemblyBuffer(abuf),
- mArmLineLength(linesz),
- mArmInstrCount(instr_count),
- mInum(0),
- mAssembly(assembly)
-{
- mMips = new MIPSAssembler(assembly, this);
- mArmPC = (uint32_t **) malloc(ARM_MAX_INSTUCTIONS * sizeof(uint32_t *));
- init_conditional_labels();
-}
-
-ArmToMipsAssembler::~ArmToMipsAssembler()
-{
- delete mMips;
- free((void *) mArmPC);
-}
-
-uint32_t* ArmToMipsAssembler::pc() const
-{
- return mMips->pc();
-}
-
-uint32_t* ArmToMipsAssembler::base() const
-{
- return mMips->base();
-}
-
-void ArmToMipsAssembler::reset()
-{
- cond.labelnum = 0;
- mInum = 0;
- mMips->reset();
-}
-
-int ArmToMipsAssembler::getCodegenArch()
-{
- return CODEGEN_ARCH_MIPS;
-}
-
-void ArmToMipsAssembler::comment(const char* string)
-{
- mMips->comment(string);
-}
-
-void ArmToMipsAssembler::label(const char* theLabel)
-{
- mMips->label(theLabel);
-}
-
-void ArmToMipsAssembler::disassemble(const char* name)
-{
- mMips->disassemble(name);
-}
-
-void ArmToMipsAssembler::init_conditional_labels()
-{
- int i;
- for (i=0;i<99; ++i) {
- sprintf(cond.label[i], "cond_%d", i);
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Prolog/Epilog & Generate...
-#endif
-
-void ArmToMipsAssembler::prolog()
-{
- mArmPC[mInum++] = pc(); // save starting PC for this instr
-
- mMips->ADDIU(R_sp, R_sp, -(5 * 4));
- mMips->SW(R_s0, R_sp, 0);
- mMips->SW(R_s1, R_sp, 4);
- mMips->SW(R_s2, R_sp, 8);
- mMips->SW(R_s3, R_sp, 12);
- mMips->SW(R_s4, R_sp, 16);
- mMips->MOVE(R_v0, R_a0); // move context * passed in a0 to v0 (arm r0)
-}
-
-void ArmToMipsAssembler::epilog(uint32_t touched __unused)
-{
- mArmPC[mInum++] = pc(); // save starting PC for this instr
-
- mMips->LW(R_s0, R_sp, 0);
- mMips->LW(R_s1, R_sp, 4);
- mMips->LW(R_s2, R_sp, 8);
- mMips->LW(R_s3, R_sp, 12);
- mMips->LW(R_s4, R_sp, 16);
- mMips->ADDIU(R_sp, R_sp, (5 * 4));
- mMips->JR(R_ra);
-
-}
-
-int ArmToMipsAssembler::generate(const char* name)
-{
- return mMips->generate(name);
-}
-
-uint32_t* ArmToMipsAssembler::pcForLabel(const char* label)
-{
- return mMips->pcForLabel(label);
-}
-
-
-
-//----------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Addressing modes & shifters...
-#endif
-
-
-// do not need this for MIPS, but it is in the Interface (virtual)
-int ArmToMipsAssembler::buildImmediate(
- uint32_t immediate, uint32_t& rot, uint32_t& imm)
-{
- // for MIPS, any 32-bit immediate is OK
- rot = 0;
- imm = immediate;
- return 0;
-}
-
-// shifters...
-
-bool ArmToMipsAssembler::isValidImmediate(uint32_t immediate __unused)
-{
- // for MIPS, any 32-bit immediate is OK
- return true;
-}
-
-uint32_t ArmToMipsAssembler::imm(uint32_t immediate)
-{
- // ALOGW("immediate value %08x at pc %08x\n", immediate, (int)pc());
- amode.value = immediate;
- return AMODE_IMM;
-}
-
-uint32_t ArmToMipsAssembler::reg_imm(int Rm, int type, uint32_t shift)
-{
- amode.reg = Rm;
- amode.stype = type;
- amode.value = shift;
- return AMODE_REG_IMM;
-}
-
-uint32_t ArmToMipsAssembler::reg_rrx(int Rm __unused)
-{
- // reg_rrx mode is not used in the GLLAssember code at this time
- return AMODE_UNSUPPORTED;
-}
-
-uint32_t ArmToMipsAssembler::reg_reg(int Rm __unused, int type __unused,
- int Rs __unused)
-{
- // reg_reg mode is not used in the GLLAssember code at this time
- return AMODE_UNSUPPORTED;
-}
-
-
-// addressing modes...
-// LDR(B)/STR(B)/PLD (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMipsAssembler::immed12_pre(int32_t immed12, int W)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
- "LDR(B)/STR(B)/PLD immediate too big (%08x)",
- immed12);
- amode.value = immed12;
- amode.writeback = W;
- return AMODE_IMM_12_PRE;
-}
-
-uint32_t ArmToMipsAssembler::immed12_post(int32_t immed12)
-{
- LOG_ALWAYS_FATAL_IF(abs(immed12) >= 0x800,
- "LDR(B)/STR(B)/PLD immediate too big (%08x)",
- immed12);
-
- amode.value = immed12;
- return AMODE_IMM_12_POST;
-}
-
-uint32_t ArmToMipsAssembler::reg_scale_pre(int Rm, int type,
- uint32_t shift, int W)
-{
- LOG_ALWAYS_FATAL_IF(W | type | shift, "reg_scale_pre adv modes not yet implemented");
-
- amode.reg = Rm;
- // amode.stype = type; // more advanced modes not used in GGLAssembler yet
- // amode.value = shift;
- // amode.writeback = W;
- return AMODE_REG_SCALE_PRE;
-}
-
-uint32_t ArmToMipsAssembler::reg_scale_post(int Rm __unused, int type __unused,
- uint32_t shift __unused)
-{
- LOG_ALWAYS_FATAL("adr mode reg_scale_post not yet implemented\n");
- return AMODE_UNSUPPORTED;
-}
-
-// LDRH/LDRSB/LDRSH/STRH (immediate and Rm can be negative, which indicate U=0)
-uint32_t ArmToMipsAssembler::immed8_pre(int32_t immed8, int W __unused)
-{
- // uint32_t offset = abs(immed8);
-
- LOG_ALWAYS_FATAL("adr mode immed8_pre not yet implemented\n");
-
- LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
- "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
- immed8);
- return AMODE_IMM_8_PRE;
-}
-
-uint32_t ArmToMipsAssembler::immed8_post(int32_t immed8)
-{
- // uint32_t offset = abs(immed8);
-
- LOG_ALWAYS_FATAL_IF(abs(immed8) >= 0x100,
- "LDRH/LDRSB/LDRSH/STRH immediate too big (%08x)",
- immed8);
- amode.value = immed8;
- return AMODE_IMM_8_POST;
-}
-
-uint32_t ArmToMipsAssembler::reg_pre(int Rm, int W)
-{
- LOG_ALWAYS_FATAL_IF(W, "reg_pre writeback not yet implemented");
- amode.reg = Rm;
- return AMODE_REG_PRE;
-}
-
-uint32_t ArmToMipsAssembler::reg_post(int Rm __unused)
-{
- LOG_ALWAYS_FATAL("adr mode reg_post not yet implemented\n");
- return AMODE_UNSUPPORTED;
-}
-
-
-
-// ----------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Data Processing...
-#endif
-
-// check if the operand registers from a previous CMP or S-bit instruction
-// would be overwritten by this instruction. If so, move the value to a
-// safe register.
-// Note that we cannot tell at _this_ instruction time if a future (conditional)
-// instruction will _also_ use this value (a defect of the simple 1-pass, one-
-// instruction-at-a-time translation). Therefore we must be conservative and
-// save the value before it is overwritten. This costs an extra MOVE instr.
-
-void ArmToMipsAssembler::protectConditionalOperands(int Rd)
-{
- if (Rd == cond.r1) {
- mMips->MOVE(R_cmp, cond.r1);
- cond.r1 = R_cmp;
- }
- if (cond.type == CMP_COND && Rd == cond.r2) {
- mMips->MOVE(R_cmp2, cond.r2);
- cond.r2 = R_cmp2;
- }
-}
-
-
-// interprets the addressing mode, and generates the common code
-// used by the majority of data-processing ops. Many MIPS instructions
-// have a register-based form and a different immediate form. See
-// opAND below for an example. (this could be inlined)
-//
-// this works with the imm(), reg_imm() methods above, which are directly
-// called by the GLLAssembler.
-// note: _signed parameter defaults to false (un-signed)
-// note: tmpReg parameter defaults to 1, MIPS register AT
-int ArmToMipsAssembler::dataProcAdrModes(int op, int& source, bool _signed, int tmpReg)
-{
- if (op < AMODE_REG) {
- source = op;
- return SRC_REG;
- } else if (op == AMODE_IMM) {
- if ((!_signed && amode.value > 0xffff)
- || (_signed && ((int)amode.value < -32768 || (int)amode.value > 32767) )) {
- mMips->LUI(tmpReg, (amode.value >> 16));
- if (amode.value & 0x0000ffff) {
- mMips->ORI(tmpReg, tmpReg, (amode.value & 0x0000ffff));
- }
- source = tmpReg;
- return SRC_REG;
- } else {
- source = amode.value;
- return SRC_IMM;
- }
- } else if (op == AMODE_REG_IMM) {
- switch (amode.stype) {
- case LSL: mMips->SLL(tmpReg, amode.reg, amode.value); break;
- case LSR: mMips->SRL(tmpReg, amode.reg, amode.value); break;
- case ASR: mMips->SRA(tmpReg, amode.reg, amode.value); break;
- case ROR: if (mips32r2) {
- mMips->ROTR(tmpReg, amode.reg, amode.value);
- } else {
- mMips->RORIsyn(tmpReg, amode.reg, amode.value);
- }
- break;
- }
- source = tmpReg;
- return SRC_REG;
- } else { // adr mode RRX is not used in GGL Assembler at this time
- // we are screwed, this should be exception, assert-fail or something
- LOG_ALWAYS_FATAL("adr mode reg_rrx not yet implemented\n");
- return SRC_ERROR;
- }
-}
-
-
-void ArmToMipsAssembler::dataProcessing(int opcode, int cc,
- int s, int Rd, int Rn, uint32_t Op2)
-{
- int src; // src is modified by dataProcAdrModes() - passed as int&
-
-
- if (cc != AL) {
- protectConditionalOperands(Rd);
- // the branch tests register(s) set by prev CMP or instr with 'S' bit set
- // inverse the condition to jump past this conditional instruction
- ArmToMipsAssembler::B(cc^1, cond.label[++cond.labelnum]);
- } else {
- mArmPC[mInum++] = pc(); // save starting PC for this instr
- }
-
- switch (opcode) {
- case opAND:
- if (dataProcAdrModes(Op2, src) == SRC_REG) {
- mMips->AND(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->ANDI(Rd, Rn, src);
- }
- break;
-
- case opADD:
- // set "signed" to true for adr modes
- if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
- mMips->ADDU(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->ADDIU(Rd, Rn, src);
- }
- break;
-
- case opSUB:
- // set "signed" to true for adr modes
- if (dataProcAdrModes(Op2, src, true) == SRC_REG) {
- mMips->SUBU(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->SUBIU(Rd, Rn, src);
- }
- break;
-
- case opEOR:
- if (dataProcAdrModes(Op2, src) == SRC_REG) {
- mMips->XOR(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->XORI(Rd, Rn, src);
- }
- break;
-
- case opORR:
- if (dataProcAdrModes(Op2, src) == SRC_REG) {
- mMips->OR(Rd, Rn, src);
- } else { // adr mode was SRC_IMM
- mMips->ORI(Rd, Rn, src);
- }
- break;
-
- case opBIC:
- if (dataProcAdrModes(Op2, src) == SRC_IMM) {
- // if we are 16-bit imnmediate, load to AT reg
- mMips->ORI(R_at, 0, src);
- src = R_at;
- }
- mMips->NOT(R_at, src);
- mMips->AND(Rd, Rn, R_at);
- break;
-
- case opRSB:
- if (dataProcAdrModes(Op2, src) == SRC_IMM) {
- // if we are 16-bit imnmediate, load to AT reg
- mMips->ORI(R_at, 0, src);
- src = R_at;
- }
- mMips->SUBU(Rd, src, Rn); // subu with the parameters reversed
- break;
-
- case opMOV:
- if (Op2 < AMODE_REG) { // op2 is reg # in this case
- mMips->MOVE(Rd, Op2);
- } else if (Op2 == AMODE_IMM) {
- if (amode.value > 0xffff) {
- mMips->LUI(Rd, (amode.value >> 16));
- if (amode.value & 0x0000ffff) {
- mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
- }
- } else {
- mMips->ORI(Rd, 0, amode.value);
- }
- } else if (Op2 == AMODE_REG_IMM) {
- switch (amode.stype) {
- case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
- case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
- case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
- case ROR: if (mips32r2) {
- mMips->ROTR(Rd, amode.reg, amode.value);
- } else {
- mMips->RORIsyn(Rd, amode.reg, amode.value);
- }
- break;
- }
- }
- else {
- // adr mode RRX is not used in GGL Assembler at this time
- mMips->UNIMPL();
- }
- break;
-
- case opMVN: // this is a 1's complement: NOT
- if (Op2 < AMODE_REG) { // op2 is reg # in this case
- mMips->NOR(Rd, Op2, 0); // NOT is NOR with 0
- break;
- } else if (Op2 == AMODE_IMM) {
- if (amode.value > 0xffff) {
- mMips->LUI(Rd, (amode.value >> 16));
- if (amode.value & 0x0000ffff) {
- mMips->ORI(Rd, Rd, (amode.value & 0x0000ffff));
- }
- } else {
- mMips->ORI(Rd, 0, amode.value);
- }
- } else if (Op2 == AMODE_REG_IMM) {
- switch (amode.stype) {
- case LSL: mMips->SLL(Rd, amode.reg, amode.value); break;
- case LSR: mMips->SRL(Rd, amode.reg, amode.value); break;
- case ASR: mMips->SRA(Rd, amode.reg, amode.value); break;
- case ROR: if (mips32r2) {
- mMips->ROTR(Rd, amode.reg, amode.value);
- } else {
- mMips->RORIsyn(Rd, amode.reg, amode.value);
- }
- break;
- }
- }
- else {
- // adr mode RRX is not used in GGL Assembler at this time
- mMips->UNIMPL();
- }
- mMips->NOR(Rd, Rd, 0); // NOT is NOR with 0
- break;
-
- case opCMP:
- // Either operand of a CMP instr could get overwritten by a subsequent
- // conditional instruction, which is ok, _UNLESS_ there is a _second_
- // conditional instruction. Under MIPS, this requires doing the comparison
- // again (SLT), and the original operands must be available. (and this
- // pattern of multiple conditional instructions from same CMP _is_ used
- // in GGL-Assembler)
- //
- // For now, if a conditional instr overwrites the operands, we will
- // move them to dedicated temp regs. This is ugly, and inefficient,
- // and should be optimized.
- //
- // WARNING: making an _Assumption_ that CMP operand regs will NOT be
- // trashed by intervening NON-conditional instructions. In the general
- // case this is legal, but it is NOT currently done in GGL-Assembler.
-
- cond.type = CMP_COND;
- cond.r1 = Rn;
- if (dataProcAdrModes(Op2, src, false, R_cmp2) == SRC_REG) {
- cond.r2 = src;
- } else { // adr mode was SRC_IMM
- mMips->ORI(R_cmp2, R_zero, src);
- cond.r2 = R_cmp2;
- }
-
- break;
-
-
- case opTST:
- case opTEQ:
- case opCMN:
- case opADC:
- case opSBC:
- case opRSC:
- mMips->UNIMPL(); // currently unused in GGL Assembler code
- break;
- }
-
- if (cc != AL) {
- mMips->label(cond.label[cond.labelnum]);
- }
- if (s && opcode != opCMP) {
- cond.type = SBIT_COND;
- cond.r1 = Rd;
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Multiply...
-#endif
-
-// multiply, accumulate
-void ArmToMipsAssembler::MLA(int cc __unused, int s,
- int Rd, int Rm, int Rs, int Rn) {
-
- mArmPC[mInum++] = pc(); // save starting PC for this instr
-
- mMips->MUL(R_at, Rm, Rs);
- mMips->ADDU(Rd, R_at, Rn);
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = Rd;
- }
-}
-
-void ArmToMipsAssembler::MUL(int cc __unused, int s,
- int Rd, int Rm, int Rs) {
- mArmPC[mInum++] = pc();
- mMips->MUL(Rd, Rm, Rs);
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = Rd;
- }
-}
-
-void ArmToMipsAssembler::UMULL(int cc __unused, int s,
- int RdLo, int RdHi, int Rm, int Rs) {
- mArmPC[mInum++] = pc();
- mMips->MULT(Rm, Rs);
- mMips->MFHI(RdHi);
- mMips->MFLO(RdLo);
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
- }
-}
-
-void ArmToMipsAssembler::UMUAL(int cc __unused, int s,
- int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "UMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- // *mPC++ = (cc<<28) | (1<<23) | (1<<21) | (s<<20) |
- // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on UMULL must be on 64-bit result\n");
- }
-}
-
-void ArmToMipsAssembler::SMULL(int cc __unused, int s,
- int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "SMULL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (s<<20) |
- // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on SMULL must be on 64-bit result\n");
- }
-}
-void ArmToMipsAssembler::SMUAL(int cc __unused, int s,
- int RdLo __unused, int RdHi, int Rm __unused, int Rs __unused) {
- LOG_FATAL_IF(RdLo==Rm || RdHi==Rm || RdLo==RdHi,
- "SMUAL(r%u,r%u,r%u,r%u)", RdLo,RdHi,Rm,Rs);
- // *mPC++ = (cc<<28) | (1<<23) | (1<<22) | (1<<21) | (s<<20) |
- // (RdHi<<16) | (RdLo<<12) | (Rs<<8) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
- if (s) {
- cond.type = SBIT_COND;
- cond.r1 = RdHi; // BUG...
- LOG_ALWAYS_FATAL("Condition on SMUAL must be on 64-bit result\n");
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Branches...
-#endif
-
-// branches...
-
-void ArmToMipsAssembler::B(int cc, const char* label)
-{
- mArmPC[mInum++] = pc();
- if (cond.type == SBIT_COND) { cond.r2 = R_zero; }
-
- switch(cc) {
- case EQ: mMips->BEQ(cond.r1, cond.r2, label); break;
- case NE: mMips->BNE(cond.r1, cond.r2, label); break;
- case HS: mMips->BGEU(cond.r1, cond.r2, label); break;
- case LO: mMips->BLTU(cond.r1, cond.r2, label); break;
- case MI: mMips->BLT(cond.r1, cond.r2, label); break;
- case PL: mMips->BGE(cond.r1, cond.r2, label); break;
-
- case HI: mMips->BGTU(cond.r1, cond.r2, label); break;
- case LS: mMips->BLEU(cond.r1, cond.r2, label); break;
- case GE: mMips->BGE(cond.r1, cond.r2, label); break;
- case LT: mMips->BLT(cond.r1, cond.r2, label); break;
- case GT: mMips->BGT(cond.r1, cond.r2, label); break;
- case LE: mMips->BLE(cond.r1, cond.r2, label); break;
- case AL: mMips->B(label); break;
- case NV: /* B Never - no instruction */ break;
-
- case VS:
- case VC:
- default:
- LOG_ALWAYS_FATAL("Unsupported cc: %02x\n", cc);
- break;
- }
-}
-
-void ArmToMipsAssembler::BL(int cc __unused, const char* label __unused)
-{
- LOG_ALWAYS_FATAL("branch-and-link not supported yet\n");
- mArmPC[mInum++] = pc();
-}
-
-// no use for Branches with integer PC, but they're in the Interface class ....
-void ArmToMipsAssembler::B(int cc __unused, uint32_t* to_pc __unused)
-{
- LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
- mArmPC[mInum++] = pc();
-}
-
-void ArmToMipsAssembler::BL(int cc __unused, uint32_t* to_pc __unused)
-{
- LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
- mArmPC[mInum++] = pc();
-}
-
-void ArmToMipsAssembler::BX(int cc __unused, int Rn __unused)
-{
- LOG_ALWAYS_FATAL("branch to absolute PC not supported, use Label\n");
- mArmPC[mInum++] = pc();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Data Transfer...
-#endif
-
-// data transfer...
-void ArmToMipsAssembler::LDR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert LDR via Arm SP to LW via Mips SP
- }
- mMips->LW(Rd, Rn, amode.value);
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- mMips->ADDIU(Rn, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert STR thru Arm SP to STR thru Mips SP
- }
- mMips->LW(Rd, Rn, 0);
- mMips->ADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->ADDU(R_at, Rn, amode.reg);
- mMips->LW(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMipsAssembler::LDRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- mMips->LBU(Rd, Rn, amode.value);
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- mMips->ADDIU(Rn, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- mMips->LBU(Rd, Rn, 0);
- mMips->ADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->ADDU(R_at, Rn, amode.reg);
- mMips->LBU(Rd, R_at, 0);
- break;
- }
-
-}
-
-void ArmToMipsAssembler::STR(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- if (Rn == ARMAssemblerInterface::SP) {
- Rn = R_sp; // convert STR thru Arm SP to SW thru Mips SP
- }
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- // If we will writeback, then update the index reg, then store.
- // This correctly handles stack-push case.
- mMips->ADDIU(Rn, Rn, amode.value);
- mMips->SW(Rd, Rn, 0);
- } else {
- // No writeback so store offset by value
- mMips->SW(Rd, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- mMips->SW(Rd, Rn, 0);
- mMips->ADDIU(Rn, Rn, amode.value); // post index always writes back
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->ADDU(R_at, Rn, amode.reg);
- mMips->SW(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMipsAssembler::STRB(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed12_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- amode.writeback = 0;
- // fall thru to next case ....
- case AMODE_IMM_12_PRE:
- mMips->SB(Rd, Rn, amode.value);
- if (amode.writeback) { // OPTIONAL writeback on pre-index mode
- mMips->ADDIU(Rn, Rn, amode.value);
- }
- break;
- case AMODE_IMM_12_POST:
- mMips->SB(Rd, Rn, 0);
- mMips->ADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_SCALE_PRE:
- // we only support simple base + index, no advanced modes for this one yet
- mMips->ADDU(R_at, Rn, amode.reg);
- mMips->SB(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMipsAssembler::LDRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed8_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- // fall thru to next case ....
- case AMODE_IMM_8_PRE: // no support yet for writeback
- mMips->LHU(Rd, Rn, amode.value);
- break;
- case AMODE_IMM_8_POST:
- mMips->LHU(Rd, Rn, 0);
- mMips->ADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_PRE:
- // we only support simple base +/- index
- if (amode.reg >= 0) {
- mMips->ADDU(R_at, Rn, amode.reg);
- } else {
- mMips->SUBU(R_at, Rn, abs(amode.reg));
- }
- mMips->LHU(Rd, R_at, 0);
- break;
- }
-}
-
-void ArmToMipsAssembler::LDRSB(int cc __unused, int Rd __unused,
- int Rn __unused, uint32_t offset __unused)
-{
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::LDRSH(int cc __unused, int Rd __unused,
- int Rn __unused, uint32_t offset __unused)
-{
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::STRH(int cc __unused, int Rd, int Rn, uint32_t offset)
-{
- mArmPC[mInum++] = pc();
- // work-around for ARM default address mode of immed8_pre(0)
- if (offset > AMODE_UNSUPPORTED) offset = 0;
- switch (offset) {
- case 0:
- amode.value = 0;
- // fall thru to next case ....
- case AMODE_IMM_8_PRE: // no support yet for writeback
- mMips->SH(Rd, Rn, amode.value);
- break;
- case AMODE_IMM_8_POST:
- mMips->SH(Rd, Rn, 0);
- mMips->ADDIU(Rn, Rn, amode.value);
- break;
- case AMODE_REG_PRE:
- // we only support simple base +/- index
- if (amode.reg >= 0) {
- mMips->ADDU(R_at, Rn, amode.reg);
- } else {
- mMips->SUBU(R_at, Rn, abs(amode.reg));
- }
- mMips->SH(Rd, R_at, 0);
- break;
- }
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Block Data Transfer...
-#endif
-
-// block data transfer...
-void ArmToMipsAssembler::LDM(int cc __unused, int dir __unused,
- int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{ // ED FD EA FA IB IA DB DA
- // const uint8_t P[8] = { 1, 0, 1, 0, 1, 0, 1, 0 };
- // const uint8_t U[8] = { 1, 1, 0, 0, 1, 1, 0, 0 };
- // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
- // (uint32_t(U[dir])<<23) | (1<<20) | (W<<21) | (Rn<<16) | reg_list;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::STM(int cc __unused, int dir __unused,
- int Rn __unused, int W __unused, uint32_t reg_list __unused)
-{ // FA EA FD ED IB IA DB DA
- // const uint8_t P[8] = { 0, 1, 0, 1, 1, 0, 1, 0 };
- // const uint8_t U[8] = { 0, 0, 1, 1, 1, 1, 0, 0 };
- // *mPC++ = (cc<<28) | (4<<25) | (uint32_t(P[dir])<<24) |
- // (uint32_t(U[dir])<<23) | (0<<20) | (W<<21) | (Rn<<16) | reg_list;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Special...
-#endif
-
-// special...
-void ArmToMipsAssembler::SWP(int cc __unused, int Rn __unused,
- int Rd __unused, int Rm __unused) {
- // *mPC++ = (cc<<28) | (2<<23) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::SWPB(int cc __unused, int Rn __unused,
- int Rd __unused, int Rm __unused) {
- // *mPC++ = (cc<<28) | (2<<23) | (1<<22) | (Rn<<16) | (Rd << 12) | 0x90 | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::SWI(int cc __unused, uint32_t comment __unused) {
- // *mPC++ = (cc<<28) | (0xF<<24) | comment;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark DSP instructions...
-#endif
-
-// DSP instructions...
-void ArmToMipsAssembler::PLD(int Rn __unused, uint32_t offset) {
- LOG_ALWAYS_FATAL_IF(!((offset&(1<<24)) && !(offset&(1<<21))),
- "PLD only P=1, W=0");
- // *mPC++ = 0xF550F000 | (Rn<<16) | offset;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::CLZ(int cc __unused, int Rd, int Rm)
-{
- mArmPC[mInum++] = pc();
- mMips->CLZ(Rd, Rm);
-}
-
-void ArmToMipsAssembler::QADD(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1000050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::QDADD(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1400050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::QSUB(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1200050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::QDSUB(int cc __unused, int Rd __unused,
- int Rm __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1600050 | (Rn<<16) | (Rd<<12) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-// 16 x 16 signed multiply (like SMLAxx without the accumulate)
-void ArmToMipsAssembler::SMUL(int cc __unused, int xy,
- int Rd, int Rm, int Rs)
-{
- mArmPC[mInum++] = pc();
-
- // the 16 bits may be in the top or bottom half of 32-bit source reg,
- // as defined by the codes BB, BT, TB, TT (compressed param xy)
- // where x corresponds to Rm and y to Rs
-
- // select half-reg for Rm
- if (xy & xyTB) {
- // use top 16-bits
- mMips->SRA(R_at, Rm, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- if (mips32r2) {
- mMips->SEH(R_at, Rm);
- } else {
- mMips->SLL(R_at, Rm, 16);
- mMips->SRA(R_at, R_at, 16);
- }
- }
- // select half-reg for Rs
- if (xy & xyBT) {
- // use top 16-bits
- mMips->SRA(R_at2, Rs, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- if (mips32r2) {
- mMips->SEH(R_at2, Rs);
- } else {
- mMips->SLL(R_at2, Rs, 16);
- mMips->SRA(R_at2, R_at2, 16);
- }
- }
- mMips->MUL(Rd, R_at, R_at2);
-}
-
-// signed 32b x 16b multiple, save top 32-bits of 48-bit result
-void ArmToMipsAssembler::SMULW(int cc __unused, int y,
- int Rd, int Rm, int Rs)
-{
- mArmPC[mInum++] = pc();
-
- // the selector yT or yB refers to reg Rs
- if (y & yT) {
- // zero the bottom 16-bits, with 2 shifts, it can affect result
- mMips->SRL(R_at, Rs, 16);
- mMips->SLL(R_at, R_at, 16);
-
- } else {
- // move low 16-bit half, to high half
- mMips->SLL(R_at, Rs, 16);
- }
- mMips->MULT(Rm, R_at);
- mMips->MFHI(Rd);
-}
-
-// 16 x 16 signed multiply, accumulate: Rd = Rm{16} * Rs{16} + Rn
-void ArmToMipsAssembler::SMLA(int cc __unused, int xy,
- int Rd, int Rm, int Rs, int Rn)
-{
- mArmPC[mInum++] = pc();
-
- // the 16 bits may be in the top or bottom half of 32-bit source reg,
- // as defined by the codes BB, BT, TB, TT (compressed param xy)
- // where x corresponds to Rm and y to Rs
-
- // select half-reg for Rm
- if (xy & xyTB) {
- // use top 16-bits
- mMips->SRA(R_at, Rm, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- if (mips32r2) {
- mMips->SEH(R_at, Rm);
- } else {
- mMips->SLL(R_at, Rm, 16);
- mMips->SRA(R_at, R_at, 16);
- }
- }
- // select half-reg for Rs
- if (xy & xyBT) {
- // use top 16-bits
- mMips->SRA(R_at2, Rs, 16);
- } else {
- // use bottom 16, but sign-extend to 32
- if (mips32r2) {
- mMips->SEH(R_at2, Rs);
- } else {
- mMips->SLL(R_at2, Rs, 16);
- mMips->SRA(R_at2, R_at2, 16);
- }
- }
-
- mMips->MUL(R_at, R_at, R_at2);
- mMips->ADDU(Rd, R_at, Rn);
-}
-
-void ArmToMipsAssembler::SMLAL(int cc __unused, int xy __unused,
- int RdHi __unused, int RdLo __unused,
- int Rs __unused, int Rm __unused)
-{
- // *mPC++ = (cc<<28) | 0x1400080 | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (xy<<4) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-void ArmToMipsAssembler::SMLAW(int cc __unused, int y __unused,
- int Rd __unused, int Rm __unused,
- int Rs __unused, int Rn __unused)
-{
- // *mPC++ = (cc<<28) | 0x1200080 | (Rd<<16) | (Rn<<12) | (Rs<<8) | (y<<4) | Rm;
- mArmPC[mInum++] = pc();
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-// used by ARMv6 version of GGLAssembler::filter32
-void ArmToMipsAssembler::UXTB16(int cc __unused, int Rd, int Rm, int rotate)
-{
- mArmPC[mInum++] = pc();
-
- //Rd[31:16] := ZeroExtend((Rm ROR (8 * sh))[23:16]),
- //Rd[15:0] := ZeroExtend((Rm ROR (8 * sh))[7:0]). sh 0-3.
-
- mMips->ROTR(Rm, Rm, rotate * 8);
- mMips->AND(Rd, Rm, 0x00FF00FF);
-}
-
-void ArmToMipsAssembler::UBFX(int cc __unused, int Rd __unused,
- int Rn __unused, int lsb __unused,
- int width __unused)
-{
- /* Placeholder for UBFX */
- mArmPC[mInum++] = pc();
-
- mMips->NOP2();
- NOT_IMPLEMENTED();
-}
-
-
-
-
-
-#if 0
-#pragma mark -
-#pragma mark MIPS Assembler...
-#endif
-
-
-//**************************************************************************
-//**************************************************************************
-//**************************************************************************
-
-
-/* mips assembler
-** this is a subset of mips32r2, targeted specifically at ARM instruction
-** replacement in the pixelflinger/codeflinger code.
-**
-** To that end, there is no need for floating point, or priviledged
-** instructions. This all runs in user space, no float.
-**
-** The syntax makes no attempt to be as complete as the assember, with
-** synthetic instructions, and automatic recognition of immedate operands
-** (use the immediate form of the instruction), etc.
-**
-** We start with mips32r1, and may add r2 and dsp extensions if cpu
-** supports. Decision will be made at compile time, based on gcc
-** options. (makes sense since android will be built for a a specific
-** device)
-*/
-
-MIPSAssembler::MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent)
- : mParent(parent),
- mAssembly(assembly)
-{
- mBase = mPC = (uint32_t *)assembly->base();
- mDuration = ggl_system_time();
-}
-
-MIPSAssembler::MIPSAssembler(void* assembly)
- : mParent(NULL), mAssembly(NULL)
-{
- mBase = mPC = (uint32_t *)assembly;
-}
-
-MIPSAssembler::~MIPSAssembler()
-{
-}
-
-
-uint32_t* MIPSAssembler::pc() const
-{
- return mPC;
-}
-
-uint32_t* MIPSAssembler::base() const
-{
- return mBase;
-}
-
-void MIPSAssembler::reset()
-{
- mBase = mPC = (uint32_t *)mAssembly->base();
- mBranchTargets.clear();
- mLabels.clear();
- mLabelsInverseMapping.clear();
- mComments.clear();
-}
-
-
-// convert tabs to spaces, and remove any newline
-// works with strings of limited size (makes a temp copy)
-#define TABSTOP 8
-void MIPSAssembler::string_detab(char *s)
-{
- char *os = s;
- char temp[100];
- char *t = temp;
- int len = 99;
- int i = TABSTOP;
-
- while (*s && len-- > 0) {
- if (*s == '\n') { s++; continue; }
- if (*s == '\t') {
- s++;
- for ( ; i>0; i--) {*t++ = ' '; len--; }
- } else {
- *t++ = *s++;
- }
- if (i <= 0) i = TABSTOP;
- i--;
- }
- *t = '\0';
- strcpy(os, temp);
-}
-
-void MIPSAssembler::string_pad(char *s, int padded_len)
-{
- int len = strlen(s);
- s += len;
- for (int i = padded_len - len; i > 0; --i) {
- *s++ = ' ';
- }
- *s = '\0';
-}
-
-// ----------------------------------------------------------------------------
-
-void MIPSAssembler::disassemble(const char* name)
-{
- char di_buf[140];
-
- if (name) {
- ALOGW("%s:\n", name);
- }
-
- bool arm_disasm_fmt = (mParent->mArmDisassemblyBuffer == NULL) ? false : true;
-
- typedef char dstr[40];
- dstr *lines = (dstr *)mParent->mArmDisassemblyBuffer;
-
- if (mParent->mArmDisassemblyBuffer != NULL) {
- for (int i=0; i<mParent->mArmInstrCount; ++i) {
- string_detab(lines[i]);
- }
- }
-
- size_t count = pc()-base();
- uint32_t* mipsPC = base();
- while (count--) {
- ssize_t label = mLabelsInverseMapping.indexOfKey(mipsPC);
- if (label >= 0) {
- ALOGW("%s:\n", mLabelsInverseMapping.valueAt(label));
- }
- ssize_t comment = mComments.indexOfKey(mipsPC);
- if (comment >= 0) {
- ALOGW("; %s\n", mComments.valueAt(comment));
- }
- // ALOGW("%08x: %08x ", int(i), int(i[0]));
- ::mips_disassem(mipsPC, di_buf, arm_disasm_fmt);
- string_detab(di_buf);
- string_pad(di_buf, 30);
- ALOGW("0x%p: %08x %s", mipsPC, uint32_t(*mipsPC), di_buf);
- mipsPC++;
- }
-}
-
-void MIPSAssembler::comment(const char* string)
-{
- mComments.add(pc(), string);
-}
-
-void MIPSAssembler::label(const char* theLabel)
-{
- mLabels.add(theLabel, pc());
- mLabelsInverseMapping.add(pc(), theLabel);
-}
-
-
-void MIPSAssembler::prolog()
-{
- // empty - done in ArmToMipsAssembler
-}
-
-void MIPSAssembler::epilog(uint32_t touched __unused)
-{
- // empty - done in ArmToMipsAssembler
-}
-
-int MIPSAssembler::generate(const char* name)
-{
- // fixup all the branches
- size_t count = mBranchTargets.size();
- while (count--) {
- const branch_target_t& bt = mBranchTargets[count];
- uint32_t* target_pc = mLabels.valueFor(bt.label);
- LOG_ALWAYS_FATAL_IF(!target_pc,
- "error resolving branch targets, target_pc is null");
- int32_t offset = int32_t(target_pc - (bt.pc+1));
- *bt.pc |= offset & 0x00FFFF;
- }
-
- mAssembly->resize( int(pc()-base())*4 );
-
- // the instruction & data caches are flushed by CodeCache
- const int64_t duration = ggl_system_time() - mDuration;
- const char * const format = "generated %s (%d ins) at [%p:%p] in %" PRId64 " ns\n";
- ALOGI(format, name, int(pc()-base()), base(), pc(), duration);
-
- char value[PROPERTY_VALUE_MAX];
- value[0] = '\0';
-
- property_get("debug.pf.disasm", value, "0");
-
- if (atoi(value) != 0) {
- disassemble(name);
- }
-
- return OK;
-}
-
-uint32_t* MIPSAssembler::pcForLabel(const char* label)
-{
- return mLabels.valueFor(label);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Arithmetic...
-#endif
-
-void MIPSAssembler::ADDU(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (addu_fn<<FUNC_SHF)
- | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-// MD00086 pdf says this is: ADDIU rt, rs, imm -- they do not use Rd
-void MIPSAssembler::ADDIU(int Rt, int Rs, int16_t imm)
-{
- *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-void MIPSAssembler::SUBU(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (subu_fn<<FUNC_SHF) |
- (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-
-void MIPSAssembler::SUBIU(int Rt, int Rs, int16_t imm) // really addiu(d, s, -j)
-{
- *mPC++ = (addiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | ((-imm) & MSK_16);
-}
-
-
-void MIPSAssembler::NEGU(int Rd, int Rs) // really subu(d, zero, s)
-{
- MIPSAssembler::SUBU(Rd, 0, Rs);
-}
-
-void MIPSAssembler::MUL(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec2_op<<OP_SHF) | (mul_fn<<FUNC_SHF) |
- (Rs<<RS_SHF) | (Rt<<RT_SHF) | (Rd<<RD_SHF) ;
-}
-
-void MIPSAssembler::MULT(int Rs, int Rt) // dest is hi,lo
-{
- *mPC++ = (spec_op<<OP_SHF) | (mult_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MULTU(int Rs, int Rt) // dest is hi,lo
-{
- *mPC++ = (spec_op<<OP_SHF) | (multu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MADD(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt
-{
- *mPC++ = (spec2_op<<OP_SHF) | (madd_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MADDU(int Rs, int Rt) // hi,lo = hi,lo + Rs * Rt
-{
- *mPC++ = (spec2_op<<OP_SHF) | (maddu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-
-void MIPSAssembler::MSUB(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt
-{
- *mPC++ = (spec2_op<<OP_SHF) | (msub_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MSUBU(int Rs, int Rt) // hi,lo = hi,lo - Rs * Rt
-{
- *mPC++ = (spec2_op<<OP_SHF) | (msubu_fn<<FUNC_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF);
-}
-
-
-void MIPSAssembler::SEB(int Rd, int Rt) // sign-extend byte (mips32r2)
-{
- *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seb_fn << SA_SHF) |
- (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPSAssembler::SEH(int Rd, int Rt) // sign-extend half-word (mips32r2)
-{
- *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (seh_fn << SA_SHF) |
- (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Comparisons...
-#endif
-
-void MIPSAssembler::SLT(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (slt_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SLTI(int Rt, int Rs, int16_t imm)
-{
- *mPC++ = (slti_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-void MIPSAssembler::SLTU(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (sltu_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SLTIU(int Rt, int Rs, int16_t imm)
-{
- *mPC++ = (sltiu_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Logical...
-#endif
-
-void MIPSAssembler::AND(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (and_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::ANDI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate
-{
- *mPC++ = (andi_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-
-void MIPSAssembler::OR(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::ORI(int Rt, int Rs, uint16_t imm)
-{
- *mPC++ = (ori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-void MIPSAssembler::NOR(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (nor_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::NOT(int Rd, int Rs)
-{
- MIPSAssembler::NOR(Rd, Rs, 0); // NOT(d,s) = NOR(d,s,zero)
-}
-
-void MIPSAssembler::XOR(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (xor_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::XORI(int Rt, int Rs, uint16_t imm) // todo: support larger immediate
-{
- *mPC++ = (xori_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | (imm & MSK_16);
-}
-
-void MIPSAssembler::SLL(int Rd, int Rt, int shft)
-{
- *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::SLLV(int Rd, int Rt, int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (sllv_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SRL(int Rd, int Rt, int shft)
-{
- *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::SRLV(int Rd, int Rt, int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::SRA(int Rd, int Rt, int shft)
-{
- *mPC++ = (spec_op<<OP_SHF) | (sra_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::SRAV(int Rd, int Rt, int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (srav_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::ROTR(int Rd, int Rt, int shft) // mips32r2
-{
- // note weird encoding (SRL + 1)
- *mPC++ = (spec_op<<OP_SHF) | (srl_fn<<FUNC_SHF) |
- (1<<RS_SHF) | (Rd<<RD_SHF) | (Rt<<RT_SHF) | (shft<<RE_SHF);
-}
-
-void MIPSAssembler::ROTRV(int Rd, int Rt, int Rs) // mips32r2
-{
- // note weird encoding (SRLV + 1)
- *mPC++ = (spec_op<<OP_SHF) | (srlv_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF) | (1<<RE_SHF);
-}
-
-// uses at2 register (mapped to some appropriate mips reg)
-void MIPSAssembler::RORsyn(int Rd, int Rt, int Rs)
-{
- // synthetic: d = t rotated by s
- MIPSAssembler::NEGU(R_at2, Rs);
- MIPSAssembler::SLLV(R_at2, Rt, R_at2);
- MIPSAssembler::SRLV(Rd, Rt, Rs);
- MIPSAssembler::OR(Rd, Rd, R_at2);
-}
-
-// immediate version - uses at2 register (mapped to some appropriate mips reg)
-void MIPSAssembler::RORIsyn(int Rd, int Rt, int rot)
-{
- // synthetic: d = t rotated by immed rot
- // d = s >> rot | s << (32-rot)
- MIPSAssembler::SLL(R_at2, Rt, 32-rot);
- MIPSAssembler::SRL(Rd, Rt, rot);
- MIPSAssembler::OR(Rd, Rd, R_at2);
-}
-
-void MIPSAssembler::CLO(int Rd, int Rs)
-{
- // Rt field must have same gpr # as Rd
- *mPC++ = (spec2_op<<OP_SHF) | (clo_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
-}
-
-void MIPSAssembler::CLZ(int Rd, int Rs)
-{
- // Rt field must have same gpr # as Rd
- *mPC++ = (spec2_op<<OP_SHF) | (clz_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rd<<RT_SHF);
-}
-
-void MIPSAssembler::WSBH(int Rd, int Rt) // mips32r2
-{
- *mPC++ = (spec3_op<<OP_SHF) | (bshfl_fn<<FUNC_SHF) | (wsbh_fn << SA_SHF) |
- (Rt<<RT_SHF) | (Rd<<RD_SHF);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Load/store...
-#endif
-
-void MIPSAssembler::LW(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (lw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::SW(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (sw_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-// lb is sign-extended
-void MIPSAssembler::LB(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (lb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::LBU(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (lbu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::SB(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (sb_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-// lh is sign-extended
-void MIPSAssembler::LH(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (lh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::LHU(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (lhu_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::SH(int Rt, int Rbase, int16_t offset)
-{
- *mPC++ = (sh_op<<OP_SHF) | (Rbase<<RS_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-void MIPSAssembler::LUI(int Rt, int16_t offset)
-{
- *mPC++ = (lui_op<<OP_SHF) | (Rt<<RT_SHF) | (offset & MSK_16);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Register move...
-#endif
-
-void MIPSAssembler::MOVE(int Rd, int Rs)
-{
- // encoded as "or rd, rs, zero"
- *mPC++ = (spec_op<<OP_SHF) | (or_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (0<<RT_SHF);
-}
-
-void MIPSAssembler::MOVN(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (movn_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::MOVZ(int Rd, int Rs, int Rt)
-{
- *mPC++ = (spec_op<<OP_SHF) | (movz_fn<<FUNC_SHF) |
- (Rd<<RD_SHF) | (Rs<<RS_SHF) | (Rt<<RT_SHF);
-}
-
-void MIPSAssembler::MFHI(int Rd)
-{
- *mPC++ = (spec_op<<OP_SHF) | (mfhi_fn<<FUNC_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPSAssembler::MFLO(int Rd)
-{
- *mPC++ = (spec_op<<OP_SHF) | (mflo_fn<<FUNC_SHF) | (Rd<<RD_SHF);
-}
-
-void MIPSAssembler::MTHI(int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (mthi_fn<<FUNC_SHF) | (Rs<<RS_SHF);
-}
-
-void MIPSAssembler::MTLO(int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (mtlo_fn<<FUNC_SHF) | (Rs<<RS_SHF);
-}
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Branch...
-#endif
-
-// temporarily forcing a NOP into branch-delay slot, just to be safe
-// todo: remove NOP, optimze use of delay slots
-void MIPSAssembler::B(const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
-
- // encoded as BEQ zero, zero, offset
- *mPC++ = (beq_op<<OP_SHF) | (0<<RT_SHF)
- | (0<<RS_SHF) | 0; // offset filled in later
-
- MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BEQ(int Rs, int Rt, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (beq_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
- MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BNE(int Rs, int Rt, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (bne_op<<OP_SHF) | (Rt<<RT_SHF) | (Rs<<RS_SHF) | 0;
- MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BLEZ(int Rs, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (blez_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
- MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BLTZ(int Rs, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (regimm_op<<OP_SHF) | (bltz_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
- MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::BGTZ(int Rs, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (bgtz_op<<OP_SHF) | (0<<RT_SHF) | (Rs<<RS_SHF) | 0;
- MIPSAssembler::NOP();
-}
-
-
-void MIPSAssembler::BGEZ(int Rs, const char* label)
-{
- mBranchTargets.add(branch_target_t(label, mPC));
- *mPC++ = (regimm_op<<OP_SHF) | (bgez_fn<<RT_SHF) | (Rs<<RS_SHF) | 0;
- MIPSAssembler::NOP();
-}
-
-void MIPSAssembler::JR(int Rs)
-{
- *mPC++ = (spec_op<<OP_SHF) | (Rs<<RS_SHF) | (jr_fn << FUNC_SHF);
- MIPSAssembler::NOP();
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark Synthesized Branch...
-#endif
-
-// synthetic variants of branches (using slt & friends)
-void MIPSAssembler::BEQZ(int Rs, const char* label)
-{
- BEQ(Rs, R_zero, label);
-}
-
-void MIPSAssembler::BNEZ(int Rs __unused, const char* label)
-{
- BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGE(int Rs, int Rt, const char* label)
-{
- SLT(R_at, Rs, Rt);
- BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGEU(int Rs, int Rt, const char* label)
-{
- SLTU(R_at, Rs, Rt);
- BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGT(int Rs, int Rt, const char* label)
-{
- SLT(R_at, Rt, Rs); // rev
- BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BGTU(int Rs, int Rt, const char* label)
-{
- SLTU(R_at, Rt, Rs); // rev
- BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLE(int Rs, int Rt, const char* label)
-{
- SLT(R_at, Rt, Rs); // rev
- BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLEU(int Rs, int Rt, const char* label)
-{
- SLTU(R_at, Rt, Rs); // rev
- BEQ(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLT(int Rs, int Rt, const char* label)
-{
- SLT(R_at, Rs, Rt);
- BNE(R_at, R_zero, label);
-}
-
-void MIPSAssembler::BLTU(int Rs, int Rt, const char* label)
-{
- SLTU(R_at, Rs, Rt);
- BNE(R_at, R_zero, label);
-}
-
-
-
-
-#if 0
-#pragma mark -
-#pragma mark Misc...
-#endif
-
-void MIPSAssembler::NOP(void)
-{
- // encoded as "sll zero, zero, 0", which is all zero
- *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF);
-}
-
-// using this as special opcode for not-yet-implemented ARM instruction
-void MIPSAssembler::NOP2(void)
-{
- // encoded as "sll zero, zero, 2", still a nop, but a unique code
- *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (2 << RE_SHF);
-}
-
-// using this as special opcode for purposefully NOT implemented ARM instruction
-void MIPSAssembler::UNIMPL(void)
-{
- // encoded as "sll zero, zero, 3", still a nop, but a unique code
- *mPC++ = (spec_op<<OP_SHF) | (sll_fn<<FUNC_SHF) | (3 << RE_SHF);
-}
-
-
-}; // namespace android:
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
deleted file mode 100644
index c1178b6..0000000
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ /dev/null
@@ -1,557 +0,0 @@
-/* libs/pixelflinger/codeflinger/MIPSAssembler.h
-**
-** Copyright 2012, 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 ANDROID_MIPSASSEMBLER_H
-#define ANDROID_MIPSASSEMBLER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include "tinyutils/smartpointer.h"
-#include "utils/KeyedVector.h"
-#include "utils/Vector.h"
-
-#include "ARMAssemblerInterface.h"
-#include "CodeCache.h"
-
-namespace android {
-
-class MIPSAssembler; // forward reference
-
-// this class mimics ARMAssembler interface
-// intent is to translate each ARM instruction to 1 or more MIPS instr
-// implementation calls MIPSAssembler class to generate mips code
-class ArmToMipsAssembler : public ARMAssemblerInterface
-{
-public:
- ArmToMipsAssembler(const sp<Assembly>& assembly,
- char *abuf = 0, int linesz = 0, int instr_count = 0);
- virtual ~ArmToMipsAssembler();
-
- uint32_t* base() const;
- uint32_t* pc() const;
- void disassemble(const char* name);
-
- virtual void reset();
-
- virtual int generate(const char* name);
- virtual int getCodegenArch();
-
- virtual void prolog();
- virtual void epilog(uint32_t touched);
- virtual void comment(const char* string);
-
-
- // -----------------------------------------------------------------------
- // shifters and addressing modes
- // -----------------------------------------------------------------------
-
- // shifters...
- virtual bool isValidImmediate(uint32_t immed);
- virtual int buildImmediate(uint32_t i, uint32_t& rot, uint32_t& imm);
-
- virtual uint32_t imm(uint32_t immediate);
- virtual uint32_t reg_imm(int Rm, int type, uint32_t shift);
- virtual uint32_t reg_rrx(int Rm);
- virtual uint32_t reg_reg(int Rm, int type, int Rs);
-
- // addressing modes...
- // LDR(B)/STR(B)/PLD
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed12_pre(int32_t immed12, int W=0);
- virtual uint32_t immed12_post(int32_t immed12);
- virtual uint32_t reg_scale_pre(int Rm, int type=0, uint32_t shift=0, int W=0);
- virtual uint32_t reg_scale_post(int Rm, int type=0, uint32_t shift=0);
-
- // LDRH/LDRSB/LDRSH/STRH
- // (immediate and Rm can be negative, which indicates U=0)
- virtual uint32_t immed8_pre(int32_t immed8, int W=0);
- virtual uint32_t immed8_post(int32_t immed8);
- virtual uint32_t reg_pre(int Rm, int W=0);
- virtual uint32_t reg_post(int Rm);
-
-
-
-
- virtual void dataProcessing(int opcode, int cc, int s,
- int Rd, int Rn,
- uint32_t Op2);
- virtual void MLA(int cc, int s,
- int Rd, int Rm, int Rs, int Rn);
- virtual void MUL(int cc, int s,
- int Rd, int Rm, int Rs);
- virtual void UMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void UMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMULL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
- virtual void SMUAL(int cc, int s,
- int RdLo, int RdHi, int Rm, int Rs);
-
- virtual void B(int cc, uint32_t* pc);
- virtual void BL(int cc, uint32_t* pc);
- virtual void BX(int cc, int Rn);
- virtual void label(const char* theLabel);
- virtual void B(int cc, const char* label);
- virtual void BL(int cc, const char* label);
-
- virtual uint32_t* pcForLabel(const char* label);
-
- virtual void LDR (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STR (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STRB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRH (int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRSB(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void LDRSH(int cc, int Rd,
- int Rn, uint32_t offset = 0);
- virtual void STRH (int cc, int Rd,
- int Rn, uint32_t offset = 0);
-
- virtual void LDM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
- virtual void STM(int cc, int dir,
- int Rn, int W, uint32_t reg_list);
-
- virtual void SWP(int cc, int Rn, int Rd, int Rm);
- virtual void SWPB(int cc, int Rn, int Rd, int Rm);
- virtual void SWI(int cc, uint32_t comment);
-
- virtual void PLD(int Rn, uint32_t offset);
- virtual void CLZ(int cc, int Rd, int Rm);
- virtual void QADD(int cc, int Rd, int Rm, int Rn);
- virtual void QDADD(int cc, int Rd, int Rm, int Rn);
- virtual void QSUB(int cc, int Rd, int Rm, int Rn);
- virtual void QDSUB(int cc, int Rd, int Rm, int Rn);
- virtual void SMUL(int cc, int xy,
- int Rd, int Rm, int Rs);
- virtual void SMULW(int cc, int y,
- int Rd, int Rm, int Rs);
- virtual void SMLA(int cc, int xy,
- int Rd, int Rm, int Rs, int Rn);
- virtual void SMLAL(int cc, int xy,
- int RdHi, int RdLo, int Rs, int Rm);
- virtual void SMLAW(int cc, int y,
- int Rd, int Rm, int Rs, int Rn);
-
- // byte/half word extract...
- virtual void UXTB16(int cc, int Rd, int Rm, int rotate);
-
- // bit manipulation...
- virtual void UBFX(int cc, int Rd, int Rn, int lsb, int width);
-
- // this is some crap to share is MIPSAssembler class for debug
- char * mArmDisassemblyBuffer;
- int mArmLineLength;
- int mArmInstrCount;
-
- int mInum; // current arm instuction number (0..n)
- uint32_t** mArmPC; // array: PC for 1st mips instr of
- // each translated ARM instr
-
-
-private:
- ArmToMipsAssembler(const ArmToMipsAssembler& rhs);
- ArmToMipsAssembler& operator = (const ArmToMipsAssembler& rhs);
-
- void init_conditional_labels(void);
-
- void protectConditionalOperands(int Rd);
-
- // reg__tmp set to MIPS AT, reg 1
- int dataProcAdrModes(int op, int& source, bool sign = false, int reg_tmp = 1);
-
- sp<Assembly> mAssembly;
- MIPSAssembler* mMips;
-
-
- enum misc_constants_t {
- ARM_MAX_INSTUCTIONS = 512 // based on ASSEMBLY_SCRATCH_SIZE
- };
-
- enum {
- SRC_REG = 0,
- SRC_IMM,
- SRC_ERROR = -1
- };
-
- enum addr_modes {
- // start above the range of legal mips reg #'s (0-31)
- AMODE_REG = 0x20,
- AMODE_IMM, AMODE_REG_IMM, // for data processing
- AMODE_IMM_12_PRE, AMODE_IMM_12_POST, // for load/store
- AMODE_REG_SCALE_PRE, AMODE_IMM_8_PRE,
- AMODE_IMM_8_POST, AMODE_REG_PRE,
- AMODE_UNSUPPORTED
- };
-
- struct addr_mode_t { // address modes for current ARM instruction
- int reg;
- int stype;
- uint32_t value;
- bool writeback; // writeback the adr reg after modification
- } amode;
-
- enum cond_types {
- CMP_COND = 1,
- SBIT_COND
- };
-
- struct cond_mode_t { // conditional-execution info for current ARM instruction
- cond_types type;
- int r1;
- int r2;
- int labelnum;
- char label[100][10];
- } cond;
-
-};
-
-
-
-
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-// ----------------------------------------------------------------------------
-
-// This is the basic MIPS assembler, which just creates the opcodes in memory.
-// All the more complicated work is done in ArmToMipsAssember above.
-
-class MIPSAssembler
-{
-public:
- MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent);
- MIPSAssembler(void* assembly);
- virtual ~MIPSAssembler();
-
- virtual uint32_t* base() const;
- virtual uint32_t* pc() const;
- virtual void reset();
-
- virtual void disassemble(const char* name);
-
- virtual void prolog();
- virtual void epilog(uint32_t touched);
- virtual int generate(const char* name);
- virtual void comment(const char* string);
- virtual void label(const char* string);
-
- // valid only after generate() has been called
- virtual uint32_t* pcForLabel(const char* label);
-
-
- // ------------------------------------------------------------------------
- // MIPSAssemblerInterface...
- // ------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Arithmetic...
-#endif
-
- void ADDU(int Rd, int Rs, int Rt);
- void ADDIU(int Rt, int Rs, int16_t imm);
- void SUBU(int Rd, int Rs, int Rt);
- void SUBIU(int Rt, int Rs, int16_t imm);
- void NEGU(int Rd, int Rs);
- void MUL(int Rd, int Rs, int Rt);
- void MULT(int Rs, int Rt); // dest is hi,lo
- void MULTU(int Rs, int Rt); // dest is hi,lo
- void MADD(int Rs, int Rt); // hi,lo = hi,lo + Rs * Rt
- void MADDU(int Rs, int Rt); // hi,lo = hi,lo + Rs * Rt
- void MSUB(int Rs, int Rt); // hi,lo = hi,lo - Rs * Rt
- void MSUBU(int Rs, int Rt); // hi,lo = hi,lo - Rs * Rt
- void SEB(int Rd, int Rt); // sign-extend byte (mips32r2)
- void SEH(int Rd, int Rt); // sign-extend half-word (mips32r2)
-
-
-#if 0
-#pragma mark -
-#pragma mark Comparisons...
-#endif
-
- void SLT(int Rd, int Rs, int Rt);
- void SLTI(int Rt, int Rs, int16_t imm);
- void SLTU(int Rd, int Rs, int Rt);
- void SLTIU(int Rt, int Rs, int16_t imm);
-
-
-#if 0
-#pragma mark -
-#pragma mark Logical...
-#endif
-
- void AND(int Rd, int Rs, int Rt);
- void ANDI(int Rd, int Rs, uint16_t imm);
- void OR(int Rd, int Rs, int Rt);
- void ORI(int Rt, int Rs, uint16_t imm);
- void NOR(int Rd, int Rs, int Rt);
- void NOT(int Rd, int Rs);
- void XOR(int Rd, int Rs, int Rt);
- void XORI(int Rt, int Rs, uint16_t imm);
-
- void SLL(int Rd, int Rt, int shft);
- void SLLV(int Rd, int Rt, int Rs);
- void SRL(int Rd, int Rt, int shft);
- void SRLV(int Rd, int Rt, int Rs);
- void SRA(int Rd, int Rt, int shft);
- void SRAV(int Rd, int Rt, int Rs);
- void ROTR(int Rd, int Rt, int shft); // mips32r2
- void ROTRV(int Rd, int Rt, int Rs); // mips32r2
- void RORsyn(int Rd, int Rs, int Rt); // synthetic: d = s rotated by t
- void RORIsyn(int Rd, int Rt, int rot); // synthetic: d = s rotated by immed
-
- void CLO(int Rd, int Rs);
- void CLZ(int Rd, int Rs);
- void WSBH(int Rd, int Rt);
-
-
-#if 0
-#pragma mark -
-#pragma mark Load/store...
-#endif
-
- void LW(int Rt, int Rbase, int16_t offset);
- void SW(int Rt, int Rbase, int16_t offset);
- void LB(int Rt, int Rbase, int16_t offset);
- void LBU(int Rt, int Rbase, int16_t offset);
- void SB(int Rt, int Rbase, int16_t offset);
- void LH(int Rt, int Rbase, int16_t offset);
- void LHU(int Rt, int Rbase, int16_t offset);
- void SH(int Rt, int Rbase, int16_t offset);
- void LUI(int Rt, int16_t offset);
-
-#if 0
-#pragma mark -
-#pragma mark Register moves...
-#endif
-
- void MOVE(int Rd, int Rs);
- void MOVN(int Rd, int Rs, int Rt);
- void MOVZ(int Rd, int Rs, int Rt);
- void MFHI(int Rd);
- void MFLO(int Rd);
- void MTHI(int Rs);
- void MTLO(int Rs);
-
-#if 0
-#pragma mark -
-#pragma mark Branch...
-#endif
-
- void B(const char* label);
- void BEQ(int Rs, int Rt, const char* label);
- void BNE(int Rs, int Rt, const char* label);
- void BGEZ(int Rs, const char* label);
- void BGTZ(int Rs, const char* label);
- void BLEZ(int Rs, const char* label);
- void BLTZ(int Rs, const char* label);
- void JR(int Rs);
-
-
-#if 0
-#pragma mark -
-#pragma mark Synthesized Branch...
-#endif
-
- // synthetic variants of above (using slt & friends)
- void BEQZ(int Rs, const char* label);
- void BNEZ(int Rs, const char* label);
- void BGE(int Rs, int Rt, const char* label);
- void BGEU(int Rs, int Rt, const char* label);
- void BGT(int Rs, int Rt, const char* label);
- void BGTU(int Rs, int Rt, const char* label);
- void BLE(int Rs, int Rt, const char* label);
- void BLEU(int Rs, int Rt, const char* label);
- void BLT(int Rs, int Rt, const char* label);
- void BLTU(int Rs, int Rt, const char* label);
-
-#if 0
-#pragma mark -
-#pragma mark Misc...
-#endif
-
- void NOP(void);
- void NOP2(void);
- void UNIMPL(void);
-
-
-
-
-
-protected:
- virtual void string_detab(char *s);
- virtual void string_pad(char *s, int padded_len);
-
- ArmToMipsAssembler *mParent;
- sp<Assembly> mAssembly;
- uint32_t* mBase;
- uint32_t* mPC;
- uint32_t* mPrologPC;
- int64_t mDuration;
-
- struct branch_target_t {
- inline branch_target_t() : label(0), pc(0) { }
- inline branch_target_t(const char* l, uint32_t* p)
- : label(l), pc(p) { }
- const char* label;
- uint32_t* pc;
- };
-
- Vector<branch_target_t> mBranchTargets;
- KeyedVector< const char*, uint32_t* > mLabels;
- KeyedVector< uint32_t*, const char* > mLabelsInverseMapping;
- KeyedVector< uint32_t*, const char* > mComments;
-
-
-
-
- // opcode field of all instructions
- enum opcode_field {
- spec_op, regimm_op, j_op, jal_op, // 00
- beq_op, bne_op, blez_op, bgtz_op,
- addi_op, addiu_op, slti_op, sltiu_op, // 08
- andi_op, ori_op, xori_op, lui_op,
- cop0_op, cop1_op, cop2_op, cop1x_op, // 10
- beql_op, bnel_op, blezl_op, bgtzl_op,
- daddi_op, daddiu_op, ldl_op, ldr_op, // 18
- spec2_op, jalx_op, mdmx_op, spec3_op,
- lb_op, lh_op, lwl_op, lw_op, // 20
- lbu_op, lhu_op, lwr_op, lwu_op,
- sb_op, sh_op, swl_op, sw_op, // 28
- sdl_op, sdr_op, swr_op, cache_op,
- ll_op, lwc1_op, lwc2_op, pref_op, // 30
- lld_op, ldc1_op, ldc2_op, ld_op,
- sc_op, swc1_op, swc2_op, rsrv_3b_op, // 38
- scd_op, sdc1_op, sdc2_op, sd_op
- };
-
-
- // func field for special opcode
- enum func_spec_op {
- sll_fn, movc_fn, srl_fn, sra_fn, // 00
- sllv_fn, pmon_fn, srlv_fn, srav_fn,
- jr_fn, jalr_fn, movz_fn, movn_fn, // 08
- syscall_fn, break_fn, spim_fn, sync_fn,
- mfhi_fn, mthi_fn, mflo_fn, mtlo_fn, // 10
- dsllv_fn, rsrv_spec_2, dsrlv_fn, dsrav_fn,
- mult_fn, multu_fn, div_fn, divu_fn, // 18
- dmult_fn, dmultu_fn, ddiv_fn, ddivu_fn,
- add_fn, addu_fn, sub_fn, subu_fn, // 20
- and_fn, or_fn, xor_fn, nor_fn,
- rsrv_spec_3, rsrv_spec_4, slt_fn, sltu_fn, // 28
- dadd_fn, daddu_fn, dsub_fn, dsubu_fn,
- tge_fn, tgeu_fn, tlt_fn, tltu_fn, // 30
- teq_fn, rsrv_spec_5, tne_fn, rsrv_spec_6,
- dsll_fn, rsrv_spec_7, dsrl_fn, dsra_fn, // 38
- dsll32_fn, rsrv_spec_8, dsrl32_fn, dsra32_fn
- };
-
- // func field for spec2 opcode
- enum func_spec2_op {
- madd_fn, maddu_fn, mul_fn, rsrv_spec2_3,
- msub_fn, msubu_fn,
- clz_fn = 0x20, clo_fn,
- dclz_fn = 0x24, dclo_fn,
- sdbbp_fn = 0x3f
- };
-
- // func field for spec3 opcode
- enum func_spec3_op {
- ext_fn, dextm_fn, dextu_fn, dext_fn,
- ins_fn, dinsm_fn, dinsu_fn, dins_fn,
- bshfl_fn = 0x20,
- dbshfl_fn = 0x24,
- rdhwr_fn = 0x3b
- };
-
- // sa field for spec3 opcodes, with BSHFL function
- enum func_spec3_bshfl {
- wsbh_fn = 0x02,
- seb_fn = 0x10,
- seh_fn = 0x18
- };
-
- // rt field of regimm opcodes.
- enum regimm_fn {
- bltz_fn, bgez_fn, bltzl_fn, bgezl_fn,
- rsrv_ri_fn4, rsrv_ri_fn5, rsrv_ri_fn6, rsrv_ri_fn7,
- tgei_fn, tgeiu_fn, tlti_fn, tltiu_fn,
- teqi_fn, rsrv_ri_fn_0d, tnei_fn, rsrv_ri_fn0f,
- bltzal_fn, bgezal_fn, bltzall_fn, bgezall_fn,
- bposge32_fn= 0x1c,
- synci_fn = 0x1f
- };
-
-
- // func field for mad opcodes (MIPS IV).
- enum mad_func {
- madd_fp_op = 0x08, msub_fp_op = 0x0a,
- nmadd_fp_op = 0x0c, nmsub_fp_op = 0x0e
- };
-
-
- enum mips_inst_shifts {
- OP_SHF = 26,
- JTARGET_SHF = 0,
- RS_SHF = 21,
- RT_SHF = 16,
- RD_SHF = 11,
- RE_SHF = 6,
- SA_SHF = RE_SHF, // synonym
- IMM_SHF = 0,
- FUNC_SHF = 0,
-
- // mask values
- MSK_16 = 0xffff,
-
-
- CACHEOP_SHF = 18,
- CACHESEL_SHF = 16,
- };
-};
-
-enum mips_regnames {
- R_zero = 0,
- R_at, R_v0, R_v1, R_a0, R_a1, R_a2, R_a3,
-#if __mips_isa_rev < 6
- R_t0, R_t1, R_t2, R_t3, R_t4, R_t5, R_t6, R_t7,
-#else
- R_a4, R_a5, R_a6, R_a7, R_t0, R_t1, R_t2, R_t3,
-#endif
- R_s0, R_s1, R_s2, R_s3, R_s4, R_s5, R_s6, R_s7,
- R_t8, R_t9, R_k0, R_k1, R_gp, R_sp, R_s8, R_ra,
- R_lr = R_s8,
-
- // arm regs 0-15 are mips regs 2-17 (meaning s0 & s1 are used)
- R_at2 = R_s2, // R_at2 = 18 = s2
- R_cmp = R_s3, // R_cmp = 19 = s3
- R_cmp2 = R_s4 // R_cmp2 = 20 = s4
-};
-
-
-
-}; // namespace android
-
-#endif //ANDROID_MIPSASSEMBLER_H
diff --git a/libpixelflinger/codeflinger/armreg.h b/libpixelflinger/codeflinger/armreg.h
deleted file mode 100644
index fde81ba..0000000
--- a/libpixelflinger/codeflinger/armreg.h
+++ /dev/null
@@ -1,300 +0,0 @@
-/* $NetBSD: armreg.h,v 1.28 2003/10/31 16:30:15 scw Exp $ */
-
-/*-
- * Copyright (c) 1998, 2001 Ben Harris
- * Copyright (c) 1994-1996 Mark Brinicombe.
- * Copyright (c) 1994 Brini.
- * All rights reserved.
- *
- * This code is derived from software written for Brini by Mark Brinicombe
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Brini.
- * 4. The name of the company nor the name of the author may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/armreg.h,v 1.3 2005/11/21 19:06:25 cognet Exp $
- */
-
-#ifndef MACHINE_ARMREG_H
-#define MACHINE_ARMREG_H
-#define INSN_SIZE 4
-#define INSN_COND_MASK 0xf0000000 /* Condition mask */
-#define PSR_MODE 0x0000001f /* mode mask */
-#define PSR_USR26_MODE 0x00000000
-#define PSR_FIQ26_MODE 0x00000001
-#define PSR_IRQ26_MODE 0x00000002
-#define PSR_SVC26_MODE 0x00000003
-#define PSR_USR32_MODE 0x00000010
-#define PSR_FIQ32_MODE 0x00000011
-#define PSR_IRQ32_MODE 0x00000012
-#define PSR_SVC32_MODE 0x00000013
-#define PSR_ABT32_MODE 0x00000017
-#define PSR_UND32_MODE 0x0000001b
-#define PSR_SYS32_MODE 0x0000001f
-#define PSR_32_MODE 0x00000010
-#define PSR_FLAGS 0xf0000000 /* flags */
-
-#define PSR_C_bit (1 << 29) /* carry */
-
-/* The high-order byte is always the implementor */
-#define CPU_ID_IMPLEMENTOR_MASK 0xff000000
-#define CPU_ID_ARM_LTD 0x41000000 /* 'A' */
-#define CPU_ID_DEC 0x44000000 /* 'D' */
-#define CPU_ID_INTEL 0x69000000 /* 'i' */
-#define CPU_ID_TI 0x54000000 /* 'T' */
-
-/* How to decide what format the CPUID is in. */
-#define CPU_ID_ISOLD(x) (((x) & 0x0000f000) == 0x00000000)
-#define CPU_ID_IS7(x) (((x) & 0x0000f000) == 0x00007000)
-#define CPU_ID_ISNEW(x) (!CPU_ID_ISOLD(x) && !CPU_ID_IS7(x))
-
-/* On ARM3 and ARM6, this byte holds the foundry ID. */
-#define CPU_ID_FOUNDRY_MASK 0x00ff0000
-#define CPU_ID_FOUNDRY_VLSI 0x00560000
-
-/* On ARM7 it holds the architecture and variant (sub-model) */
-#define CPU_ID_7ARCH_MASK 0x00800000
-#define CPU_ID_7ARCH_V3 0x00000000
-#define CPU_ID_7ARCH_V4T 0x00800000
-#define CPU_ID_7VARIANT_MASK 0x007f0000
-
-/* On more recent ARMs, it does the same, but in a different format */
-#define CPU_ID_ARCH_MASK 0x000f0000
-#define CPU_ID_ARCH_V3 0x00000000
-#define CPU_ID_ARCH_V4 0x00010000
-#define CPU_ID_ARCH_V4T 0x00020000
-#define CPU_ID_ARCH_V5 0x00030000
-#define CPU_ID_ARCH_V5T 0x00040000
-#define CPU_ID_ARCH_V5TE 0x00050000
-#define CPU_ID_VARIANT_MASK 0x00f00000
-
-/* Next three nybbles are part number */
-#define CPU_ID_PARTNO_MASK 0x0000fff0
-
-/* Intel XScale has sub fields in part number */
-#define CPU_ID_XSCALE_COREGEN_MASK 0x0000e000 /* core generation */
-#define CPU_ID_XSCALE_COREREV_MASK 0x00001c00 /* core revision */
-#define CPU_ID_XSCALE_PRODUCT_MASK 0x000003f0 /* product number */
-
-/* And finally, the revision number. */
-#define CPU_ID_REVISION_MASK 0x0000000f
-
-/* Individual CPUs are probably best IDed by everything but the revision. */
-#define CPU_ID_CPU_MASK 0xfffffff0
-
-/* Fake CPU IDs for ARMs without CP15 */
-#define CPU_ID_ARM2 0x41560200
-#define CPU_ID_ARM250 0x41560250
-
-/* Pre-ARM7 CPUs -- [15:12] == 0 */
-#define CPU_ID_ARM3 0x41560300
-#define CPU_ID_ARM600 0x41560600
-#define CPU_ID_ARM610 0x41560610
-#define CPU_ID_ARM620 0x41560620
-
-/* ARM7 CPUs -- [15:12] == 7 */
-#define CPU_ID_ARM700 0x41007000 /* XXX This is a guess. */
-#define CPU_ID_ARM710 0x41007100
-#define CPU_ID_ARM7500 0x41027100 /* XXX This is a guess. */
-#define CPU_ID_ARM710A 0x41047100 /* inc ARM7100 */
-#define CPU_ID_ARM7500FE 0x41077100
-#define CPU_ID_ARM710T 0x41807100
-#define CPU_ID_ARM720T 0x41807200
-#define CPU_ID_ARM740T8K 0x41807400 /* XXX no MMU, 8KB cache */
-#define CPU_ID_ARM740T4K 0x41817400 /* XXX no MMU, 4KB cache */
-
-/* Post-ARM7 CPUs */
-#define CPU_ID_ARM810 0x41018100
-#define CPU_ID_ARM920T 0x41129200
-#define CPU_ID_ARM920T_ALT 0x41009200
-#define CPU_ID_ARM922T 0x41029220
-#define CPU_ID_ARM940T 0x41029400 /* XXX no MMU */
-#define CPU_ID_ARM946ES 0x41049460 /* XXX no MMU */
-#define CPU_ID_ARM966ES 0x41049660 /* XXX no MMU */
-#define CPU_ID_ARM966ESR1 0x41059660 /* XXX no MMU */
-#define CPU_ID_ARM1020E 0x4115a200 /* (AKA arm10 rev 1) */
-#define CPU_ID_ARM1022ES 0x4105a220
-#define CPU_ID_SA110 0x4401a100
-#define CPU_ID_SA1100 0x4401a110
-#define CPU_ID_TI925T 0x54029250
-#define CPU_ID_SA1110 0x6901b110
-#define CPU_ID_IXP1200 0x6901c120
-#define CPU_ID_80200 0x69052000
-#define CPU_ID_PXA250 0x69052100 /* sans core revision */
-#define CPU_ID_PXA210 0x69052120
-#define CPU_ID_PXA250A 0x69052100 /* 1st version Core */
-#define CPU_ID_PXA210A 0x69052120 /* 1st version Core */
-#define CPU_ID_PXA250B 0x69052900 /* 3rd version Core */
-#define CPU_ID_PXA210B 0x69052920 /* 3rd version Core */
-#define CPU_ID_PXA250C 0x69052d00 /* 4th version Core */
-#define CPU_ID_PXA210C 0x69052d20 /* 4th version Core */
-#define CPU_ID_80321_400 0x69052420
-#define CPU_ID_80321_600 0x69052430
-#define CPU_ID_80321_400_B0 0x69052c20
-#define CPU_ID_80321_600_B0 0x69052c30
-#define CPU_ID_IXP425_533 0x690541c0
-#define CPU_ID_IXP425_400 0x690541d0
-#define CPU_ID_IXP425_266 0x690541f0
-
-/* ARM3-specific coprocessor 15 registers */
-#define ARM3_CP15_FLUSH 1
-#define ARM3_CP15_CONTROL 2
-#define ARM3_CP15_CACHEABLE 3
-#define ARM3_CP15_UPDATEABLE 4
-#define ARM3_CP15_DISRUPTIVE 5
-
-/* ARM3 Control register bits */
-#define ARM3_CTL_CACHE_ON 0x00000001
-#define ARM3_CTL_SHARED 0x00000002
-#define ARM3_CTL_MONITOR 0x00000004
-
-/*
- * Post-ARM3 CP15 registers:
- *
- * 1 Control register
- *
- * 2 Translation Table Base
- *
- * 3 Domain Access Control
- *
- * 4 Reserved
- *
- * 5 Fault Status
- *
- * 6 Fault Address
- *
- * 7 Cache/write-buffer Control
- *
- * 8 TLB Control
- *
- * 9 Cache Lockdown
- *
- * 10 TLB Lockdown
- *
- * 11 Reserved
- *
- * 12 Reserved
- *
- * 13 Process ID (for FCSE)
- *
- * 14 Reserved
- *
- * 15 Implementation Dependent
- */
-
-/* Some of the definitions below need cleaning up for V3/V4 architectures */
-
-/* CPU control register (CP15 register 1) */
-#define CPU_CONTROL_MMU_ENABLE 0x00000001 /* M: MMU/Protection unit enable */
-#define CPU_CONTROL_AFLT_ENABLE 0x00000002 /* A: Alignment fault enable */
-#define CPU_CONTROL_DC_ENABLE 0x00000004 /* C: IDC/DC enable */
-#define CPU_CONTROL_WBUF_ENABLE 0x00000008 /* W: Write buffer enable */
-#define CPU_CONTROL_32BP_ENABLE 0x00000010 /* P: 32-bit exception handlers */
-#define CPU_CONTROL_32BD_ENABLE 0x00000020 /* D: 32-bit addressing */
-#define CPU_CONTROL_LABT_ENABLE 0x00000040 /* L: Late abort enable */
-#define CPU_CONTROL_BEND_ENABLE 0x00000080 /* B: Big-endian mode */
-#define CPU_CONTROL_SYST_ENABLE 0x00000100 /* S: System protection bit */
-#define CPU_CONTROL_ROM_ENABLE 0x00000200 /* R: ROM protection bit */
-#define CPU_CONTROL_CPCLK 0x00000400 /* F: Implementation defined */
-#define CPU_CONTROL_BPRD_ENABLE 0x00000800 /* Z: Branch prediction enable */
-#define CPU_CONTROL_IC_ENABLE 0x00001000 /* I: IC enable */
-#define CPU_CONTROL_VECRELOC 0x00002000 /* V: Vector relocation */
-#define CPU_CONTROL_ROUNDROBIN 0x00004000 /* RR: Predictable replacement */
-#define CPU_CONTROL_V4COMPAT 0x00008000 /* L4: ARMv4 compat LDR R15 etc */
-
-#define CPU_CONTROL_IDC_ENABLE CPU_CONTROL_DC_ENABLE
-
-/* XScale Auxillary Control Register (CP15 register 1, opcode2 1) */
-#define XSCALE_AUXCTL_K 0x00000001 /* dis. write buffer coalescing */
-#define XSCALE_AUXCTL_P 0x00000002 /* ECC protect page table access */
-#define XSCALE_AUXCTL_MD_WB_RA 0x00000000 /* mini-D$ wb, read-allocate */
-#define XSCALE_AUXCTL_MD_WB_RWA 0x00000010 /* mini-D$ wb, read/write-allocate */
-#define XSCALE_AUXCTL_MD_WT 0x00000020 /* mini-D$ wt, read-allocate */
-#define XSCALE_AUXCTL_MD_MASK 0x00000030
-
-/* Cache type register definitions */
-#define CPU_CT_ISIZE(x) ((x) & 0xfff) /* I$ info */
-#define CPU_CT_DSIZE(x) (((x) >> 12) & 0xfff) /* D$ info */
-#define CPU_CT_S (1U << 24) /* split cache */
-#define CPU_CT_CTYPE(x) (((x) >> 25) & 0xf) /* cache type */
-
-#define CPU_CT_CTYPE_WT 0 /* write-through */
-#define CPU_CT_CTYPE_WB1 1 /* write-back, clean w/ read */
-#define CPU_CT_CTYPE_WB2 2 /* w/b, clean w/ cp15,7 */
-#define CPU_CT_CTYPE_WB6 6 /* w/b, cp15,7, lockdown fmt A */
-#define CPU_CT_CTYPE_WB7 7 /* w/b, cp15,7, lockdown fmt B */
-
-#define CPU_CT_xSIZE_LEN(x) ((x) & 0x3) /* line size */
-#define CPU_CT_xSIZE_M (1U << 2) /* multiplier */
-#define CPU_CT_xSIZE_ASSOC(x) (((x) >> 3) & 0x7) /* associativity */
-#define CPU_CT_xSIZE_SIZE(x) (((x) >> 6) & 0x7) /* size */
-
-/* Fault status register definitions */
-
-#define FAULT_TYPE_MASK 0x0f
-#define FAULT_USER 0x10
-
-#define FAULT_WRTBUF_0 0x00 /* Vector Exception */
-#define FAULT_WRTBUF_1 0x02 /* Terminal Exception */
-#define FAULT_BUSERR_0 0x04 /* External Abort on Linefetch -- Section */
-#define FAULT_BUSERR_1 0x06 /* External Abort on Linefetch -- Page */
-#define FAULT_BUSERR_2 0x08 /* External Abort on Non-linefetch -- Section */
-#define FAULT_BUSERR_3 0x0a /* External Abort on Non-linefetch -- Page */
-#define FAULT_BUSTRNL1 0x0c /* External abort on Translation -- Level 1 */
-#define FAULT_BUSTRNL2 0x0e /* External abort on Translation -- Level 2 */
-#define FAULT_ALIGN_0 0x01 /* Alignment */
-#define FAULT_ALIGN_1 0x03 /* Alignment */
-#define FAULT_TRANS_S 0x05 /* Translation -- Section */
-#define FAULT_TRANS_P 0x07 /* Translation -- Page */
-#define FAULT_DOMAIN_S 0x09 /* Domain -- Section */
-#define FAULT_DOMAIN_P 0x0b /* Domain -- Page */
-#define FAULT_PERM_S 0x0d /* Permission -- Section */
-#define FAULT_PERM_P 0x0f /* Permission -- Page */
-
-#define FAULT_IMPRECISE 0x400 /* Imprecise exception (XSCALE) */
-
-/*
- * Address of the vector page, low and high versions.
- */
-#define ARM_VECTORS_LOW 0x00000000U
-#define ARM_VECTORS_HIGH 0xffff0000U
-
-/*
- * ARM Instructions
- *
- * 3 3 2 2 2
- * 1 0 9 8 7 0
- * +-------+-------------------------------------------------------+
- * | cond | instruction dependant |
- * |c c c c| |
- * +-------+-------------------------------------------------------+
- */
-
-#define INSN_SIZE 4 /* Always 4 bytes */
-#define INSN_COND_MASK 0xf0000000 /* Condition mask */
-#define INSN_COND_AL 0xe0000000 /* Always condition */
-
-#endif /* !MACHINE_ARMREG_H */
diff --git a/libpixelflinger/codeflinger/blending.cpp b/libpixelflinger/codeflinger/blending.cpp
deleted file mode 100644
index 2cbb00f..0000000
--- a/libpixelflinger/codeflinger/blending.cpp
+++ /dev/null
@@ -1,674 +0,0 @@
-/* libs/pixelflinger/codeflinger/blending.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "pixelflinger-code"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <android-base/macros.h>
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-void GGLAssembler::build_fog(
- component_t& temp, // incomming fragment / output
- int component,
- Scratch& regs)
-{
- if (mInfo[component].fog) {
- Scratch scratches(registerFile());
- comment("fog");
-
- integer_t fragment(temp.reg, temp.h, temp.flags);
- if (!(temp.flags & CORRUPTIBLE)) {
- temp.reg = regs.obtain();
- temp.flags |= CORRUPTIBLE;
- }
-
- integer_t fogColor(scratches.obtain(), 8, CORRUPTIBLE);
- LDRB(AL, fogColor.reg, mBuilderContext.Rctx,
- immed12_pre(GGL_OFFSETOF(state.fog.color[component])));
-
- integer_t factor(scratches.obtain(), 16, CORRUPTIBLE);
- CONTEXT_LOAD(factor.reg, generated_vars.f);
-
- // clamp fog factor (TODO: see if there is a way to guarantee
- // we won't overflow, when setting the iterators)
- BIC(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, ASR, 31));
- CMP(AL, factor.reg, imm( 0x10000 ));
- MOV(HS, 0, factor.reg, imm( 0x10000 ));
-
- build_blendFOneMinusF(temp, factor, fragment, fogColor);
- }
-}
-
-void GGLAssembler::build_blending(
- component_t& temp, // incomming fragment / output
- const pixel_t& pixel, // framebuffer
- int component,
- Scratch& regs)
-{
- if (!mInfo[component].blend)
- return;
-
- int fs = component==GGLFormat::ALPHA ? mBlendSrcA : mBlendSrc;
- int fd = component==GGLFormat::ALPHA ? mBlendDstA : mBlendDst;
- if (fs==GGL_SRC_ALPHA_SATURATE && component==GGLFormat::ALPHA)
- fs = GGL_ONE;
- const int blending = blending_codes(fs, fd);
- if (!temp.size()) {
- // here, blending will produce something which doesn't depend on
- // that component (eg: GL_ZERO:GL_*), so the register has not been
- // allocated yet. Will never be used as a source.
- temp = component_t(regs.obtain(), CORRUPTIBLE);
- }
-
- // we are doing real blending...
- // fb: extracted dst
- // fragment: extracted src
- // temp: component_t(fragment) and result
-
- // scoped register allocator
- Scratch scratches(registerFile());
- comment("blending");
-
- // we can optimize these cases a bit...
- // (1) saturation is not needed
- // (2) we can use only one multiply instead of 2
- // (3) we can reduce the register pressure
- // R = S*f + D*(1-f) = (S-D)*f + D
- // R = S*(1-f) + D*f = (D-S)*f + S
-
- const bool same_factor_opt1 =
- (fs==GGL_DST_COLOR && fd==GGL_ONE_MINUS_DST_COLOR) ||
- (fs==GGL_SRC_COLOR && fd==GGL_ONE_MINUS_SRC_COLOR) ||
- (fs==GGL_DST_ALPHA && fd==GGL_ONE_MINUS_DST_ALPHA) ||
- (fs==GGL_SRC_ALPHA && fd==GGL_ONE_MINUS_SRC_ALPHA);
-
- const bool same_factor_opt2 =
- (fs==GGL_ONE_MINUS_DST_COLOR && fd==GGL_DST_COLOR) ||
- (fs==GGL_ONE_MINUS_SRC_COLOR && fd==GGL_SRC_COLOR) ||
- (fs==GGL_ONE_MINUS_DST_ALPHA && fd==GGL_DST_ALPHA) ||
- (fs==GGL_ONE_MINUS_SRC_ALPHA && fd==GGL_SRC_ALPHA);
-
-
- // XXX: we could also optimize these cases:
- // R = S*f + D*f = (S+D)*f
- // R = S*(1-f) + D*(1-f) = (S+D)*(1-f)
- // R = S*D + D*S = 2*S*D
-
-
- // see if we need to extract 'component' from the destination (fb)
- integer_t fb;
- if (blending & (BLEND_DST|FACTOR_DST)) {
- fb.setTo(scratches.obtain(), 32);
- extract(fb, pixel, component);
- if (mDithering) {
- // XXX: maybe what we should do instead, is simply
- // expand fb -or- fragment to the larger of the two
- if (fb.size() < temp.size()) {
- // for now we expand 'fb' to min(fragment, 8)
- int new_size = temp.size() < 8 ? temp.size() : 8;
- expand(fb, fb, new_size);
- }
- }
- }
-
-
- // convert input fragment to integer_t
- if (temp.l && (temp.flags & CORRUPTIBLE)) {
- MOV(AL, 0, temp.reg, reg_imm(temp.reg, LSR, temp.l));
- temp.h -= temp.l;
- temp.l = 0;
- }
- integer_t fragment(temp.reg, temp.size(), temp.flags);
-
- // if not done yet, convert input fragment to integer_t
- if (temp.l) {
- // here we know temp is not CORRUPTIBLE
- fragment.reg = scratches.obtain();
- MOV(AL, 0, fragment.reg, reg_imm(temp.reg, LSR, temp.l));
- fragment.flags |= CORRUPTIBLE;
- }
-
- if (!(temp.flags & CORRUPTIBLE)) {
- // temp is not corruptible, but since it's the destination it
- // will be modified, so we need to allocate a new register.
- temp.reg = regs.obtain();
- temp.flags &= ~CORRUPTIBLE;
- fragment.flags &= ~CORRUPTIBLE;
- }
-
- if ((blending & BLEND_SRC) && !same_factor_opt1) {
- // source (fragment) is needed for the blending stage
- // so it's not CORRUPTIBLE (unless we're doing same_factor_opt1)
- fragment.flags &= ~CORRUPTIBLE;
- }
-
-
- if (same_factor_opt1) {
- // R = S*f + D*(1-f) = (S-D)*f + D
- integer_t factor;
- build_blend_factor(factor, fs,
- component, pixel, fragment, fb, scratches);
- // fb is always corruptible from this point
- fb.flags |= CORRUPTIBLE;
- build_blendFOneMinusF(temp, factor, fragment, fb);
- } else if (same_factor_opt2) {
- // R = S*(1-f) + D*f = (D-S)*f + S
- integer_t factor;
- // fb is always corrruptible here
- fb.flags |= CORRUPTIBLE;
- build_blend_factor(factor, fd,
- component, pixel, fragment, fb, scratches);
- build_blendOneMinusFF(temp, factor, fragment, fb);
- } else {
- integer_t src_factor;
- integer_t dst_factor;
-
- // if destination (fb) is not needed for the blending stage,
- // then it can be marked as CORRUPTIBLE
- if (!(blending & BLEND_DST)) {
- fb.flags |= CORRUPTIBLE;
- }
-
- // XXX: try to mark some registers as CORRUPTIBLE
- // in most case we could make those corruptible
- // when we're processing the last component
- // but not always, for instance
- // when fragment is constant and not reloaded
- // when fb is needed for logic-ops or masking
- // when a register is aliased (for instance with mAlphaSource)
-
- // blend away...
- if (fs==GGL_ZERO) {
- if (fd==GGL_ZERO) { // R = 0
- // already taken care of
- } else if (fd==GGL_ONE) { // R = D
- // already taken care of
- } else { // R = D*fd
- // compute fd
- build_blend_factor(dst_factor, fd,
- component, pixel, fragment, fb, scratches);
- mul_factor(temp, fb, dst_factor);
- }
- } else if (fs==GGL_ONE) {
- if (fd==GGL_ZERO) { // R = S
- // NOP, taken care of
- } else if (fd==GGL_ONE) { // R = S + D
- component_add(temp, fb, fragment); // args order matters
- component_sat(temp);
- } else { // R = S + D*fd
- // compute fd
- build_blend_factor(dst_factor, fd,
- component, pixel, fragment, fb, scratches);
- mul_factor_add(temp, fb, dst_factor, component_t(fragment));
- component_sat(temp);
- }
- } else {
- // compute fs
- build_blend_factor(src_factor, fs,
- component, pixel, fragment, fb, scratches);
- if (fd==GGL_ZERO) { // R = S*fs
- mul_factor(temp, fragment, src_factor);
- } else if (fd==GGL_ONE) { // R = S*fs + D
- mul_factor_add(temp, fragment, src_factor, component_t(fb));
- component_sat(temp);
- } else { // R = S*fs + D*fd
- mul_factor(temp, fragment, src_factor);
- if (scratches.isUsed(src_factor.reg))
- scratches.recycle(src_factor.reg);
- // compute fd
- build_blend_factor(dst_factor, fd,
- component, pixel, fragment, fb, scratches);
- mul_factor_add(temp, fb, dst_factor, temp);
- if (!same_factor_opt1 && !same_factor_opt2) {
- component_sat(temp);
- }
- }
- }
- }
-
- // now we can be corrupted (it's the dest)
- temp.flags |= CORRUPTIBLE;
-}
-
-void GGLAssembler::build_blend_factor(
- integer_t& factor, int f, int component,
- const pixel_t& dst_pixel,
- integer_t& fragment,
- integer_t& fb,
- Scratch& scratches)
-{
- integer_t src_alpha(fragment);
-
- // src_factor/dst_factor won't be used after blending,
- // so it's fine to mark them as CORRUPTIBLE (if not aliased)
- factor.flags |= CORRUPTIBLE;
-
- switch(f) {
- case GGL_ONE_MINUS_SRC_ALPHA:
- case GGL_SRC_ALPHA:
- if (component==GGLFormat::ALPHA && !isAlphaSourceNeeded()) {
- // we're processing alpha, so we already have
- // src-alpha in fragment, and we need src-alpha just this time.
- } else {
- // alpha-src will be needed for other components
- if (!mBlendFactorCached || mBlendFactorCached==f) {
- src_alpha = mAlphaSource;
- factor = mAlphaSource;
- factor.flags &= ~CORRUPTIBLE;
- // we already computed the blend factor before, nothing to do.
- if (mBlendFactorCached)
- return;
- // this is the first time, make sure to compute the blend
- // factor properly.
- mBlendFactorCached = f;
- break;
- } else {
- // we have a cached alpha blend factor, but we want another one,
- // this should really not happen because by construction,
- // we cannot have BOTH source and destination
- // blend factors use ALPHA *and* ONE_MINUS_ALPHA (because
- // the blending stage uses the f/(1-f) optimization
-
- // for completeness, we handle this case though. Since there
- // are only 2 choices, this meens we want "the other one"
- // (1-factor)
- factor = mAlphaSource;
- factor.flags &= ~CORRUPTIBLE;
- RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s)));
- mBlendFactorCached = f;
- return;
- }
- }
- FALLTHROUGH_INTENDED;
- case GGL_ONE_MINUS_DST_COLOR:
- case GGL_DST_COLOR:
- case GGL_ONE_MINUS_SRC_COLOR:
- case GGL_SRC_COLOR:
- case GGL_ONE_MINUS_DST_ALPHA:
- case GGL_DST_ALPHA:
- case GGL_SRC_ALPHA_SATURATE:
- // help us find out what register we can use for the blend-factor
- // CORRUPTIBLE registers are chosen first, or a new one is allocated.
- if (fragment.flags & CORRUPTIBLE) {
- factor.setTo(fragment.reg, 32, CORRUPTIBLE);
- fragment.flags &= ~CORRUPTIBLE;
- } else if (fb.flags & CORRUPTIBLE) {
- factor.setTo(fb.reg, 32, CORRUPTIBLE);
- fb.flags &= ~CORRUPTIBLE;
- } else {
- factor.setTo(scratches.obtain(), 32, CORRUPTIBLE);
- }
- break;
- }
-
- // XXX: doesn't work if size==1
-
- switch(f) {
- case GGL_ONE_MINUS_DST_COLOR:
- case GGL_DST_COLOR:
- factor.s = fb.s;
- ADD(AL, 0, factor.reg, fb.reg, reg_imm(fb.reg, LSR, fb.s-1));
- break;
- case GGL_ONE_MINUS_SRC_COLOR:
- case GGL_SRC_COLOR:
- factor.s = fragment.s;
- ADD(AL, 0, factor.reg, fragment.reg,
- reg_imm(fragment.reg, LSR, fragment.s-1));
- break;
- case GGL_ONE_MINUS_SRC_ALPHA:
- case GGL_SRC_ALPHA:
- factor.s = src_alpha.s;
- ADD(AL, 0, factor.reg, src_alpha.reg,
- reg_imm(src_alpha.reg, LSR, src_alpha.s-1));
- break;
- case GGL_ONE_MINUS_DST_ALPHA:
- case GGL_DST_ALPHA:
- // XXX: should be precomputed
- extract(factor, dst_pixel, GGLFormat::ALPHA);
- ADD(AL, 0, factor.reg, factor.reg,
- reg_imm(factor.reg, LSR, factor.s-1));
- break;
- case GGL_SRC_ALPHA_SATURATE:
- // XXX: should be precomputed
- // XXX: f = min(As, 1-Ad)
- // btw, we're guaranteed that Ad's size is <= 8, because
- // it's extracted from the framebuffer
- break;
- }
-
- switch(f) {
- case GGL_ONE_MINUS_DST_COLOR:
- case GGL_ONE_MINUS_SRC_COLOR:
- case GGL_ONE_MINUS_DST_ALPHA:
- case GGL_ONE_MINUS_SRC_ALPHA:
- RSB(AL, 0, factor.reg, factor.reg, imm((1<<factor.s)));
- }
-
- // don't need more than 8-bits for the blend factor
- // and this will prevent overflows in the multiplies later
- if (factor.s > 8) {
- MOV(AL, 0, factor.reg, reg_imm(factor.reg, LSR, factor.s-8));
- factor.s = 8;
- }
-}
-
-int GGLAssembler::blending_codes(int fs, int fd)
-{
- int blending = 0;
- switch(fs) {
- case GGL_ONE:
- blending |= BLEND_SRC;
- break;
-
- case GGL_ONE_MINUS_DST_COLOR:
- case GGL_DST_COLOR:
- blending |= FACTOR_DST|BLEND_SRC;
- break;
- case GGL_ONE_MINUS_DST_ALPHA:
- case GGL_DST_ALPHA:
- // no need to extract 'component' from the destination
- // for the blend factor, because we need ALPHA only.
- blending |= BLEND_SRC;
- break;
-
- case GGL_ONE_MINUS_SRC_COLOR:
- case GGL_SRC_COLOR:
- blending |= FACTOR_SRC|BLEND_SRC;
- break;
- case GGL_ONE_MINUS_SRC_ALPHA:
- case GGL_SRC_ALPHA:
- case GGL_SRC_ALPHA_SATURATE:
- blending |= FACTOR_SRC|BLEND_SRC;
- break;
- }
- switch(fd) {
- case GGL_ONE:
- blending |= BLEND_DST;
- break;
-
- case GGL_ONE_MINUS_DST_COLOR:
- case GGL_DST_COLOR:
- blending |= FACTOR_DST|BLEND_DST;
- break;
- case GGL_ONE_MINUS_DST_ALPHA:
- case GGL_DST_ALPHA:
- blending |= FACTOR_DST|BLEND_DST;
- break;
-
- case GGL_ONE_MINUS_SRC_COLOR:
- case GGL_SRC_COLOR:
- blending |= FACTOR_SRC|BLEND_DST;
- break;
- case GGL_ONE_MINUS_SRC_ALPHA:
- case GGL_SRC_ALPHA:
- // no need to extract 'component' from the source
- // for the blend factor, because we need ALPHA only.
- blending |= BLEND_DST;
- break;
- }
- return blending;
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::build_blendFOneMinusF(
- component_t& temp,
- const integer_t& factor,
- const integer_t& fragment,
- const integer_t& fb)
-{
- // R = S*f + D*(1-f) = (S-D)*f + D
- Scratch scratches(registerFile());
- // compute S-D
- integer_t diff(fragment.flags & CORRUPTIBLE ?
- fragment.reg : scratches.obtain(), fb.size(), CORRUPTIBLE);
- const int shift = fragment.size() - fb.size();
- if (shift>0) RSB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSR, shift));
- else if (shift<0) RSB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSL,-shift));
- else RSB(AL, 0, diff.reg, fb.reg, fragment.reg);
- mul_factor_add(temp, diff, factor, component_t(fb));
-}
-
-void GGLAssembler::build_blendOneMinusFF(
- component_t& temp,
- const integer_t& factor,
- const integer_t& fragment,
- const integer_t& fb)
-{
- // R = S*f + D*(1-f) = (S-D)*f + D
- Scratch scratches(registerFile());
- // compute D-S
- integer_t diff(fb.flags & CORRUPTIBLE ?
- fb.reg : scratches.obtain(), fb.size(), CORRUPTIBLE);
- const int shift = fragment.size() - fb.size();
- if (shift>0) SUB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSR, shift));
- else if (shift<0) SUB(AL, 0, diff.reg, fb.reg, reg_imm(fragment.reg, LSL,-shift));
- else SUB(AL, 0, diff.reg, fb.reg, fragment.reg);
- mul_factor_add(temp, diff, factor, component_t(fragment));
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::mul_factor( component_t& d,
- const integer_t& v,
- const integer_t& f)
-{
- int vs = v.size();
- int fs = f.size();
- int ms = vs+fs;
-
- // XXX: we could have special cases for 1 bit mul
-
- // all this code below to use the best multiply instruction
- // wrt the parameters size. We take advantage of the fact
- // that the 16-bits multiplies allow a 16-bit shift
- // The trick is that we just make sure that we have at least 8-bits
- // per component (which is enough for a 8 bits display).
-
- int xy;
- int vshift = 0;
- int fshift = 0;
- int smulw = 0;
-
- if (vs<16) {
- if (fs<16) {
- xy = xyBB;
- } else if (GGL_BETWEEN(fs, 24, 31)) {
- ms -= 16;
- xy = xyTB;
- } else {
- // eg: 15 * 18 -> 15 * 15
- fshift = fs - 15;
- ms -= fshift;
- xy = xyBB;
- }
- } else if (GGL_BETWEEN(vs, 24, 31)) {
- if (fs<16) {
- ms -= 16;
- xy = xyTB;
- } else if (GGL_BETWEEN(fs, 24, 31)) {
- ms -= 32;
- xy = xyTT;
- } else {
- // eg: 24 * 18 -> 8 * 18
- fshift = fs - 15;
- ms -= 16 + fshift;
- xy = xyTB;
- }
- } else {
- if (fs<16) {
- // eg: 18 * 15 -> 15 * 15
- vshift = vs - 15;
- ms -= vshift;
- xy = xyBB;
- } else if (GGL_BETWEEN(fs, 24, 31)) {
- // eg: 18 * 24 -> 15 * 8
- vshift = vs - 15;
- ms -= 16 + vshift;
- xy = xyBT;
- } else {
- // eg: 18 * 18 -> (15 * 18)>>16
- fshift = fs - 15;
- ms -= 16 + fshift;
- xy = yB; //XXX SMULWB
- smulw = 1;
- }
- }
-
- ALOGE_IF(ms>=32, "mul_factor overflow vs=%d, fs=%d", vs, fs);
-
- int vreg = v.reg;
- int freg = f.reg;
- if (vshift) {
- MOV(AL, 0, d.reg, reg_imm(vreg, LSR, vshift));
- vreg = d.reg;
- }
- if (fshift) {
- MOV(AL, 0, d.reg, reg_imm(vreg, LSR, fshift));
- freg = d.reg;
- }
- if (smulw) SMULW(AL, xy, d.reg, vreg, freg);
- else SMUL(AL, xy, d.reg, vreg, freg);
-
-
- d.h = ms;
- if (mDithering) {
- d.l = 0;
- } else {
- d.l = fs;
- d.flags |= CLEAR_LO;
- }
-}
-
-void GGLAssembler::mul_factor_add( component_t& d,
- const integer_t& v,
- const integer_t& f,
- const component_t& a)
-{
- // XXX: we could have special cases for 1 bit mul
- Scratch scratches(registerFile());
-
- int vs = v.size();
- int fs = f.size();
- int as = a.h;
- int ms = vs+fs;
-
- ALOGE_IF(ms>=32, "mul_factor_add overflow vs=%d, fs=%d, as=%d", vs, fs, as);
-
- integer_t add(a.reg, a.h, a.flags);
-
- // 'a' is a component_t but it is guaranteed to have
- // its high bits set to 0. However in the dithering case,
- // we can't get away with truncating the potentially bad bits
- // so extraction is needed.
-
- if ((mDithering) && (a.size() < ms)) {
- // we need to expand a
- if (!(a.flags & CORRUPTIBLE)) {
- // ... but it's not corruptible, so we need to pick a
- // temporary register.
- // Try to uses the destination register first (it's likely
- // to be usable, unless it aliases an input).
- if (d.reg!=a.reg && d.reg!=v.reg && d.reg!=f.reg) {
- add.reg = d.reg;
- } else {
- add.reg = scratches.obtain();
- }
- }
- expand(add, a, ms); // extracts and expands
- as = ms;
- }
-
- if (ms == as) {
- if (vs<16 && fs<16) SMLABB(AL, d.reg, v.reg, f.reg, add.reg);
- else MLA(AL, 0, d.reg, v.reg, f.reg, add.reg);
- } else {
- int temp = d.reg;
- if (temp == add.reg) {
- // the mul will modify add.reg, we need an intermediary reg
- if (v.flags & CORRUPTIBLE) temp = v.reg;
- else if (f.flags & CORRUPTIBLE) temp = f.reg;
- else temp = scratches.obtain();
- }
-
- if (vs<16 && fs<16) SMULBB(AL, temp, v.reg, f.reg);
- else MUL(AL, 0, temp, v.reg, f.reg);
-
- if (ms>as) {
- ADD(AL, 0, d.reg, temp, reg_imm(add.reg, LSL, ms-as));
- } else if (ms<as) {
- // not sure if we should expand the mul instead?
- ADD(AL, 0, d.reg, temp, reg_imm(add.reg, LSR, as-ms));
- }
- }
-
- d.h = ms;
- if (mDithering) {
- d.l = a.l;
- } else {
- d.l = fs>a.l ? fs : a.l;
- d.flags |= CLEAR_LO;
- }
-}
-
-void GGLAssembler::component_add(component_t& d,
- const integer_t& dst, const integer_t& src)
-{
- // here we're guaranteed that fragment.size() >= fb.size()
- const int shift = src.size() - dst.size();
- if (!shift) {
- ADD(AL, 0, d.reg, src.reg, dst.reg);
- } else {
- ADD(AL, 0, d.reg, src.reg, reg_imm(dst.reg, LSL, shift));
- }
-
- d.h = src.size();
- if (mDithering) {
- d.l = 0;
- } else {
- d.l = shift;
- d.flags |= CLEAR_LO;
- }
-}
-
-void GGLAssembler::component_sat(const component_t& v)
-{
- const int one = ((1<<v.size())-1)<<v.l;
- CMP(AL, v.reg, imm( 1<<v.h ));
- if (isValidImmediate(one)) {
- MOV(HS, 0, v.reg, imm( one ));
- } else if (isValidImmediate(~one)) {
- MVN(HS, 0, v.reg, imm( ~one ));
- } else {
- MOV(HS, 0, v.reg, imm( 1<<v.h ));
- SUB(HS, 0, v.reg, v.reg, imm( 1<<v.l ));
- }
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/disassem.c b/libpixelflinger/codeflinger/disassem.c
deleted file mode 100644
index 5cbd63d..0000000
--- a/libpixelflinger/codeflinger/disassem.c
+++ /dev/null
@@ -1,714 +0,0 @@
-/* $NetBSD: disassem.c,v 1.14 2003/03/27 16:58:36 mycroft Exp $ */
-
-/*-
- * Copyright (c) 1996 Mark Brinicombe.
- * Copyright (c) 1996 Brini.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Brini.
- * 4. The name of the company nor the name of the author may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * RiscBSD kernel project
- *
- * db_disasm.c
- *
- * Kernel disassembler
- *
- * Created : 10/02/96
- *
- * Structured after the sparc/sparc/db_disasm.c by David S. Miller &
- * Paul Kranenburg
- *
- * This code is not complete. Not all instructions are disassembled.
- */
-
-#include <sys/cdefs.h>
-//__FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/arm/arm/disassem.c,v 1.2 2005/01/05 21:58:47 imp Exp $");
-#include <sys/param.h>
-#include <stdio.h>
-
-#include "disassem.h"
-#include "armreg.h"
-//#include <ddb/ddb.h>
-
-/*
- * General instruction format
- *
- * insn[cc][mod] [operands]
- *
- * Those fields with an uppercase format code indicate that the field
- * follows directly after the instruction before the separator i.e.
- * they modify the instruction rather than just being an operand to
- * the instruction. The only exception is the writeback flag which
- * follows a operand.
- *
- *
- * 2 - print Operand 2 of a data processing instruction
- * d - destination register (bits 12-15)
- * n - n register (bits 16-19)
- * s - s register (bits 8-11)
- * o - indirect register rn (bits 16-19) (used by swap)
- * m - m register (bits 0-3)
- * a - address operand of ldr/str instruction
- * e - address operand of ldrh/strh instruction
- * l - register list for ldm/stm instruction
- * f - 1st fp operand (register) (bits 12-14)
- * g - 2nd fp operand (register) (bits 16-18)
- * h - 3rd fp operand (register/immediate) (bits 0-4)
- * j - xtb rotate literal (bits 10-11)
- * i - bfx lsb literal (bits 7-11)
- * w - bfx width literal (bits 16-20)
- * b - branch address
- * t - thumb branch address (bits 24, 0-23)
- * k - breakpoint comment (bits 0-3, 8-19)
- * X - block transfer type
- * Y - block transfer type (r13 base)
- * c - comment field bits(0-23)
- * p - saved or current status register
- * F - PSR transfer fields
- * D - destination-is-r15 (P) flag on TST, TEQ, CMP, CMN
- * L - co-processor transfer size
- * S - set status flag
- * P - fp precision
- * Q - fp precision (for ldf/stf)
- * R - fp rounding
- * v - co-processor data transfer registers + addressing mode
- * W - writeback flag
- * x - instruction in hex
- * # - co-processor number
- * y - co-processor data processing registers
- * z - co-processor register transfer registers
- */
-
-struct arm32_insn {
- u_int mask;
- u_int pattern;
- char* name;
- char* format;
-};
-
-static const struct arm32_insn arm32_i[] = {
- { 0x0fffffff, 0x0ff00000, "imb", "c" }, /* Before swi */
- { 0x0fffffff, 0x0ff00001, "imbrange", "c" }, /* Before swi */
- { 0x0f000000, 0x0f000000, "swi", "c" },
- { 0xfe000000, 0xfa000000, "blx", "t" }, /* Before b and bl */
- { 0x0f000000, 0x0a000000, "b", "b" },
- { 0x0f000000, 0x0b000000, "bl", "b" },
- { 0x0fe000f0, 0x00000090, "mul", "Snms" },
- { 0x0fe000f0, 0x00200090, "mla", "Snmsd" },
- { 0x0fe000f0, 0x00800090, "umull", "Sdnms" },
- { 0x0fe000f0, 0x00c00090, "smull", "Sdnms" },
- { 0x0fe000f0, 0x00a00090, "umlal", "Sdnms" },
- { 0x0fe000f0, 0x00e00090, "smlal", "Sdnms" },
- { 0x0fff03f0, 0x06cf0070, "uxtb16", "dmj" },
- { 0x0fe00070, 0x07e00050, "ubfx", "dmiw" },
- { 0x0d700000, 0x04200000, "strt", "daW" },
- { 0x0d700000, 0x04300000, "ldrt", "daW" },
- { 0x0d700000, 0x04600000, "strbt", "daW" },
- { 0x0d700000, 0x04700000, "ldrbt", "daW" },
- { 0x0c500000, 0x04000000, "str", "daW" },
- { 0x0c500000, 0x04100000, "ldr", "daW" },
- { 0x0c500000, 0x04400000, "strb", "daW" },
- { 0x0c500000, 0x04500000, "ldrb", "daW" },
- { 0x0e1f0000, 0x080d0000, "stm", "YnWl" },/* separate out r13 base */
- { 0x0e1f0000, 0x081d0000, "ldm", "YnWl" },/* separate out r13 base */
- { 0x0e100000, 0x08000000, "stm", "XnWl" },
- { 0x0e100000, 0x08100000, "ldm", "XnWl" },
- { 0x0e1000f0, 0x00100090, "ldrb", "deW" },
- { 0x0e1000f0, 0x00000090, "strb", "deW" },
- { 0x0e1000f0, 0x001000d0, "ldrsb", "deW" },
- { 0x0e1000f0, 0x001000b0, "ldrh", "deW" },
- { 0x0e1000f0, 0x000000b0, "strh", "deW" },
- { 0x0e1000f0, 0x001000f0, "ldrsh", "deW" },
- { 0x0f200090, 0x00200090, "und", "x" }, /* Before data processing */
- { 0x0e1000d0, 0x000000d0, "und", "x" }, /* Before data processing */
- { 0x0ff00ff0, 0x01000090, "swp", "dmo" },
- { 0x0ff00ff0, 0x01400090, "swpb", "dmo" },
- { 0x0fbf0fff, 0x010f0000, "mrs", "dp" }, /* Before data processing */
- { 0x0fb0fff0, 0x0120f000, "msr", "pFm" },/* Before data processing */
- { 0x0fb0f000, 0x0320f000, "msr", "pF2" },/* Before data processing */
- { 0x0ffffff0, 0x012fff10, "bx", "m" },
- { 0x0fff0ff0, 0x016f0f10, "clz", "dm" },
- { 0x0ffffff0, 0x012fff30, "blx", "m" },
- { 0xfff000f0, 0xe1200070, "bkpt", "k" },
- { 0x0de00000, 0x00000000, "and", "Sdn2" },
- { 0x0de00000, 0x00200000, "eor", "Sdn2" },
- { 0x0de00000, 0x00400000, "sub", "Sdn2" },
- { 0x0de00000, 0x00600000, "rsb", "Sdn2" },
- { 0x0de00000, 0x00800000, "add", "Sdn2" },
- { 0x0de00000, 0x00a00000, "adc", "Sdn2" },
- { 0x0de00000, 0x00c00000, "sbc", "Sdn2" },
- { 0x0de00000, 0x00e00000, "rsc", "Sdn2" },
- { 0x0df00000, 0x01100000, "tst", "Dn2" },
- { 0x0df00000, 0x01300000, "teq", "Dn2" },
- { 0x0df00000, 0x01500000, "cmp", "Dn2" },
- { 0x0df00000, 0x01700000, "cmn", "Dn2" },
- { 0x0de00000, 0x01800000, "orr", "Sdn2" },
- { 0x0de00000, 0x01a00000, "mov", "Sd2" },
- { 0x0de00000, 0x01c00000, "bic", "Sdn2" },
- { 0x0de00000, 0x01e00000, "mvn", "Sd2" },
- { 0x0ff08f10, 0x0e000100, "adf", "PRfgh" },
- { 0x0ff08f10, 0x0e100100, "muf", "PRfgh" },
- { 0x0ff08f10, 0x0e200100, "suf", "PRfgh" },
- { 0x0ff08f10, 0x0e300100, "rsf", "PRfgh" },
- { 0x0ff08f10, 0x0e400100, "dvf", "PRfgh" },
- { 0x0ff08f10, 0x0e500100, "rdf", "PRfgh" },
- { 0x0ff08f10, 0x0e600100, "pow", "PRfgh" },
- { 0x0ff08f10, 0x0e700100, "rpw", "PRfgh" },
- { 0x0ff08f10, 0x0e800100, "rmf", "PRfgh" },
- { 0x0ff08f10, 0x0e900100, "fml", "PRfgh" },
- { 0x0ff08f10, 0x0ea00100, "fdv", "PRfgh" },
- { 0x0ff08f10, 0x0eb00100, "frd", "PRfgh" },
- { 0x0ff08f10, 0x0ec00100, "pol", "PRfgh" },
- { 0x0f008f10, 0x0e000100, "fpbop", "PRfgh" },
- { 0x0ff08f10, 0x0e008100, "mvf", "PRfh" },
- { 0x0ff08f10, 0x0e108100, "mnf", "PRfh" },
- { 0x0ff08f10, 0x0e208100, "abs", "PRfh" },
- { 0x0ff08f10, 0x0e308100, "rnd", "PRfh" },
- { 0x0ff08f10, 0x0e408100, "sqt", "PRfh" },
- { 0x0ff08f10, 0x0e508100, "log", "PRfh" },
- { 0x0ff08f10, 0x0e608100, "lgn", "PRfh" },
- { 0x0ff08f10, 0x0e708100, "exp", "PRfh" },
- { 0x0ff08f10, 0x0e808100, "sin", "PRfh" },
- { 0x0ff08f10, 0x0e908100, "cos", "PRfh" },
- { 0x0ff08f10, 0x0ea08100, "tan", "PRfh" },
- { 0x0ff08f10, 0x0eb08100, "asn", "PRfh" },
- { 0x0ff08f10, 0x0ec08100, "acs", "PRfh" },
- { 0x0ff08f10, 0x0ed08100, "atn", "PRfh" },
- { 0x0f008f10, 0x0e008100, "fpuop", "PRfh" },
- { 0x0e100f00, 0x0c000100, "stf", "QLv" },
- { 0x0e100f00, 0x0c100100, "ldf", "QLv" },
- { 0x0ff00f10, 0x0e000110, "flt", "PRgd" },
- { 0x0ff00f10, 0x0e100110, "fix", "PRdh" },
- { 0x0ff00f10, 0x0e200110, "wfs", "d" },
- { 0x0ff00f10, 0x0e300110, "rfs", "d" },
- { 0x0ff00f10, 0x0e400110, "wfc", "d" },
- { 0x0ff00f10, 0x0e500110, "rfc", "d" },
- { 0x0ff0ff10, 0x0e90f110, "cmf", "PRgh" },
- { 0x0ff0ff10, 0x0eb0f110, "cnf", "PRgh" },
- { 0x0ff0ff10, 0x0ed0f110, "cmfe", "PRgh" },
- { 0x0ff0ff10, 0x0ef0f110, "cnfe", "PRgh" },
- { 0xff100010, 0xfe000010, "mcr2", "#z" },
- { 0x0f100010, 0x0e000010, "mcr", "#z" },
- { 0xff100010, 0xfe100010, "mrc2", "#z" },
- { 0x0f100010, 0x0e100010, "mrc", "#z" },
- { 0xff000010, 0xfe000000, "cdp2", "#y" },
- { 0x0f000010, 0x0e000000, "cdp", "#y" },
- { 0xfe100090, 0xfc100000, "ldc2", "L#v" },
- { 0x0e100090, 0x0c100000, "ldc", "L#v" },
- { 0xfe100090, 0xfc000000, "stc2", "L#v" },
- { 0x0e100090, 0x0c000000, "stc", "L#v" },
- { 0xf550f000, 0xf550f000, "pld", "ne" },
- { 0x0ff00ff0, 0x01000050, "qaad", "dmn" },
- { 0x0ff00ff0, 0x01400050, "qdaad", "dmn" },
- { 0x0ff00ff0, 0x01600050, "qdsub", "dmn" },
- { 0x0ff00ff0, 0x01200050, "dsub", "dmn" },
- { 0x0ff000f0, 0x01000080, "smlabb", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x010000a0, "smlatb", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x010000c0, "smlabt", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x010000e0, "smlatt", "nmsd" }, // d & n inverted!!
- { 0x0ff000f0, 0x01400080, "smlalbb","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x014000a0, "smlaltb","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x014000c0, "smlalbt","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x014000e0, "smlaltt","ndms" }, // d & n inverted!!
- { 0x0ff000f0, 0x01200080, "smlawb", "nmsd" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x012000a0, "smulwb","nms" }, // d & n inverted!!
- { 0x0ff000f0, 0x012000c0, "smlawt", "nmsd" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x012000e0, "smulwt","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x01600080, "smulbb","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x016000a0, "smultb","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x016000c0, "smulbt","nms" }, // d & n inverted!!
- { 0x0ff0f0f0, 0x016000e0, "smultt","nms" }, // d & n inverted!!
- { 0x00000000, 0x00000000, NULL, NULL }
-};
-
-static char const arm32_insn_conditions[][4] = {
- "eq", "ne", "cs", "cc",
- "mi", "pl", "vs", "vc",
- "hi", "ls", "ge", "lt",
- "gt", "le", "", "nv"
-};
-
-static char const insn_block_transfers[][4] = {
- "da", "ia", "db", "ib"
-};
-
-static char const insn_stack_block_transfers[][4] = {
- "ed", "ea", "fd", "fa"
-};
-
-static char const op_shifts[][4] = {
- "lsl", "lsr", "asr", "ror"
-};
-
-static char const insn_fpa_rounding[][2] = {
- "", "p", "m", "z"
-};
-
-static char const insn_fpa_precision[][2] = {
- "s", "d", "e", "p"
-};
-
-static char const insn_fpaconstants[][8] = {
- "0.0", "1.0", "2.0", "3.0",
- "4.0", "5.0", "0.5", "10.0"
-};
-
-#define insn_condition(x) arm32_insn_conditions[((x) >> 28) & 0x0f]
-#define insn_blktrans(x) insn_block_transfers[((x) >> 23) & 3]
-#define insn_stkblktrans(x) insn_stack_block_transfers[(3*(((x) >> 20)&1))^(((x) >> 23)&3)]
-#define op2_shift(x) op_shifts[((x) >> 5) & 3]
-#define insn_fparnd(x) insn_fpa_rounding[((x) >> 5) & 0x03]
-#define insn_fpaprec(x) insn_fpa_precision[((((x) >> 18) & 2)|((x) >> 7)) & 1]
-#define insn_fpaprect(x) insn_fpa_precision[((((x) >> 21) & 2)|((x) >> 15)) & 1]
-#define insn_fpaimm(x) insn_fpaconstants[(x) & 0x07]
-
-/* Local prototypes */
-static void disasm_register_shift(const disasm_interface_t *di, u_int insn);
-static void disasm_print_reglist(const disasm_interface_t *di, u_int insn);
-static void disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn,
- u_int loc);
-static void disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn,
- u_int loc);
-static void disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn,
- u_int loc);
-static u_int disassemble_readword(u_int address);
-static void disassemble_printaddr(u_int address);
-
-u_int
-disasm(const disasm_interface_t *di, u_int loc, int __unused altfmt)
-{
- const struct arm32_insn *i_ptr = &arm32_i[0];
- u_int insn = di->di_readword(loc);
- int matchp = 0;
- int branch;
- char* f_ptr;
- int fmt = 0;
-
-/* di->di_printf("loc=%08x insn=%08x : ", loc, insn);*/
-
- while (i_ptr->name) {
- if ((insn & i_ptr->mask) == i_ptr->pattern) {
- matchp = 1;
- break;
- }
- i_ptr++;
- }
-
- if (!matchp) {
- di->di_printf("und%s\t%08x\n", insn_condition(insn), insn);
- return(loc + INSN_SIZE);
- }
-
- /* If instruction forces condition code, don't print it. */
- if ((i_ptr->mask & 0xf0000000) == 0xf0000000)
- di->di_printf("%s", i_ptr->name);
- else
- di->di_printf("%s%s", i_ptr->name, insn_condition(insn));
-
- f_ptr = i_ptr->format;
-
- /* Insert tab if there are no instruction modifiers */
-
- if (*(f_ptr) < 'A' || *(f_ptr) > 'Z') {
- ++fmt;
- di->di_printf("\t");
- }
-
- while (*f_ptr) {
- switch (*f_ptr) {
- /* 2 - print Operand 2 of a data processing instruction */
- case '2':
- if (insn & 0x02000000) {
- int rotate= ((insn >> 7) & 0x1e);
-
- di->di_printf("#0x%08x",
- (insn & 0xff) << (32 - rotate) |
- (insn & 0xff) >> rotate);
- } else {
- disasm_register_shift(di, insn);
- }
- break;
- /* d - destination register (bits 12-15) */
- case 'd':
- di->di_printf("r%d", ((insn >> 12) & 0x0f));
- break;
- /* D - insert 'p' if Rd is R15 */
- case 'D':
- if (((insn >> 12) & 0x0f) == 15)
- di->di_printf("p");
- break;
- /* n - n register (bits 16-19) */
- case 'n':
- di->di_printf("r%d", ((insn >> 16) & 0x0f));
- break;
- /* s - s register (bits 8-11) */
- case 's':
- di->di_printf("r%d", ((insn >> 8) & 0x0f));
- break;
- /* o - indirect register rn (bits 16-19) (used by swap) */
- case 'o':
- di->di_printf("[r%d]", ((insn >> 16) & 0x0f));
- break;
- /* m - m register (bits 0-4) */
- case 'm':
- di->di_printf("r%d", ((insn >> 0) & 0x0f));
- break;
- /* a - address operand of ldr/str instruction */
- case 'a':
- disasm_insn_ldrstr(di, insn, loc);
- break;
- /* e - address operand of ldrh/strh instruction */
- case 'e':
- disasm_insn_ldrhstrh(di, insn, loc);
- break;
- /* l - register list for ldm/stm instruction */
- case 'l':
- disasm_print_reglist(di, insn);
- break;
- /* f - 1st fp operand (register) (bits 12-14) */
- case 'f':
- di->di_printf("f%d", (insn >> 12) & 7);
- break;
- /* g - 2nd fp operand (register) (bits 16-18) */
- case 'g':
- di->di_printf("f%d", (insn >> 16) & 7);
- break;
- /* h - 3rd fp operand (register/immediate) (bits 0-4) */
- case 'h':
- if (insn & (1 << 3))
- di->di_printf("#%s", insn_fpaimm(insn));
- else
- di->di_printf("f%d", insn & 7);
- break;
- /* j - xtb rotate literal (bits 10-11) */
- case 'j':
- di->di_printf("ror #%d", ((insn >> 10) & 3) << 3);
- break;
- /* i - bfx lsb literal (bits 7-11) */
- case 'i':
- di->di_printf("#%d", (insn >> 7) & 31);
- break;
- /* w - bfx width literal (bits 16-20) */
- case 'w':
- di->di_printf("#%d", 1 + ((insn >> 16) & 31));
- break;
- /* b - branch address */
- case 'b':
- branch = ((insn << 2) & 0x03ffffff);
- if (branch & 0x02000000)
- branch |= 0xfc000000;
- di->di_printaddr(loc + 8 + branch);
- break;
- /* t - blx address */
- case 't':
- branch = ((insn << 2) & 0x03ffffff) |
- (insn >> 23 & 0x00000002);
- if (branch & 0x02000000)
- branch |= 0xfc000000;
- di->di_printaddr(loc + 8 + branch);
- break;
- /* X - block transfer type */
- case 'X':
- di->di_printf("%s", insn_blktrans(insn));
- break;
- /* Y - block transfer type (r13 base) */
- case 'Y':
- di->di_printf("%s", insn_stkblktrans(insn));
- break;
- /* c - comment field bits(0-23) */
- case 'c':
- di->di_printf("0x%08x", (insn & 0x00ffffff));
- break;
- /* k - breakpoint comment (bits 0-3, 8-19) */
- case 'k':
- di->di_printf("0x%04x",
- (insn & 0x000fff00) >> 4 | (insn & 0x0000000f));
- break;
- /* p - saved or current status register */
- case 'p':
- if (insn & 0x00400000)
- di->di_printf("spsr");
- else
- di->di_printf("cpsr");
- break;
- /* F - PSR transfer fields */
- case 'F':
- di->di_printf("_");
- if (insn & (1 << 16))
- di->di_printf("c");
- if (insn & (1 << 17))
- di->di_printf("x");
- if (insn & (1 << 18))
- di->di_printf("s");
- if (insn & (1 << 19))
- di->di_printf("f");
- break;
- /* B - byte transfer flag */
- case 'B':
- if (insn & 0x00400000)
- di->di_printf("b");
- break;
- /* L - co-processor transfer size */
- case 'L':
- if (insn & (1 << 22))
- di->di_printf("l");
- break;
- /* S - set status flag */
- case 'S':
- if (insn & 0x00100000)
- di->di_printf("s");
- break;
- /* P - fp precision */
- case 'P':
- di->di_printf("%s", insn_fpaprec(insn));
- break;
- /* Q - fp precision (for ldf/stf) */
- case 'Q':
- break;
- /* R - fp rounding */
- case 'R':
- di->di_printf("%s", insn_fparnd(insn));
- break;
- /* W - writeback flag */
- case 'W':
- if (insn & (1 << 21))
- di->di_printf("!");
- break;
- /* # - co-processor number */
- case '#':
- di->di_printf("p%d", (insn >> 8) & 0x0f);
- break;
- /* v - co-processor data transfer registers+addressing mode */
- case 'v':
- disasm_insn_ldcstc(di, insn, loc);
- break;
- /* x - instruction in hex */
- case 'x':
- di->di_printf("0x%08x", insn);
- break;
- /* y - co-processor data processing registers */
- case 'y':
- di->di_printf("%d, ", (insn >> 20) & 0x0f);
-
- di->di_printf("c%d, c%d, c%d", (insn >> 12) & 0x0f,
- (insn >> 16) & 0x0f, insn & 0x0f);
-
- di->di_printf(", %d", (insn >> 5) & 0x07);
- break;
- /* z - co-processor register transfer registers */
- case 'z':
- di->di_printf("%d, ", (insn >> 21) & 0x07);
- di->di_printf("r%d, c%d, c%d, %d",
- (insn >> 12) & 0x0f, (insn >> 16) & 0x0f,
- insn & 0x0f, (insn >> 5) & 0x07);
-
-/* if (((insn >> 5) & 0x07) != 0)
- di->di_printf(", %d", (insn >> 5) & 0x07);*/
- break;
- default:
- di->di_printf("[%c - unknown]", *f_ptr);
- break;
- }
- if (*(f_ptr+1) >= 'A' && *(f_ptr+1) <= 'Z')
- ++f_ptr;
- else if (*(++f_ptr)) {
- ++fmt;
- if (fmt == 1)
- di->di_printf("\t");
- else
- di->di_printf(", ");
- }
- };
-
- di->di_printf("\n");
-
- return(loc + INSN_SIZE);
-}
-
-
-static void
-disasm_register_shift(const disasm_interface_t *di, u_int insn)
-{
- di->di_printf("r%d", (insn & 0x0f));
- if ((insn & 0x00000ff0) == 0)
- ;
- else if ((insn & 0x00000ff0) == 0x00000060)
- di->di_printf(", rrx");
- else {
- if (insn & 0x10)
- di->di_printf(", %s r%d", op2_shift(insn),
- (insn >> 8) & 0x0f);
- else
- di->di_printf(", %s #%d", op2_shift(insn),
- (insn >> 7) & 0x1f);
- }
-}
-
-
-static void
-disasm_print_reglist(const disasm_interface_t *di, u_int insn)
-{
- int loop;
- int start;
- int comma;
-
- di->di_printf("{");
- start = -1;
- comma = 0;
-
- for (loop = 0; loop < 17; ++loop) {
- if (start != -1) {
- if (loop == 16 || !(insn & (1 << loop))) {
- if (comma)
- di->di_printf(", ");
- else
- comma = 1;
- if (start == loop - 1)
- di->di_printf("r%d", start);
- else
- di->di_printf("r%d-r%d", start, loop - 1);
- start = -1;
- }
- } else {
- if (insn & (1 << loop))
- start = loop;
- }
- }
- di->di_printf("}");
-
- if (insn & (1 << 22))
- di->di_printf("^");
-}
-
-static void
-disasm_insn_ldrstr(const disasm_interface_t *di, u_int insn, u_int loc)
-{
- int offset;
-
- offset = insn & 0xfff;
- if ((insn & 0x032f0000) == 0x010f0000) {
- /* rA = pc, immediate index */
- if (insn & 0x00800000)
- loc += offset;
- else
- loc -= offset;
- di->di_printaddr(loc + 8);
- } else {
- di->di_printf("[r%d", (insn >> 16) & 0x0f);
- if ((insn & 0x03000fff) != 0x01000000) {
- di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
- if (!(insn & 0x00800000))
- di->di_printf("-");
- if (insn & (1 << 25))
- disasm_register_shift(di, insn);
- else
- di->di_printf("#0x%03x", offset);
- }
- if (insn & (1 << 24))
- di->di_printf("]");
- }
-}
-
-static void
-disasm_insn_ldrhstrh(const disasm_interface_t *di, u_int insn, u_int loc)
-{
- int offset;
-
- offset = ((insn & 0xf00) >> 4) | (insn & 0xf);
- if ((insn & 0x004f0000) == 0x004f0000) {
- /* rA = pc, immediate index */
- if (insn & 0x00800000)
- loc += offset;
- else
- loc -= offset;
- di->di_printaddr(loc + 8);
- } else {
- di->di_printf("[r%d", (insn >> 16) & 0x0f);
- if ((insn & 0x01400f0f) != 0x01400000) {
- di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
- if (!(insn & 0x00800000))
- di->di_printf("-");
- if (insn & (1 << 22))
- di->di_printf("#0x%02x", offset);
- else
- di->di_printf("r%d", (insn & 0x0f));
- }
- if (insn & (1 << 24))
- di->di_printf("]");
- }
-}
-
-static void
-disasm_insn_ldcstc(const disasm_interface_t *di, u_int insn, u_int __unused loc)
-{
- if (((insn >> 8) & 0xf) == 1)
- di->di_printf("f%d, ", (insn >> 12) & 0x07);
- else
- di->di_printf("c%d, ", (insn >> 12) & 0x0f);
-
- di->di_printf("[r%d", (insn >> 16) & 0x0f);
-
- di->di_printf("%s, ", (insn & (1 << 24)) ? "" : "]");
-
- if (!(insn & (1 << 23)))
- di->di_printf("-");
-
- di->di_printf("#0x%03x", (insn & 0xff) << 2);
-
- if (insn & (1 << 24))
- di->di_printf("]");
-
- if (insn & (1 << 21))
- di->di_printf("!");
-}
-
-static u_int
-disassemble_readword(u_int address)
-{
- return(*((u_int *)address));
-}
-
-static void
-disassemble_printaddr(u_int address)
-{
- printf("0x%08x", address);
-}
-
-static const disasm_interface_t disassemble_di = {
- disassemble_readword, disassemble_printaddr, printf
-};
-
-void
-disassemble(u_int address)
-{
-
- (void)disasm(&disassemble_di, address, 0);
-}
-
-/* End of disassem.c */
diff --git a/libpixelflinger/codeflinger/disassem.h b/libpixelflinger/codeflinger/disassem.h
deleted file mode 100644
index c7c60b6..0000000
--- a/libpixelflinger/codeflinger/disassem.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* $NetBSD: disassem.h,v 1.4 2001/03/04 04:15:58 matt Exp $ */
-
-/*-
- * Copyright (c) 1997 Mark Brinicombe.
- * Copyright (c) 1997 Causality Limited.
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Mark Brinicombe.
- * 4. The name of the company nor the name of the author may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Define the interface structure required by the disassembler.
- *
- * $FreeBSD: /repoman/r/ncvs/src/sys/arm/include/disassem.h,v 1.2 2005/01/05 21:58:48 imp Exp $
- */
-
-#ifndef ANDROID_MACHINE_DISASSEM_H
-#define ANDROID_MACHINE_DISASSEM_H
-
-#include <sys/types.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- u_int (*di_readword)(u_int);
- void (*di_printaddr)(u_int);
- int (*di_printf)(const char *, ...);
-} disasm_interface_t;
-
-/* Prototypes for callable functions */
-
-u_int disasm(const disasm_interface_t *, u_int, int);
-void disassemble(u_int);
-
-#if __cplusplus
-}
-#endif
-
-#endif /* !ANDROID_MACHINE_DISASSEM_H */
diff --git a/libpixelflinger/codeflinger/load_store.cpp b/libpixelflinger/codeflinger/load_store.cpp
deleted file mode 100644
index 4db0a49..0000000
--- a/libpixelflinger/codeflinger/load_store.cpp
+++ /dev/null
@@ -1,384 +0,0 @@
-/* libs/pixelflinger/codeflinger/load_store.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "pixelflinger-code"
-
-#include <assert.h>
-#include <stdio.h>
-
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-void GGLAssembler::store(const pointer_t& addr, const pixel_t& s, uint32_t flags)
-{
- const int bits = addr.size;
- const int inc = (flags & WRITE_BACK)?1:0;
- switch (bits) {
- case 32:
- if (inc) STR(AL, s.reg, addr.reg, immed12_post(4));
- else STR(AL, s.reg, addr.reg);
- break;
- case 24:
- // 24 bits formats are a little special and used only for RGB
- // 0x00BBGGRR is unpacked as R,G,B
- STRB(AL, s.reg, addr.reg, immed12_pre(0));
- MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 8));
- STRB(AL, s.reg, addr.reg, immed12_pre(1));
- MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 8));
- STRB(AL, s.reg, addr.reg, immed12_pre(2));
- if (!(s.flags & CORRUPTIBLE)) {
- MOV(AL, 0, s.reg, reg_imm(s.reg, ROR, 16));
- }
- if (inc)
- ADD(AL, 0, addr.reg, addr.reg, imm(3));
- break;
- case 16:
- if (inc) STRH(AL, s.reg, addr.reg, immed8_post(2));
- else STRH(AL, s.reg, addr.reg);
- break;
- case 8:
- if (inc) STRB(AL, s.reg, addr.reg, immed12_post(1));
- else STRB(AL, s.reg, addr.reg);
- break;
- }
-}
-
-void GGLAssembler::load(const pointer_t& addr, const pixel_t& s, uint32_t flags)
-{
- Scratch scratches(registerFile());
- int s0;
-
- const int bits = addr.size;
- const int inc = (flags & WRITE_BACK)?1:0;
- switch (bits) {
- case 32:
- if (inc) LDR(AL, s.reg, addr.reg, immed12_post(4));
- else LDR(AL, s.reg, addr.reg);
- break;
- case 24:
- // 24 bits formats are a little special and used only for RGB
- // R,G,B is packed as 0x00BBGGRR
- s0 = scratches.obtain();
- if (s.reg != addr.reg) {
- LDRB(AL, s.reg, addr.reg, immed12_pre(0)); // R
- LDRB(AL, s0, addr.reg, immed12_pre(1)); // G
- ORR(AL, 0, s.reg, s.reg, reg_imm(s0, LSL, 8));
- LDRB(AL, s0, addr.reg, immed12_pre(2)); // B
- ORR(AL, 0, s.reg, s.reg, reg_imm(s0, LSL, 16));
- } else {
- int s1 = scratches.obtain();
- LDRB(AL, s1, addr.reg, immed12_pre(0)); // R
- LDRB(AL, s0, addr.reg, immed12_pre(1)); // G
- ORR(AL, 0, s1, s1, reg_imm(s0, LSL, 8));
- LDRB(AL, s0, addr.reg, immed12_pre(2)); // B
- ORR(AL, 0, s.reg, s1, reg_imm(s0, LSL, 16));
- }
- if (inc)
- ADD(AL, 0, addr.reg, addr.reg, imm(3));
- break;
- case 16:
- if (inc) LDRH(AL, s.reg, addr.reg, immed8_post(2));
- else LDRH(AL, s.reg, addr.reg);
- break;
- case 8:
- if (inc) LDRB(AL, s.reg, addr.reg, immed12_post(1));
- else LDRB(AL, s.reg, addr.reg);
- break;
- }
-}
-
-void GGLAssembler::extract(integer_t& d, int s, int h, int l, int bits)
-{
- const int maskLen = h-l;
-
-#ifdef __mips__
- assert(maskLen<=11);
-#else
- assert(maskLen<=8);
-#endif
- assert(h);
-
- if (h != bits) {
- const int mask = ((1<<maskLen)-1) << l;
- if (isValidImmediate(mask)) {
- AND(AL, 0, d.reg, s, imm(mask)); // component = packed & mask;
- } else if (isValidImmediate(~mask)) {
- BIC(AL, 0, d.reg, s, imm(~mask)); // component = packed & mask;
- } else {
- MOV(AL, 0, d.reg, reg_imm(s, LSL, 32-h));
- l += 32-h;
- h = 32;
- }
- s = d.reg;
- }
-
- if (l) {
- MOV(AL, 0, d.reg, reg_imm(s, LSR, l)); // component = packed >> l;
- s = d.reg;
- }
-
- if (s != d.reg) {
- MOV(AL, 0, d.reg, s);
- }
-
- d.s = maskLen;
-}
-
-void GGLAssembler::extract(integer_t& d, const pixel_t& s, int component)
-{
- extract(d, s.reg,
- s.format.c[component].h,
- s.format.c[component].l,
- s.size());
-}
-
-void GGLAssembler::extract(component_t& d, const pixel_t& s, int component)
-{
- integer_t r(d.reg, 32, d.flags);
- extract(r, s.reg,
- s.format.c[component].h,
- s.format.c[component].l,
- s.size());
- d = component_t(r);
-}
-
-
-void GGLAssembler::expand(integer_t& d, const component_t& s, int dbits)
-{
- if (s.l || (s.flags & CLEAR_HI)) {
- extract(d, s.reg, s.h, s.l, 32);
- expand(d, d, dbits);
- } else {
- expand(d, integer_t(s.reg, s.size(), s.flags), dbits);
- }
-}
-
-void GGLAssembler::expand(component_t& d, const component_t& s, int dbits)
-{
- integer_t r(d.reg, 32, d.flags);
- expand(r, s, dbits);
- d = component_t(r);
-}
-
-void GGLAssembler::expand(integer_t& dst, const integer_t& src, int dbits)
-{
- assert(src.size());
-
- int sbits = src.size();
- int s = src.reg;
- int d = dst.reg;
-
- // be sure to set 'dst' after we read 'src' as they may be identical
- dst.s = dbits;
- dst.flags = 0;
-
- if (dbits<=sbits) {
- if (s != d) {
- MOV(AL, 0, d, s);
- }
- return;
- }
-
- if (sbits == 1) {
- RSB(AL, 0, d, s, reg_imm(s, LSL, dbits));
- // d = (s<<dbits) - s;
- return;
- }
-
- if (dbits % sbits) {
- MOV(AL, 0, d, reg_imm(s, LSL, dbits-sbits));
- // d = s << (dbits-sbits);
- dbits -= sbits;
- do {
- ORR(AL, 0, d, d, reg_imm(d, LSR, sbits));
- // d |= d >> sbits;
- dbits -= sbits;
- sbits *= 2;
- } while(dbits>0);
- return;
- }
-
- dbits -= sbits;
- do {
- ORR(AL, 0, d, s, reg_imm(s, LSL, sbits));
- // d |= d<<sbits;
- s = d;
- dbits -= sbits;
- if (sbits*2 < dbits) {
- sbits *= 2;
- }
- } while(dbits>0);
-}
-
-void GGLAssembler::downshift(
- pixel_t& d, int component, component_t s, const reg_t& dither)
-{
- Scratch scratches(registerFile());
-
- int sh = s.h;
- int sl = s.l;
- int maskHiBits = (sh!=32) ? ((s.flags & CLEAR_HI)?1:0) : 0;
- int maskLoBits = (sl!=0) ? ((s.flags & CLEAR_LO)?1:0) : 0;
- int sbits = sh - sl;
-
- int dh = d.format.c[component].h;
- int dl = d.format.c[component].l;
- int dbits = dh - dl;
- int dithering = 0;
-
- ALOGE_IF(sbits<dbits, "sbits (%d) < dbits (%d) in downshift", sbits, dbits);
-
- if (sbits>dbits) {
- // see if we need to dither
- dithering = mDithering;
- }
-
- int ireg = d.reg;
- if (!(d.flags & FIRST)) {
- if (s.flags & CORRUPTIBLE) {
- ireg = s.reg;
- } else {
- ireg = scratches.obtain();
- }
- }
- d.flags &= ~FIRST;
-
- if (maskHiBits) {
- // we need to mask the high bits (and possibly the lowbits too)
- // and we might be able to use immediate mask.
- if (!dithering) {
- // we don't do this if we only have maskLoBits because we can
- // do it more efficiently below (in the case where dl=0)
- const int offset = sh - dbits;
- if (dbits<=8 && offset >= 0) {
- const uint32_t mask = ((1<<dbits)-1) << offset;
- if (isValidImmediate(mask) || isValidImmediate(~mask)) {
- build_and_immediate(ireg, s.reg, mask, 32);
- sl = offset;
- s.reg = ireg;
- sbits = dbits;
- maskLoBits = maskHiBits = 0;
- }
- }
- } else {
- // in the dithering case though, we need to preserve the lower bits
- const uint32_t mask = ((1<<sbits)-1) << sl;
- if (isValidImmediate(mask) || isValidImmediate(~mask)) {
- build_and_immediate(ireg, s.reg, mask, 32);
- s.reg = ireg;
- maskLoBits = maskHiBits = 0;
- }
- }
- }
-
- // XXX: we could special case (maskHiBits & !maskLoBits)
- // like we do for maskLoBits below, but it happens very rarely
- // that we have maskHiBits only and the conditions necessary to lead
- // to better code (like doing d |= s << 24)
-
- if (maskHiBits) {
- MOV(AL, 0, ireg, reg_imm(s.reg, LSL, 32-sh));
- sl += 32-sh;
- sh = 32;
- s.reg = ireg;
- maskHiBits = 0;
- }
-
- // Downsampling should be performed as follows:
- // V * ((1<<dbits)-1) / ((1<<sbits)-1)
- // V * [(1<<dbits)/((1<<sbits)-1) - 1/((1<<sbits)-1)]
- // V * [1/((1<<sbits)-1)>>dbits - 1/((1<<sbits)-1)]
- // V/((1<<(sbits-dbits))-(1>>dbits)) - (V>>sbits)/((1<<sbits)-1)>>sbits
- // V/((1<<(sbits-dbits))-(1>>dbits)) - (V>>sbits)/(1-(1>>sbits))
- //
- // By approximating (1>>dbits) and (1>>sbits) to 0:
- //
- // V>>(sbits-dbits) - V>>sbits
- //
- // A good approximation is V>>(sbits-dbits),
- // but better one (needed for dithering) is:
- //
- // (V>>(sbits-dbits)<<sbits - V)>>sbits
- // (V<<dbits - V)>>sbits
- // (V - V>>dbits)>>(sbits-dbits)
-
- // Dithering is done here
- if (dithering) {
- comment("dithering");
- if (sl) {
- MOV(AL, 0, ireg, reg_imm(s.reg, LSR, sl));
- sh -= sl;
- sl = 0;
- s.reg = ireg;
- }
- // scaling (V-V>>dbits)
- SUB(AL, 0, ireg, s.reg, reg_imm(s.reg, LSR, dbits));
- const int shift = (GGL_DITHER_BITS - (sbits-dbits));
- if (shift>0) ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSR, shift));
- else if (shift<0) ADD(AL, 0, ireg, ireg, reg_imm(dither.reg, LSL,-shift));
- else ADD(AL, 0, ireg, ireg, dither.reg);
- s.reg = ireg;
- }
-
- if ((maskLoBits|dithering) && (sh > dbits)) {
- int shift = sh-dbits;
- if (dl) {
- MOV(AL, 0, ireg, reg_imm(s.reg, LSR, shift));
- if (ireg == d.reg) {
- MOV(AL, 0, d.reg, reg_imm(ireg, LSL, dl));
- } else {
- ORR(AL, 0, d.reg, d.reg, reg_imm(ireg, LSL, dl));
- }
- } else {
- if (ireg == d.reg) {
- MOV(AL, 0, d.reg, reg_imm(s.reg, LSR, shift));
- } else {
- ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSR, shift));
- }
- }
- } else {
- int shift = sh-dh;
- if (shift>0) {
- if (ireg == d.reg) {
- MOV(AL, 0, d.reg, reg_imm(s.reg, LSR, shift));
- } else {
- ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSR, shift));
- }
- } else if (shift<0) {
- if (ireg == d.reg) {
- MOV(AL, 0, d.reg, reg_imm(s.reg, LSL, -shift));
- } else {
- ORR(AL, 0, d.reg, d.reg, reg_imm(s.reg, LSL, -shift));
- }
- } else {
- if (ireg == d.reg) {
- if (s.reg != d.reg) {
- MOV(AL, 0, d.reg, s.reg);
- }
- } else {
- ORR(AL, 0, d.reg, d.reg, s.reg);
- }
- }
- }
-}
-
-}; // namespace android
diff --git a/libpixelflinger/codeflinger/mips64_disassem.c b/libpixelflinger/codeflinger/mips64_disassem.c
deleted file mode 100644
index 8528299..0000000
--- a/libpixelflinger/codeflinger/mips64_disassem.c
+++ /dev/null
@@ -1,584 +0,0 @@
-/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93
- */
-
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-
-#include "mips_opcode.h"
-
-#define __unused __attribute__((__unused__))
-
-static char *sprintf_buffer;
-static int sprintf_buf_len;
-
-typedef uint64_t db_addr_t;
-static void db_printf(const char* fmt, ...);
-
-static const char * const op_name[64] = {
-/* 0 */ "spec", "bcond", "j", "jal", "beq", "bne", "blez", "bgtz",
-/* 8 */ "pop10", "addiu", "slti", "sltiu", "andi", "ori", "xori", "aui",
-/*16 */ "cop0", "cop1", "cop2", "?", "?", "?", "pop26", "pop27",
-/*24 */ "pop30", "daddiu", "?", "?", "?", "daui", "msa", "op37",
-/*32 */ "lb", "lh", "?", "lw", "lbu", "lhu", "?", "lwu",
-/*40 */ "sb", "sh", "?", "sw", "?", "?", "?", "?",
-/*48 */ "?", "lwc1", "bc", "?", "?", "ldc1", "pop66", "ld",
-/*56 */ "?", "swc1", "balc", "pcrel", "?", "sdc1", "pop76", "sd"
-};
-
-static const char * const spec_name[64] = {
-/* 0 */ "sll", "?", "srl", "sra", "sllv", "?", "srlv", "srav",
-/* 8 */ "?", "jalr", "?", "?", "syscall", "break", "sdbpp", "sync",
-/*16 */ "clz", "clo", "dclz", "dclo", "dsllv", "dlsa", "dsrlv", "dsrav",
-/*24 */ "sop30", "sop31", "sop32", "sop33", "sop34", "sop35", "sop36", "sop37",
-/*32 */ "add", "addu", "sub", "subu", "and", "or", "xor", "nor",
-/*40 */ "?", "?", "slt", "sltu", "dadd", "daddu", "dsub", "dsubu",
-/*48 */ "tge", "tgeu", "tlt", "tltu", "teq", "seleqz", "tne", "selnez",
-/*56 */ "dsll", "?", "dsrl", "dsra", "dsll32", "?", "dsrl32", "dsra32"
-};
-
-static const char * const bcond_name[32] = {
-/* 0 */ "bltz", "bgez", "?", "?", "?", "?", "dahi", "?",
-/* 8 */ "?", "?", "?", "?", "?", "?", "?", "?",
-/*16 */ "nal", "bal", "?", "?", "?", "?", "?", "sigrie",
-/*24 */ "?", "?", "?", "?", "?", "?", "dati", "synci",
-};
-
-static const char * const cop1_name[64] = {
-/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg",
-/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
-/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
-/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
-/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27",
-/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
-/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult",
- "fcmp.ole","fcmp.ule",
-/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge",
- "fcmp.le","fcmp.ngt"
-};
-
-static const char * const fmt_name[16] = {
- "s", "d", "e", "fmt3",
- "w", "fmt5", "fmt6", "fmt7",
- "fmt8", "fmt9", "fmta", "fmtb",
- "fmtc", "fmtd", "fmte", "fmtf"
-};
-
-static char * const mips_reg_name[32] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
-};
-
-static char * alt_arm_reg_name[32] = { // hacked names for comparison with ARM code
- "zero", "at", "r0", "r1", "r2", "r3", "r4", "r5",
- "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13",
- "r14", "r15", "at2", "cmp", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
-};
-
-static char * const * reg_name = &mips_reg_name[0];
-
-static const char * const c0_opname[64] = {
- "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
- "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
- "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
- "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
- "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
- "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
- "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
- "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
-};
-
-static const char * const c0_reg[32] = {
- "index", "random", "tlblo0", "tlblo1",
- "context", "pagemask", "wired", "cp0r7",
- "badvaddr", "count", "tlbhi", "compare",
- "status", "cause", "epc", "prid",
- "config", "lladdr", "watchlo", "watchhi",
- "xcontext", "cp0r21", "cp0r22", "debug",
- "depc", "perfcnt", "ecc", "cacheerr",
- "taglo", "taghi", "errepc", "desave"
-};
-
-static void print_addr(db_addr_t);
-db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format);
-
-
-/*
- * Disassemble instruction 'insn' nominally at 'loc'.
- * 'loc' may in fact contain a breakpoint instruction.
- */
-static db_addr_t
-db_disasm_insn(int insn, db_addr_t loc, bool altfmt __unused)
-{
- bool bdslot = false;
- InstFmt i;
-
- i.word = insn;
-
- switch (i.JType.op) {
- case OP_SPECIAL:
- if (i.word == 0) {
- db_printf("nop");
- break;
- }
- if (i.word == 0x0080) {
- db_printf("NIY");
- break;
- }
- if (i.word == 0x00c0) {
- db_printf("NOT IMPL");
- break;
- }
- /* Special cases --------------------------------------------------
- * "addu" is a "move" only in 32-bit mode. What's the correct
- * answer - never decode addu/daddu as "move"?
- */
- if ( (i.RType.func == OP_ADDU && i.RType.rt == 0) ||
- (i.RType.func == OP_OR && i.RType.rt == 0) ) {
- db_printf("move\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rs]);
- break;
- }
-
- if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) {
- db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd],
- reg_name[i.RType.rt], i.RType.shamt);
- break;
- }
- if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) {
- db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd],
- reg_name[i.RType.rt], reg_name[i.RType.rs]);
- break;
- }
-
- if (i.RType.func == OP_SOP30) {
- if (i.RType.shamt == OP_MUL) {
- db_printf("mul");
- } else if (i.RType.shamt == OP_MUH) {
- db_printf("muh");
- }
- db_printf("\t%s,%s,%s", reg_name[i.RType.rd],
- reg_name[i.RType.rs], reg_name[i.RType.rt]);
- break;
- }
- if (i.RType.func == OP_SOP31) {
- if (i.RType.shamt == OP_MUL) {
- db_printf("mulu");
- } else if (i.RType.shamt == OP_MUH) {
- db_printf("muhu");
- }
- db_printf("\t%s,%s,%s", reg_name[i.RType.rd],
- reg_name[i.RType.rs], reg_name[i.RType.rt]);
- break;
- }
-
- if (i.RType.func == OP_JALR && i.RType.rd == 0) {
- db_printf("jr\t%s", reg_name[i.RType.rs]);
- bdslot = true;
- break;
- }
-
- db_printf("%s", spec_name[i.RType.func]);
- switch (i.RType.func) {
- case OP_SLL:
- case OP_SRL:
- case OP_SRA:
- case OP_DSLL:
-
- case OP_DSRL:
- case OP_DSRA:
- case OP_DSLL32:
- case OP_DSRL32:
- case OP_DSRA32:
- db_printf("\t%s,%s,%d",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt],
- i.RType.shamt);
- break;
-
- case OP_SLLV:
- case OP_SRLV:
- case OP_SRAV:
- case OP_DSLLV:
- case OP_DSRLV:
- case OP_DSRAV:
- db_printf("\t%s,%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt],
- reg_name[i.RType.rs]);
- break;
-
- case OP_CLZ:
- case OP_CLO:
- case OP_DCLZ:
- case OP_DCLO:
- db_printf("\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rs]);
- break;
-
- case OP_JALR:
- db_printf("\t");
- if (i.RType.rd != 31) {
- db_printf("%s,", reg_name[i.RType.rd]);
- }
- db_printf("%s", reg_name[i.RType.rs]);
- bdslot = true;
- break;
-
- case OP_SYSCALL:
- case OP_SYNC:
- break;
-
- case OP_BREAK:
- db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
- break;
-
- default:
- db_printf("\t%s,%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rs],
- reg_name[i.RType.rt]);
- }
- break;
-
- case OP_SPECIAL3:
- if (i.RType.func == OP_EXT)
- db_printf("ext\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd+1);
- else if (i.RType.func == OP_DEXT)
- db_printf("dext\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd+1);
- else if (i.RType.func == OP_DEXTM)
- db_printf("dextm\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd+33);
- else if (i.RType.func == OP_DEXTU)
- db_printf("dextu\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt+32,
- i.RType.rd+1);
- else if (i.RType.func == OP_INS)
- db_printf("ins\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd-i.RType.shamt+1);
- else if (i.RType.func == OP_DINS)
- db_printf("dins\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd-i.RType.shamt+1);
- else if (i.RType.func == OP_DINSM)
- db_printf("dinsm\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd-i.RType.shamt+33);
- else if (i.RType.func == OP_DINSU)
- db_printf("dinsu\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt+32,
- i.RType.rd-i.RType.shamt+1);
- else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH)
- db_printf("wsbh\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt]);
- else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEB)
- db_printf("seb\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt]);
- else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEH)
- db_printf("seh\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt]);
- else if (i.RType.func == OP_RDHWR)
- db_printf("rdhwr\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt]);
- else
- db_printf("Unknown");
- break;
-
- case OP_BCOND:
- db_printf("%s\t%s,", bcond_name[i.IType.rt],
- reg_name[i.IType.rs]);
- goto pr_displ;
-
- case OP_BLEZ:
- case OP_BGTZ:
- db_printf("%s\t%s,", op_name[i.IType.op],
- reg_name[i.IType.rs]);
- goto pr_displ;
-
- case OP_BEQ:
- if (i.IType.rs == 0 && i.IType.rt == 0) {
- db_printf("b\t");
- goto pr_displ;
- }
- /* FALLTHROUGH */
- case OP_BNE:
- db_printf("%s\t%s,%s,", op_name[i.IType.op],
- reg_name[i.IType.rs],
- reg_name[i.IType.rt]);
- pr_displ:
- print_addr(loc + 4 + ((short)i.IType.imm << 2));
- bdslot = true;
- break;
-
- case OP_COP0:
- switch (i.RType.rs) {
- case OP_BCx:
- case OP_BCy:
-
- db_printf("bc0%c\t",
- "ft"[i.RType.rt & COPz_BC_TF_MASK]);
- goto pr_displ;
-
- case OP_MT:
- db_printf("mtc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- case OP_DMT:
- db_printf("dmtc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- case OP_MF:
- db_printf("mfc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- case OP_DMF:
- db_printf("dmfc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- default:
- db_printf("%s", c0_opname[i.FRType.func]);
- }
- break;
-
- case OP_COP1:
- switch (i.RType.rs) {
- case OP_BCx:
- case OP_BCy:
- db_printf("bc1%c\t",
- "ft"[i.RType.rt & COPz_BC_TF_MASK]);
- goto pr_displ;
-
- case OP_MT:
- db_printf("mtc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- case OP_MF:
- db_printf("mfc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- case OP_CT:
- db_printf("ctc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- case OP_CF:
- db_printf("cfc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- default:
- db_printf("%s.%s\tf%d,f%d,f%d",
- cop1_name[i.FRType.func],
- fmt_name[i.FRType.fmt],
- i.FRType.fd, i.FRType.fs, i.FRType.ft);
- }
- break;
-
- case OP_J:
- case OP_JAL:
- db_printf("%s\t", op_name[i.JType.op]);
- print_addr((loc & 0xFFFFFFFFF0000000) | (i.JType.target << 2));
- bdslot = true;
- break;
-
- case OP_LWC1:
- case OP_SWC1:
- db_printf("%s\tf%d,", op_name[i.IType.op],
- i.IType.rt);
- goto loadstore;
-
- case OP_LB:
- case OP_LH:
- case OP_LW:
- case OP_LD:
- case OP_LBU:
- case OP_LHU:
- case OP_LWU:
- case OP_SB:
- case OP_SH:
- case OP_SW:
- case OP_SD:
- db_printf("%s\t%s,", op_name[i.IType.op],
- reg_name[i.IType.rt]);
- loadstore:
- db_printf("%d(%s)", (short)i.IType.imm,
- reg_name[i.IType.rs]);
- break;
-
- case OP_ORI:
- case OP_XORI:
- if (i.IType.rs == 0) {
- db_printf("li\t%s,0x%x",
- reg_name[i.IType.rt],
- i.IType.imm);
- break;
- }
- /* FALLTHROUGH */
- case OP_ANDI:
- db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
- reg_name[i.IType.rt],
- reg_name[i.IType.rs],
- i.IType.imm);
- break;
-
- case OP_AUI:
- if (i.IType.rs == 0) {
- db_printf("lui\t%s,0x%x", reg_name[i.IType.rt],
- i.IType.imm);
- } else {
- db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
- reg_name[i.IType.rt], reg_name[i.IType.rs],
- (short)i.IType.imm);
- }
- break;
-
- case OP_ADDIU:
- case OP_DADDIU:
- if (i.IType.rs == 0) {
- db_printf("li\t%s,%d",
- reg_name[i.IType.rt],
- (short)i.IType.imm);
- break;
- }
- /* FALLTHROUGH */
- default:
- db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
- reg_name[i.IType.rt],
- reg_name[i.IType.rs],
- (short)i.IType.imm);
- }
- // db_printf("\n");
- // if (bdslot) {
- // db_printf(" bd: ");
- // mips_disassem(loc+4);
- // return (loc + 8);
- // }
- return (loc + 4);
-}
-
-static void
-print_addr(db_addr_t loc)
-{
- db_printf("0x%08lx", loc);
-}
-
-static void db_printf(const char* fmt, ...)
-{
- int cnt;
- va_list argp;
- va_start(argp, fmt);
- if (sprintf_buffer) {
- cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp);
- sprintf_buffer += cnt;
- sprintf_buf_len -= cnt;
- } else {
- vprintf(fmt, argp);
- }
- va_end(argp);
-}
-
-/*
- * Disassemble instruction at 'loc'.
- * Return address of start of next instruction.
- * Since this function is used by 'examine' and by 'step'
- * "next instruction" does NOT mean the next instruction to
- * be executed but the 'linear' next instruction.
- */
-db_addr_t
-mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format)
-{
- u_int32_t instr;
-
- if (alt_dis_format) { // use ARM register names for disassembly
- reg_name = &alt_arm_reg_name[0];
- }
-
- sprintf_buffer = di_buffer; // quick 'n' dirty printf() vs sprintf()
- sprintf_buf_len = 39; // should be passed in
-
- instr = *(u_int32_t *)loc;
- return (db_disasm_insn(instr, loc, false));
-}
diff --git a/libpixelflinger/codeflinger/mips64_disassem.h b/libpixelflinger/codeflinger/mips64_disassem.h
deleted file mode 100644
index c94f04f..0000000
--- a/libpixelflinger/codeflinger/mips64_disassem.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93
- */
-
-
-
-#ifndef ANDROID_MIPS_DISASSEM_H
-#define ANDROID_MIPS_DISASSEM_H
-
-#include <sys/types.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-/* Prototypes for callable functions */
-
-void mips_disassem(uint32_t *location, char *di_buffer, int alt_fmt);
-
-#if __cplusplus
-}
-#endif
-
-#endif /* !ANDROID_MIPS_DISASSEM_H */
diff --git a/libpixelflinger/codeflinger/mips_disassem.c b/libpixelflinger/codeflinger/mips_disassem.c
deleted file mode 100644
index 1fe6806..0000000
--- a/libpixelflinger/codeflinger/mips_disassem.c
+++ /dev/null
@@ -1,592 +0,0 @@
-/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <sys/cdefs.h>
-
-#include <sys/types.h>
-#include "mips_opcode.h"
-
-
-// #include <sys/systm.h>
-// #include <sys/param.h>
-
-// #include <machine/reg.h>
-// #include <machine/cpu.h>
-/*#include <machine/param.h>*/
-// #include <machine/db_machdep.h>
-
-// #include <ddb/db_interface.h>
-// #include <ddb/db_output.h>
-// #include <ddb/db_extern.h>
-// #include <ddb/db_sym.h>
-
-#define __unused __attribute__((__unused__))
-
-static char *sprintf_buffer;
-static int sprintf_buf_len;
-
-
-typedef uint32_t db_addr_t;
-static void db_printf(const char* fmt, ...);
-
-static const char * const op_name[64] = {
-/* 0 */ "spec", "bcond","j ", "jal", "beq", "bne", "blez", "bgtz",
-/* 8 */ "addi", "addiu","slti", "sltiu","andi", "ori", "xori", "lui",
-/*16 */ "cop0", "cop1", "cop2", "cop3", "beql", "bnel", "blezl","bgtzl",
-/*24 */ "daddi","daddiu","ldl", "ldr", "op34", "op35", "op36", "op37",
-/*32 */ "lb ", "lh ", "lwl", "lw ", "lbu", "lhu", "lwr", "lwu",
-/*40 */ "sb ", "sh ", "swl", "sw ", "sdl", "sdr", "swr", "cache",
-/*48 */ "ll ", "lwc1", "lwc2", "lwc3", "lld", "ldc1", "ldc2", "ld ",
-/*56 */ "sc ", "swc1", "swc2", "swc3", "scd", "sdc1", "sdc2", "sd "
-};
-
-static const char * const spec_name[64] = {
-/* 0 */ "sll", "spec01","srl", "sra", "sllv", "spec05","srlv","srav",
-/* 8 */ "jr", "jalr", "movz","movn","syscall","break","spec16","sync",
-/*16 */ "mfhi", "mthi", "mflo", "mtlo", "dsllv","spec25","dsrlv","dsrav",
-/*24 */ "mult", "multu","div", "divu", "dmult","dmultu","ddiv","ddivu",
-/*32 */ "add", "addu", "sub", "subu", "and", "or ", "xor", "nor",
-/*40 */ "spec50","spec51","slt","sltu", "dadd","daddu","dsub","dsubu",
-/*48 */ "tge","tgeu","tlt","tltu","teq","spec65","tne","spec67",
-/*56 */ "dsll","spec71","dsrl","dsra","dsll32","spec75","dsrl32","dsra32"
-};
-
-static const char * const spec2_name[64] = { /* QED RM4650, R5000, etc. */
-/* 0x00 */ "madd", "maddu", "mul", "spec3", "msub", "msubu", "rsrv6", "rsrv7",
-/* 0x08 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x10 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x18 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x20 */ "clz", "clo", "rsrv", "rsrv", "dclz", "dclo", "rsrv", "rsrv",
-/* 0x28 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x30 */ "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv", "rsrv",
-/* 0x38 */ "rsrv", "rsrv", "rsrv", "resv", "rsrv", "rsrv", "rsrv", "sdbbp"
-};
-
-static const char * const bcond_name[32] = {
-/* 0 */ "bltz", "bgez", "bltzl", "bgezl", "?", "?", "?", "?",
-/* 8 */ "tgei", "tgeiu", "tlti", "tltiu", "teqi", "?", "tnei", "?",
-/*16 */ "bltzal", "bgezal", "bltzall", "bgezall", "?", "?", "?", "?",
-/*24 */ "?", "?", "?", "?", "?", "?", "?", "?",
-};
-
-static const char * const cop1_name[64] = {
-/* 0 */ "fadd", "fsub", "fmpy", "fdiv", "fsqrt","fabs", "fmov", "fneg",
-/* 8 */ "fop08","fop09","fop0a","fop0b","fop0c","fop0d","fop0e","fop0f",
-/*16 */ "fop10","fop11","fop12","fop13","fop14","fop15","fop16","fop17",
-/*24 */ "fop18","fop19","fop1a","fop1b","fop1c","fop1d","fop1e","fop1f",
-/*32 */ "fcvts","fcvtd","fcvte","fop23","fcvtw","fop25","fop26","fop27",
-/*40 */ "fop28","fop29","fop2a","fop2b","fop2c","fop2d","fop2e","fop2f",
-/*48 */ "fcmp.f","fcmp.un","fcmp.eq","fcmp.ueq","fcmp.olt","fcmp.ult",
- "fcmp.ole","fcmp.ule",
-/*56 */ "fcmp.sf","fcmp.ngle","fcmp.seq","fcmp.ngl","fcmp.lt","fcmp.nge",
- "fcmp.le","fcmp.ngt"
-};
-
-static const char * const fmt_name[16] = {
- "s", "d", "e", "fmt3",
- "w", "fmt5", "fmt6", "fmt7",
- "fmt8", "fmt9", "fmta", "fmtb",
- "fmtc", "fmtd", "fmte", "fmtf"
-};
-
-#if defined(__mips_n32) || defined(__mips_n64)
-static char * const reg_name[32] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
-};
-#else
-
-static char * alt_arm_reg_name[32] = { // hacked names for comparison with ARM code
- "zero", "at", "r0", "r1", "r2", "r3", "r4", "r5",
- "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13",
- "r14", "r15", "at2", "cmp", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
-};
-
-static char * mips_reg_name[32] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
-};
-
-static char ** reg_name = &mips_reg_name[0];
-
-#endif /* __mips_n32 || __mips_n64 */
-
-static const char * const c0_opname[64] = {
- "c0op00","tlbr", "tlbwi", "c0op03","c0op04","c0op05","tlbwr", "c0op07",
- "tlbp", "c0op11","c0op12","c0op13","c0op14","c0op15","c0op16","c0op17",
- "rfe", "c0op21","c0op22","c0op23","c0op24","c0op25","c0op26","c0op27",
- "eret", "c0op31","c0op32","c0op33","c0op34","c0op35","c0op36","c0op37",
- "c0op40","c0op41","c0op42","c0op43","c0op44","c0op45","c0op46","c0op47",
- "c0op50","c0op51","c0op52","c0op53","c0op54","c0op55","c0op56","c0op57",
- "c0op60","c0op61","c0op62","c0op63","c0op64","c0op65","c0op66","c0op67",
- "c0op70","c0op71","c0op72","c0op73","c0op74","c0op75","c0op77","c0op77",
-};
-
-static const char * const c0_reg[32] = {
- "index", "random", "tlblo0", "tlblo1",
- "context", "pagemask", "wired", "cp0r7",
- "badvaddr", "count", "tlbhi", "compare",
- "status", "cause", "epc", "prid",
- "config", "lladdr", "watchlo", "watchhi",
- "xcontext", "cp0r21", "cp0r22", "debug",
- "depc", "perfcnt", "ecc", "cacheerr",
- "taglo", "taghi", "errepc", "desave"
-};
-
-static void print_addr(db_addr_t);
-db_addr_t mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format);
-
-
-/*
- * Disassemble instruction 'insn' nominally at 'loc'.
- * 'loc' may in fact contain a breakpoint instruction.
- */
-static db_addr_t
-db_disasm_insn(int insn, db_addr_t loc, bool altfmt __unused)
-{
- bool bdslot = false;
- InstFmt i;
-
- i.word = insn;
-
- switch (i.JType.op) {
- case OP_SPECIAL:
- if (i.word == 0) {
- db_printf("nop");
- break;
- }
- if (i.word == 0x0080) {
- db_printf("NIY");
- break;
- }
- if (i.word == 0x00c0) {
- db_printf("NOT IMPL");
- break;
- }
- /* Special cases --------------------------------------------------
- * "addu" is a "move" only in 32-bit mode. What's the correct
- * answer - never decode addu/daddu as "move"?
- */
- if ( (i.RType.func == OP_ADDU && i.RType.rt == 0) ||
- (i.RType.func == OP_OR && i.RType.rt == 0) ) {
- db_printf("move\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rs]);
- break;
- }
- // mips32r2, rotr & rotrv
- if (i.RType.func == OP_SRL && (i.RType.rs & 1) == 1) {
- db_printf("rotr\t%s,%s,%d", reg_name[i.RType.rd],
- reg_name[i.RType.rt], i.RType.shamt);
- break;
- }
- if (i.RType.func == OP_SRLV && (i.RType.shamt & 1) == 1) {
- db_printf("rotrv\t%s,%s,%s", reg_name[i.RType.rd],
- reg_name[i.RType.rt], reg_name[i.RType.rs]);
- break;
- }
-
-
- db_printf("%s", spec_name[i.RType.func]);
- switch (i.RType.func) {
- case OP_SLL:
- case OP_SRL:
- case OP_SRA:
- case OP_DSLL:
-
- case OP_DSRL:
- case OP_DSRA:
- case OP_DSLL32:
- case OP_DSRL32:
- case OP_DSRA32:
- db_printf("\t%s,%s,%d",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt],
- i.RType.shamt);
- break;
-
- case OP_SLLV:
- case OP_SRLV:
- case OP_SRAV:
- case OP_DSLLV:
- case OP_DSRLV:
- case OP_DSRAV:
- db_printf("\t%s,%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt],
- reg_name[i.RType.rs]);
- break;
-
- case OP_MFHI:
- case OP_MFLO:
- db_printf("\t%s", reg_name[i.RType.rd]);
- break;
-
- case OP_JR:
- case OP_JALR:
- db_printf("\t%s", reg_name[i.RType.rs]);
- bdslot = true;
- break;
- case OP_MTLO:
- case OP_MTHI:
- db_printf("\t%s", reg_name[i.RType.rs]);
- break;
-
- case OP_MULT:
- case OP_MULTU:
- case OP_DMULT:
- case OP_DMULTU:
- case OP_DIV:
- case OP_DIVU:
- case OP_DDIV:
- case OP_DDIVU:
- db_printf("\t%s,%s",
- reg_name[i.RType.rs],
- reg_name[i.RType.rt]);
- break;
-
-
- case OP_SYSCALL:
- case OP_SYNC:
- break;
-
- case OP_BREAK:
- db_printf("\t%d", (i.RType.rs << 5) | i.RType.rt);
- break;
-
- default:
- db_printf("\t%s,%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rs],
- reg_name[i.RType.rt]);
- }
- break;
-
- case OP_SPECIAL2:
- if (i.RType.func == OP_MUL)
- db_printf("%s\t%s,%s,%s",
- spec2_name[i.RType.func & 0x3f],
- reg_name[i.RType.rd],
- reg_name[i.RType.rs],
- reg_name[i.RType.rt]);
- else
- db_printf("%s\t%s,%s",
- spec2_name[i.RType.func & 0x3f],
- reg_name[i.RType.rs],
- reg_name[i.RType.rt]);
-
- break;
-
- case OP_SPECIAL3:
- if (i.RType.func == OP_EXT)
- db_printf("ext\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd+1);
- else if (i.RType.func == OP_INS)
- db_printf("ins\t%s,%s,%d,%d",
- reg_name[i.RType.rt],
- reg_name[i.RType.rs],
- i.RType.shamt,
- i.RType.rd-i.RType.shamt+1);
- else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_WSBH)
- db_printf("wsbh\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt]);
- else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEB)
- db_printf("seb\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt]);
- else if (i.RType.func == OP_BSHFL && i.RType.shamt == OP_SEH)
- db_printf("seh\t%s,%s",
- reg_name[i.RType.rd],
- reg_name[i.RType.rt]);
- else
- db_printf("Unknown");
- break;
-
- case OP_BCOND:
- db_printf("%s\t%s,", bcond_name[i.IType.rt],
- reg_name[i.IType.rs]);
- goto pr_displ;
-
- case OP_BLEZ:
- case OP_BLEZL:
- case OP_BGTZ:
- case OP_BGTZL:
- db_printf("%s\t%s,", op_name[i.IType.op],
- reg_name[i.IType.rs]);
- goto pr_displ;
-
- case OP_BEQ:
- case OP_BEQL:
- if (i.IType.rs == 0 && i.IType.rt == 0) {
- db_printf("b \t");
- goto pr_displ;
- }
- /* FALLTHROUGH */
- case OP_BNE:
- case OP_BNEL:
- db_printf("%s\t%s,%s,", op_name[i.IType.op],
- reg_name[i.IType.rs],
- reg_name[i.IType.rt]);
- pr_displ:
- print_addr(loc + 4 + ((short)i.IType.imm << 2));
- bdslot = true;
- break;
-
- case OP_COP0:
- switch (i.RType.rs) {
- case OP_BCx:
- case OP_BCy:
-
- db_printf("bc0%c\t",
- "ft"[i.RType.rt & COPz_BC_TF_MASK]);
- goto pr_displ;
-
- case OP_MT:
- db_printf("mtc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- case OP_DMT:
- db_printf("dmtc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- case OP_MF:
- db_printf("mfc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- case OP_DMF:
- db_printf("dmfc0\t%s,%s",
- reg_name[i.RType.rt],
- c0_reg[i.RType.rd]);
- break;
-
- default:
- db_printf("%s", c0_opname[i.FRType.func]);
- }
- break;
-
- case OP_COP1:
- switch (i.RType.rs) {
- case OP_BCx:
- case OP_BCy:
- db_printf("bc1%c\t",
- "ft"[i.RType.rt & COPz_BC_TF_MASK]);
- goto pr_displ;
-
- case OP_MT:
- db_printf("mtc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- case OP_MF:
- db_printf("mfc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- case OP_CT:
- db_printf("ctc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- case OP_CF:
- db_printf("cfc1\t%s,f%d",
- reg_name[i.RType.rt],
- i.RType.rd);
- break;
-
- default:
- db_printf("%s.%s\tf%d,f%d,f%d",
- cop1_name[i.FRType.func],
- fmt_name[i.FRType.fmt],
- i.FRType.fd, i.FRType.fs, i.FRType.ft);
- }
- break;
-
- case OP_J:
- case OP_JAL:
- db_printf("%s\t", op_name[i.JType.op]);
- print_addr((loc & 0xF0000000) | (i.JType.target << 2));
- bdslot = true;
- break;
-
- case OP_LWC1:
- case OP_SWC1:
- db_printf("%s\tf%d,", op_name[i.IType.op],
- i.IType.rt);
- goto loadstore;
-
- case OP_LB:
- case OP_LH:
- case OP_LW:
- case OP_LD:
- case OP_LBU:
- case OP_LHU:
- case OP_LWU:
- case OP_SB:
- case OP_SH:
- case OP_SW:
- case OP_SD:
- db_printf("%s\t%s,", op_name[i.IType.op],
- reg_name[i.IType.rt]);
- loadstore:
- db_printf("%d(%s)", (short)i.IType.imm,
- reg_name[i.IType.rs]);
- break;
-
- case OP_ORI:
- case OP_XORI:
- if (i.IType.rs == 0) {
- db_printf("li\t%s,0x%x",
- reg_name[i.IType.rt],
- i.IType.imm);
- break;
- }
- /* FALLTHROUGH */
- case OP_ANDI:
- db_printf("%s\t%s,%s,0x%x", op_name[i.IType.op],
- reg_name[i.IType.rt],
- reg_name[i.IType.rs],
- i.IType.imm);
- break;
-
- case OP_LUI:
- db_printf("%s\t%s,0x%x", op_name[i.IType.op],
- reg_name[i.IType.rt],
- i.IType.imm);
- break;
-
- case OP_CACHE:
- db_printf("%s\t0x%x,0x%x(%s)",
- op_name[i.IType.op],
- i.IType.rt,
- i.IType.imm,
- reg_name[i.IType.rs]);
- break;
-
- case OP_ADDI:
- case OP_DADDI:
- case OP_ADDIU:
- case OP_DADDIU:
- if (i.IType.rs == 0) {
- db_printf("li\t%s,%d",
- reg_name[i.IType.rt],
- (short)i.IType.imm);
- break;
- }
- /* FALLTHROUGH */
- default:
- db_printf("%s\t%s,%s,%d", op_name[i.IType.op],
- reg_name[i.IType.rt],
- reg_name[i.IType.rs],
- (short)i.IType.imm);
- }
- // db_printf("\n");
- // if (bdslot) {
- // db_printf(" bd: ");
- // mips_disassem(loc+4);
- // return (loc + 8);
- // }
- return (loc + 4);
-}
-
-static void
-print_addr(db_addr_t loc)
-{
- db_printf("0x%08x", loc);
-}
-
-
-
-static void db_printf(const char* fmt, ...)
-{
- int cnt;
- va_list argp;
- va_start(argp, fmt);
- if (sprintf_buffer) {
- cnt = vsnprintf(sprintf_buffer, sprintf_buf_len, fmt, argp);
- sprintf_buffer += cnt;
- sprintf_buf_len -= cnt;
- } else {
- vprintf(fmt, argp);
- }
- va_end(argp);
-}
-
-
-/*
- * Disassemble instruction at 'loc'.
- * Return address of start of next instruction.
- * Since this function is used by 'examine' and by 'step'
- * "next instruction" does NOT mean the next instruction to
- * be executed but the 'linear' next instruction.
- */
-db_addr_t
-mips_disassem(db_addr_t loc, char *di_buffer, int alt_dis_format)
-{
- u_int32_t instr;
-
- if (alt_dis_format) { // use ARM register names for disassembly
- reg_name = &alt_arm_reg_name[0];
- }
-
- sprintf_buffer = di_buffer; // quick 'n' dirty printf() vs sprintf()
- sprintf_buf_len = 39; // should be passed in
-
- instr = *(u_int32_t *)loc;
- return (db_disasm_insn(instr, loc, false));
-}
-
diff --git a/libpixelflinger/codeflinger/mips_disassem.h b/libpixelflinger/codeflinger/mips_disassem.h
deleted file mode 100644
index 2d5b7f5..0000000
--- a/libpixelflinger/codeflinger/mips_disassem.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/* $NetBSD: db_disasm.c,v 1.19 2007/02/28 04:21:53 thorpej Exp $ */
-
-/*-
- * Copyright (c) 1991, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * from: @(#)kadb.c 8.1 (Berkeley) 6/10/93
- */
-
-
-
-#ifndef ANDROID_MIPS_DISASSEM_H
-#define ANDROID_MIPS_DISASSEM_H
-
-#include <sys/types.h>
-
-#if __cplusplus
-extern "C" {
-#endif
-
-
-// could add an interface like this, but I have not
-// typedef struct {
-// u_int (*di_readword)(u_int);
-// void (*di_printaddr)(u_int);
-// void (*di_printf)(const char *, ...);
-// } disasm_interface_t;
-
-/* Prototypes for callable functions */
-
-// u_int disasm(const disasm_interface_t *, u_int, int);
-
-void mips_disassem(uint32_t *location, char *di_buffer, int alt_fmt);
-
-#if __cplusplus
-}
-#endif
-
-#endif /* !ANDROID_MIPS_DISASSEM_H */
diff --git a/libpixelflinger/codeflinger/mips_opcode.h b/libpixelflinger/codeflinger/mips_opcode.h
deleted file mode 100644
index 45bb19e..0000000
--- a/libpixelflinger/codeflinger/mips_opcode.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/* $NetBSD: mips_opcode.h,v 1.12 2005/12/11 12:18:09 christos Exp $ */
-
-/*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)mips_opcode.h 8.1 (Berkeley) 6/10/93
- */
-
-/*
- * Define the instruction formats and opcode values for the
- * MIPS instruction set.
- */
-
-#include <endian.h>
-
-/*
- * Define the instruction formats.
- */
-typedef union {
- unsigned word;
-
-#if BYTE_ORDER == LITTLE_ENDIAN
- struct {
- unsigned imm: 16;
- unsigned rt: 5;
- unsigned rs: 5;
- unsigned op: 6;
- } IType;
-
- struct {
- unsigned target: 26;
- unsigned op: 6;
- } JType;
-
- struct {
- unsigned func: 6;
- unsigned shamt: 5;
- unsigned rd: 5;
- unsigned rt: 5;
- unsigned rs: 5;
- unsigned op: 6;
- } RType;
-
- struct {
- unsigned func: 6;
- unsigned fd: 5;
- unsigned fs: 5;
- unsigned ft: 5;
- unsigned fmt: 4;
- unsigned : 1; /* always '1' */
- unsigned op: 6; /* always '0x11' */
- } FRType;
-#endif
-#if BYTE_ORDER == BIG_ENDIAN
- struct {
- unsigned op: 6;
- unsigned rs: 5;
- unsigned rt: 5;
- unsigned imm: 16;
- } IType;
-
- struct {
- unsigned op: 6;
- unsigned target: 26;
- } JType;
-
- struct {
- unsigned op: 6;
- unsigned rs: 5;
- unsigned rt: 5;
- unsigned rd: 5;
- unsigned shamt: 5;
- unsigned func: 6;
- } RType;
-
- struct {
- unsigned op: 6; /* always '0x11' */
- unsigned : 1; /* always '1' */
- unsigned fmt: 4;
- unsigned ft: 5;
- unsigned fs: 5;
- unsigned fd: 5;
- unsigned func: 6;
- } FRType;
-#endif
-} InstFmt;
-
-/*
- * Values for the 'op' field.
- */
-#define OP_SPECIAL 000
-#define OP_BCOND 001
-#define OP_J 002
-#define OP_JAL 003
-#define OP_BEQ 004
-#define OP_BNE 005
-#define OP_BLEZ 006
-#define OP_BGTZ 007
-
-#if __mips_isa_rev < 6
-#define OP_ADDI 010
-#else
-#define OP_POP10 010
-#endif
-
-#define OP_ADDIU 011
-#define OP_SLTI 012
-#define OP_SLTIU 013
-#define OP_ANDI 014
-#define OP_ORI 015
-#define OP_XORI 016
-
-#if __mips_isa_rev < 6
-#define OP_LUI 017
-#else
-#define OP_AUI 017
-#endif
-
-#define OP_COP0 020
-#define OP_COP1 021
-#define OP_COP2 022
-
-#if __mips_isa_rev < 6
-#define OP_COP3 023
-#define OP_BEQL 024
-#define OP_BNEL 025
-#define OP_BLEZL 026
-#define OP_BGTZL 027
-#define OP_DADDI 030
-#else
-#define OP_POP26 026
-#define OP_POP27 027
-#define OP_POP30 030
-#endif
-
-#define OP_DADDIU 031
-
-#if __mips_isa_rev < 6
-#define OP_LDL 032
-#define OP_LDR 033
-#define OP_SPECIAL2 034
-#else
-#define OP_DAUI 035
-#endif
-
-#define OP_SPECIAL3 037
-
-#define OP_LB 040
-#define OP_LH 041
-
-#if __mips_isa_rev < 6
-#define OP_LWL 042
-#endif
-
-#define OP_LW 043
-#define OP_LBU 044
-#define OP_LHU 045
-#define OP_LWR 046
-#define OP_LHU 045
-
-#if __mips_isa_rev < 6
-#define OP_LWR 046
-#endif
-
-#define OP_LWU 047
-
-#define OP_SB 050
-#define OP_SH 051
-
-#if __mips_isa_rev < 6
-#define OP_SWL 052
-#endif
-
-#define OP_SW 053
-
-#if __mips_isa_rev < 6
-#define OP_SDL 054
-#define OP_SDR 055
-#define OP_SWR 056
-#define OP_CACHE 057
-#define OP_LL 060
-#define OP_LWC0 OP_LL
-#define OP_LWC1 061
-#define OP_LWC2 062
-#define OP_LWC3 063
-#define OP_LLD 064
-#else
-#define OP_LWC1 061
-#define OP_BC 062
-#endif
-
-#define OP_LDC1 065
-#define OP_LD 067
-
-#if __mips_isa_rev < 6
-#define OP_SC 070
-#define OP_SWC0 OP_SC
-#endif
-
-#define OP_SWC1 071
-
-#if __mips_isa_rev < 6
-#define OP_SWC2 072
-#define OP_SWC3 073
-#define OP_SCD 074
-#else
-#define OP_BALC 072
-#endif
-
-#define OP_SDC1 075
-#define OP_SD 077
-
-/*
- * Values for the 'func' field when 'op' == OP_SPECIAL.
- */
-#define OP_SLL 000
-#define OP_SRL 002
-#define OP_SRA 003
-#define OP_SLLV 004
-#define OP_SRLV 006
-#define OP_SRAV 007
-
-#if __mips_isa_rev < 6
-#define OP_JR 010
-#endif
-
-#define OP_JALR 011
-#define OP_SYSCALL 014
-#define OP_BREAK 015
-#define OP_SYNC 017
-
-#if __mips_isa_rev < 6
-#define OP_MFHI 020
-#define OP_MTHI 021
-#define OP_MFLO 022
-#define OP_MTLO 023
-#else
-#define OP_CLZ 020
-#define OP_CLO 021
-#define OP_DCLZ 022
-#define OP_DCLO 023
-#endif
-
-#define OP_DSLLV 024
-#define OP_DSRLV 026
-#define OP_DSRAV 027
-
-#if __mips_isa_rev < 6
-#define OP_MULT 030
-#define OP_MULTU 031
-#define OP_DIV 032
-#define OP_DIVU 033
-#define OP_DMULT 034
-#define OP_DMULTU 035
-#define OP_DDIV 036
-#define OP_DDIVU 037
-#else
-#define OP_SOP30 030
-#define OP_SOP31 031
-#define OP_SOP32 032
-#define OP_SOP33 033
-#define OP_SOP34 034
-#define OP_SOP35 035
-#define OP_SOP36 036
-#define OP_SOP37 037
-#endif
-
-#define OP_ADD 040
-#define OP_ADDU 041
-#define OP_SUB 042
-#define OP_SUBU 043
-#define OP_AND 044
-#define OP_OR 045
-#define OP_XOR 046
-#define OP_NOR 047
-
-#define OP_SLT 052
-#define OP_SLTU 053
-#define OP_DADD 054
-#define OP_DADDU 055
-#define OP_DSUB 056
-#define OP_DSUBU 057
-
-#define OP_TGE 060
-#define OP_TGEU 061
-#define OP_TLT 062
-#define OP_TLTU 063
-#define OP_TEQ 064
-#define OP_TNE 066
-
-#define OP_DSLL 070
-#define OP_DSRL 072
-#define OP_DSRA 073
-#define OP_DSLL32 074
-#define OP_DSRL32 076
-#define OP_DSRA32 077
-
-#if __mips_isa_rev < 6
-/*
- * Values for the 'func' field when 'op' == OP_SPECIAL2.
- * OP_SPECIAL2 opcodes are removed in mips32r6
- */
-#define OP_MAD 000 /* QED */
-#define OP_MADU 001 /* QED */
-#define OP_MUL 002 /* QED */
-#endif
-
-/*
- * Values for the 'func' field when 'op' == OP_SPECIAL3.
- */
-#define OP_EXT 000
-#define OP_DEXTM 001
-#define OP_DEXTU 002
-#define OP_DEXT 003
-#define OP_INS 004
-#define OP_DINSM 005
-#define OP_DINSU 006
-#define OP_DINS 007
-#define OP_BSHFL 040
-#define OP_RDHWR 073
-
-/*
- * Values for the 'shamt' field when OP_SPECIAL3 && func OP_BSHFL.
- */
-
-#define OP_WSBH 002
-#define OP_SEB 020
-#define OP_SEH 030
-
-#if __mips_isa_rev == 6
-/*
- * Values for the 'shamt' field when OP_SOP30.
- */
-#define OP_MUL 002
-#define OP_MUH 003
-#endif
-
-/*
- * Values for the 'func' field when 'op' == OP_BCOND.
- */
-#define OP_BLTZ 000
-#define OP_BGEZ 001
-
-#if __mips_isa_rev < 6
-#define OP_BLTZL 002
-#define OP_BGEZL 003
-#define OP_TGEI 010
-#define OP_TGEIU 011
-#define OP_TLTI 012
-#define OP_TLTIU 013
-#define OP_TEQI 014
-#define OP_TNEI 016
-#define OP_BLTZAL 020
-#define OP_BGEZAL 021
-#define OP_BLTZALL 022
-#define OP_BGEZALL 023
-#else
-#define OP_NAL 020
-#define OP_BAL 021
-#endif
-
-/*
- * Values for the 'rs' field when 'op' == OP_COPz.
- */
-#define OP_MF 000
-#define OP_DMF 001
-#define OP_MT 004
-#define OP_DMT 005
-#define OP_BCx 010
-#define OP_BCy 014
-#define OP_CF 002
-#define OP_CT 006
-
-/*
- * Values for the 'rt' field when 'op' == OP_COPz.
- */
-#define COPz_BC_TF_MASK 0x01
-#define COPz_BC_TRUE 0x01
-#define COPz_BC_FALSE 0x00
-#define COPz_BCL_TF_MASK 0x02
-#define COPz_BCL_TRUE 0x02
-#define COPz_BCL_FALSE 0x00
diff --git a/libpixelflinger/codeflinger/texturing.cpp b/libpixelflinger/codeflinger/texturing.cpp
deleted file mode 100644
index e6997bd..0000000
--- a/libpixelflinger/codeflinger/texturing.cpp
+++ /dev/null
@@ -1,1261 +0,0 @@
-/* libs/pixelflinger/codeflinger/texturing.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "pixelflinger-code"
-
-#include <assert.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "GGLAssembler.h"
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-// iterators are initialized like this:
-// (intToFixedCenter(x) * dx)>>16 + x0
-// ((x<<16 + 0x8000) * dx)>>16 + x0
-// ((x<<16)*dx + (0x8000*dx))>>16 + x0
-// ( (x*dx) + dx>>1 ) + x0
-// (x*dx) + (dx>>1 + x0)
-
-void GGLAssembler::init_iterated_color(fragment_parts_t& parts, const reg_t& x)
-{
- context_t const* c = mBuilderContext.c;
-
- if (mSmooth) {
- // NOTE: we could take this case in the mDithering + !mSmooth case,
- // but this would use up to 4 more registers for the color components
- // for only a little added quality.
- // Currently, this causes the system to run out of registers in
- // some case (see issue #719496)
-
- comment("compute initial iterated color (smooth and/or dither case)");
-
- parts.iterated_packed = 0;
- parts.packed = 0;
-
- // 0x1: color component
- // 0x2: iterators
- const int optReload = mOptLevel >> 1;
- if (optReload >= 3) parts.reload = 0; // reload nothing
- else if (optReload == 2) parts.reload = 2; // reload iterators
- else if (optReload == 1) parts.reload = 1; // reload colors
- else if (optReload <= 0) parts.reload = 3; // reload both
-
- if (!mSmooth) {
- // we're not smoothing (just dithering), we never have to
- // reload the iterators
- parts.reload &= ~2;
- }
-
- Scratch scratches(registerFile());
- const int t0 = (parts.reload & 1) ? scratches.obtain() : 0;
- const int t1 = (parts.reload & 2) ? scratches.obtain() : 0;
- for (int i=0 ; i<4 ; i++) {
- if (!mInfo[i].iterated)
- continue;
-
- // this component exists in the destination and is not replaced
- // by a texture unit.
- const int c = (parts.reload & 1) ? t0 : obtainReg();
- if (i==0) CONTEXT_LOAD(c, iterators.ydady);
- if (i==1) CONTEXT_LOAD(c, iterators.ydrdy);
- if (i==2) CONTEXT_LOAD(c, iterators.ydgdy);
- if (i==3) CONTEXT_LOAD(c, iterators.ydbdy);
- parts.argb[i].reg = c;
-
- if (mInfo[i].smooth) {
- parts.argb_dx[i].reg = (parts.reload & 2) ? t1 : obtainReg();
- const int dvdx = parts.argb_dx[i].reg;
- CONTEXT_LOAD(dvdx, generated_vars.argb[i].dx);
- MLA(AL, 0, c, x.reg, dvdx, c);
-
- // adjust the color iterator to make sure it won't overflow
- if (!mAA) {
- // this is not needed when we're using anti-aliasing
- // because we will (have to) clamp the components
- // anyway.
- int end = scratches.obtain();
- MOV(AL, 0, end, reg_imm(parts.count.reg, LSR, 16));
- MLA(AL, 1, end, dvdx, end, c);
- SUB(MI, 0, c, c, end);
- BIC(AL, 0, c, c, reg_imm(c, ASR, 31));
- scratches.recycle(end);
- }
- }
-
- if (parts.reload & 1) {
- CONTEXT_STORE(c, generated_vars.argb[i].c);
- }
- }
- } else {
- // We're not smoothed, so we can
- // just use a packed version of the color and extract the
- // components as needed (or not at all if we don't blend)
-
- // figure out if we need the iterated color
- int load = 0;
- for (int i=0 ; i<4 ; i++) {
- component_info_t& info = mInfo[i];
- if ((info.inDest || info.needed) && !info.replaced)
- load |= 1;
- }
-
- parts.iterated_packed = 1;
- parts.packed = (!mTextureMachine.mask && !mBlending
- && !mFog && !mDithering);
- parts.reload = 0;
- if (load || parts.packed) {
- if (mBlending || mDithering || mInfo[GGLFormat::ALPHA].needed) {
- comment("load initial iterated color (8888 packed)");
- parts.iterated.setTo(obtainReg(),
- &(c->formats[GGL_PIXEL_FORMAT_RGBA_8888]));
- CONTEXT_LOAD(parts.iterated.reg, packed8888);
- } else {
- comment("load initial iterated color (dest format packed)");
-
- parts.iterated.setTo(obtainReg(), &mCbFormat);
-
- // pre-mask the iterated color
- const int bits = parts.iterated.size();
- const uint32_t size = ((bits>=32) ? 0 : (1LU << bits)) - 1;
- uint32_t mask = 0;
- if (mMasking) {
- for (int i=0 ; i<4 ; i++) {
- const int component_mask = 1<<i;
- const int h = parts.iterated.format.c[i].h;
- const int l = parts.iterated.format.c[i].l;
- if (h && (!(mMasking & component_mask))) {
- mask |= ((1<<(h-l))-1) << l;
- }
- }
- }
-
- if (mMasking && ((mask & size)==0)) {
- // none of the components are present in the mask
- } else {
- CONTEXT_LOAD(parts.iterated.reg, packed);
- if (mCbFormat.size == 1) {
- AND(AL, 0, parts.iterated.reg,
- parts.iterated.reg, imm(0xFF));
- } else if (mCbFormat.size == 2) {
- MOV(AL, 0, parts.iterated.reg,
- reg_imm(parts.iterated.reg, LSR, 16));
- }
- }
-
- // pre-mask the iterated color
- if (mMasking) {
- build_and_immediate(parts.iterated.reg, parts.iterated.reg,
- mask, bits);
- }
- }
- }
- }
-}
-
-void GGLAssembler::build_iterated_color(
- component_t& fragment,
- const fragment_parts_t& parts,
- int component,
- Scratch& regs)
-{
- fragment.setTo( regs.obtain(), 0, 32, CORRUPTIBLE);
-
- if (!mInfo[component].iterated)
- return;
-
- if (parts.iterated_packed) {
- // iterated colors are packed, extract the one we need
- extract(fragment, parts.iterated, component);
- } else {
- fragment.h = GGL_COLOR_BITS;
- fragment.l = GGL_COLOR_BITS - 8;
- fragment.flags |= CLEAR_LO;
- // iterated colors are held in their own register,
- // (smooth and/or dithering case)
- if (parts.reload==3) {
- // this implies mSmooth
- Scratch scratches(registerFile());
- int dx = scratches.obtain();
- CONTEXT_LOAD(fragment.reg, generated_vars.argb[component].c);
- CONTEXT_LOAD(dx, generated_vars.argb[component].dx);
- ADD(AL, 0, dx, fragment.reg, dx);
- CONTEXT_STORE(dx, generated_vars.argb[component].c);
- } else if (parts.reload & 1) {
- CONTEXT_LOAD(fragment.reg, generated_vars.argb[component].c);
- } else {
- // we don't reload, so simply rename the register and mark as
- // non CORRUPTIBLE so that the texture env or blending code
- // won't modify this (renamed) register
- regs.recycle(fragment.reg);
- fragment.reg = parts.argb[component].reg;
- fragment.flags &= ~CORRUPTIBLE;
- }
- if (mInfo[component].smooth && mAA) {
- // when using smooth shading AND anti-aliasing, we need to clamp
- // the iterators because there is always an extra pixel on the
- // edges, which most of the time will cause an overflow
- // (since technically its outside of the domain).
- BIC(AL, 0, fragment.reg, fragment.reg,
- reg_imm(fragment.reg, ASR, 31));
- component_sat(fragment);
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::decodeLogicOpNeeds(const needs_t& needs)
-{
- // gather some informations about the components we need to process...
- const int opcode = GGL_READ_NEEDS(LOGIC_OP, needs.n) | GGL_CLEAR;
- switch(opcode) {
- case GGL_COPY:
- mLogicOp = 0;
- break;
- case GGL_CLEAR:
- case GGL_SET:
- mLogicOp = LOGIC_OP;
- break;
- case GGL_AND:
- case GGL_AND_REVERSE:
- case GGL_AND_INVERTED:
- case GGL_XOR:
- case GGL_OR:
- case GGL_NOR:
- case GGL_EQUIV:
- case GGL_OR_REVERSE:
- case GGL_OR_INVERTED:
- case GGL_NAND:
- mLogicOp = LOGIC_OP|LOGIC_OP_SRC|LOGIC_OP_DST;
- break;
- case GGL_NOOP:
- case GGL_INVERT:
- mLogicOp = LOGIC_OP|LOGIC_OP_DST;
- break;
- case GGL_COPY_INVERTED:
- mLogicOp = LOGIC_OP|LOGIC_OP_SRC;
- break;
- };
-}
-
-void GGLAssembler::decodeTMUNeeds(const needs_t& needs, context_t const* c)
-{
- uint8_t replaced=0;
- mTextureMachine.mask = 0;
- mTextureMachine.activeUnits = 0;
- for (int i=GGL_TEXTURE_UNIT_COUNT-1 ; i>=0 ; i--) {
- texture_unit_t& tmu = mTextureMachine.tmu[i];
- if (replaced == 0xF) {
- // all components are replaced, skip this TMU.
- tmu.format_idx = 0;
- tmu.mask = 0;
- tmu.replaced = replaced;
- continue;
- }
- tmu.format_idx = GGL_READ_NEEDS(T_FORMAT, needs.t[i]);
- tmu.format = c->formats[tmu.format_idx];
- tmu.bits = tmu.format.size*8;
- tmu.swrap = GGL_READ_NEEDS(T_S_WRAP, needs.t[i]);
- tmu.twrap = GGL_READ_NEEDS(T_T_WRAP, needs.t[i]);
- tmu.env = ggl_needs_to_env(GGL_READ_NEEDS(T_ENV, needs.t[i]));
- tmu.pot = GGL_READ_NEEDS(T_POT, needs.t[i]);
- tmu.linear = GGL_READ_NEEDS(T_LINEAR, needs.t[i])
- && tmu.format.size!=3; // XXX: only 8, 16 and 32 modes for now
-
- // 5551 linear filtering is not supported
- if (tmu.format_idx == GGL_PIXEL_FORMAT_RGBA_5551)
- tmu.linear = 0;
-
- tmu.mask = 0;
- tmu.replaced = replaced;
-
- if (tmu.format_idx) {
- mTextureMachine.activeUnits++;
- if (tmu.format.c[0].h) tmu.mask |= 0x1;
- if (tmu.format.c[1].h) tmu.mask |= 0x2;
- if (tmu.format.c[2].h) tmu.mask |= 0x4;
- if (tmu.format.c[3].h) tmu.mask |= 0x8;
- if (tmu.env == GGL_REPLACE) {
- replaced |= tmu.mask;
- } else if (tmu.env == GGL_DECAL) {
- if (!tmu.format.c[GGLFormat::ALPHA].h) {
- // if we don't have alpha, decal does nothing
- tmu.mask = 0;
- } else {
- // decal always ignores At
- tmu.mask &= ~(1<<GGLFormat::ALPHA);
- }
- }
- }
- mTextureMachine.mask |= tmu.mask;
- //printf("%d: mask=%08lx, replaced=%08lx\n",
- // i, int(tmu.mask), int(tmu.replaced));
- }
- mTextureMachine.replaced = replaced;
- mTextureMachine.directTexture = 0;
- //printf("replaced=%08lx\n", mTextureMachine.replaced);
-}
-
-
-void GGLAssembler::init_textures(
- tex_coord_t* coords,
- const reg_t& x, const reg_t& y)
-{
- const needs_t& needs = mBuilderContext.needs;
- int Rx = x.reg;
- int Ry = y.reg;
-
- if (mTextureMachine.mask) {
- comment("compute texture coordinates");
- }
-
- // init texture coordinates for each tmu
- const int cb_format_idx = GGL_READ_NEEDS(CB_FORMAT, needs.n);
- const bool multiTexture = mTextureMachine.activeUnits > 1;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
- const texture_unit_t& tmu = mTextureMachine.tmu[i];
- if (tmu.format_idx == 0)
- continue;
- if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
- (tmu.twrap == GGL_NEEDS_WRAP_11))
- {
- // 1:1 texture
- pointer_t& txPtr = coords[i].ptr;
- txPtr.setTo(obtainReg(), tmu.bits);
- CONTEXT_LOAD(txPtr.reg, state.texture[i].iterators.ydsdy);
- ADD(AL, 0, Rx, Rx, reg_imm(txPtr.reg, ASR, 16)); // x += (s>>16)
- CONTEXT_LOAD(txPtr.reg, state.texture[i].iterators.ydtdy);
- ADD(AL, 0, Ry, Ry, reg_imm(txPtr.reg, ASR, 16)); // y += (t>>16)
- // merge base & offset
- CONTEXT_LOAD(txPtr.reg, generated_vars.texture[i].stride);
- SMLABB(AL, Rx, Ry, txPtr.reg, Rx); // x+y*stride
- CONTEXT_ADDR_LOAD(txPtr.reg, generated_vars.texture[i].data);
- base_offset(txPtr, txPtr, Rx);
- } else {
- Scratch scratches(registerFile());
- reg_t& s = coords[i].s;
- reg_t& t = coords[i].t;
- // s = (x * dsdx)>>16 + ydsdy
- // s = (x * dsdx)>>16 + (y*dsdy)>>16 + s0
- // t = (x * dtdx)>>16 + ydtdy
- // t = (x * dtdx)>>16 + (y*dtdy)>>16 + t0
- s.setTo(obtainReg());
- t.setTo(obtainReg());
- const int need_w = GGL_READ_NEEDS(W, needs.n);
- if (need_w) {
- CONTEXT_LOAD(s.reg, state.texture[i].iterators.ydsdy);
- CONTEXT_LOAD(t.reg, state.texture[i].iterators.ydtdy);
- } else {
- int ydsdy = scratches.obtain();
- int ydtdy = scratches.obtain();
- CONTEXT_LOAD(s.reg, generated_vars.texture[i].dsdx);
- CONTEXT_LOAD(ydsdy, state.texture[i].iterators.ydsdy);
- CONTEXT_LOAD(t.reg, generated_vars.texture[i].dtdx);
- CONTEXT_LOAD(ydtdy, state.texture[i].iterators.ydtdy);
- MLA(AL, 0, s.reg, Rx, s.reg, ydsdy);
- MLA(AL, 0, t.reg, Rx, t.reg, ydtdy);
- }
-
- if ((mOptLevel&1)==0) {
- CONTEXT_STORE(s.reg, generated_vars.texture[i].spill[0]);
- CONTEXT_STORE(t.reg, generated_vars.texture[i].spill[1]);
- recycleReg(s.reg);
- recycleReg(t.reg);
- }
- }
-
- // direct texture?
- if (!multiTexture && !mBlending && !mDithering && !mFog &&
- cb_format_idx == tmu.format_idx && !tmu.linear &&
- mTextureMachine.replaced == tmu.mask)
- {
- mTextureMachine.directTexture = i + 1;
- }
- }
-}
-
-void GGLAssembler::build_textures( fragment_parts_t& parts,
- Scratch& regs)
-{
- // We don't have a way to spill registers automatically
- // spill depth and AA regs, when we know we may have to.
- // build the spill list...
- uint32_t spill_list = 0;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
- const texture_unit_t& tmu = mTextureMachine.tmu[i];
- if (tmu.format_idx == 0)
- continue;
- if (tmu.linear) {
- // we may run out of register if we have linear filtering
- // at 1 or 4 bytes / pixel on any texture unit.
- if (tmu.format.size == 1) {
- // if depth and AA enabled, we'll run out of 1 register
- if (parts.z.reg > 0 && parts.covPtr.reg > 0)
- spill_list |= 1<<parts.covPtr.reg;
- }
- if (tmu.format.size == 4) {
- // if depth or AA enabled, we'll run out of 1 or 2 registers
- if (parts.z.reg > 0)
- spill_list |= 1<<parts.z.reg;
- if (parts.covPtr.reg > 0)
- spill_list |= 1<<parts.covPtr.reg;
- }
- }
- }
-
- Spill spill(registerFile(), *this, spill_list);
-
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
- const texture_unit_t& tmu = mTextureMachine.tmu[i];
- if (tmu.format_idx == 0)
- continue;
-
- pointer_t& txPtr = parts.coords[i].ptr;
- pixel_t& texel = parts.texel[i];
-
- // repeat...
- if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
- (tmu.twrap == GGL_NEEDS_WRAP_11))
- { // 1:1 textures
- comment("fetch texel");
- texel.setTo(regs.obtain(), &tmu.format);
- load(txPtr, texel, WRITE_BACK);
- } else {
- Scratch scratches(registerFile());
- reg_t& s = parts.coords[i].s;
- reg_t& t = parts.coords[i].t;
- if ((mOptLevel&1)==0) {
- comment("reload s/t (multitexture or linear filtering)");
- s.reg = scratches.obtain();
- t.reg = scratches.obtain();
- CONTEXT_LOAD(s.reg, generated_vars.texture[i].spill[0]);
- CONTEXT_LOAD(t.reg, generated_vars.texture[i].spill[1]);
- }
-
- if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
- return;
-
- comment("compute repeat/clamp");
- int u = scratches.obtain();
- int v = scratches.obtain();
- int width = scratches.obtain();
- int height = scratches.obtain();
- int U = 0;
- int V = 0;
-
- if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
- return;
-
- CONTEXT_LOAD(width, generated_vars.texture[i].width);
- CONTEXT_LOAD(height, generated_vars.texture[i].height);
-
- int FRAC_BITS = 0;
- if (tmu.linear) {
- // linear interpolation
- if (tmu.format.size == 1) {
- // for 8-bits textures, we can afford
- // 7 bits of fractional precision at no
- // additional cost (we can't do 8 bits
- // because filter8 uses signed 16 bits muls)
- FRAC_BITS = 7;
- } else if (tmu.format.size == 2) {
- // filter16() is internally limited to 4 bits, so:
- // FRAC_BITS=2 generates less instructions,
- // FRAC_BITS=3,4,5 creates unpleasant artifacts,
- // FRAC_BITS=6+ looks good
- FRAC_BITS = 6;
- } else if (tmu.format.size == 4) {
- // filter32() is internally limited to 8 bits, so:
- // FRAC_BITS=4 looks good
- // FRAC_BITS=5+ looks better, but generates 3 extra ipp
- FRAC_BITS = 6;
- } else {
- // for all other cases we use 4 bits.
- FRAC_BITS = 4;
- }
- }
- wrapping(u, s.reg, width, tmu.swrap, FRAC_BITS);
- wrapping(v, t.reg, height, tmu.twrap, FRAC_BITS);
-
- if (tmu.linear) {
- comment("compute linear filtering offsets");
- // pixel size scale
- const int shift = 31 - gglClz(tmu.format.size);
- U = scratches.obtain();
- V = scratches.obtain();
-
- if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
- return;
-
- // sample the texel center
- SUB(AL, 0, u, u, imm(1<<(FRAC_BITS-1)));
- SUB(AL, 0, v, v, imm(1<<(FRAC_BITS-1)));
-
- // get the fractionnal part of U,V
- AND(AL, 0, U, u, imm((1<<FRAC_BITS)-1));
- AND(AL, 0, V, v, imm((1<<FRAC_BITS)-1));
-
- // compute width-1 and height-1
- SUB(AL, 0, width, width, imm(1));
- SUB(AL, 0, height, height, imm(1));
-
- // get the integer part of U,V and clamp/wrap
- // and compute offset to the next texel
- if (tmu.swrap == GGL_NEEDS_WRAP_REPEAT) {
- // u has already been REPEATed
- MOV(AL, 1, u, reg_imm(u, ASR, FRAC_BITS));
- MOV(MI, 0, u, width);
- CMP(AL, u, width);
- MOV(LT, 0, width, imm(1 << shift));
- if (shift)
- MOV(GE, 0, width, reg_imm(width, LSL, shift));
- RSB(GE, 0, width, width, imm(0));
- } else {
- // u has not been CLAMPed yet
- // algorithm:
- // if ((u>>4) >= width)
- // u = width<<4
- // width = 0
- // else
- // width = 1<<shift
- // u = u>>4; // get integer part
- // if (u<0)
- // u = 0
- // width = 0
- // generated_vars.rt = width
-
- CMP(AL, width, reg_imm(u, ASR, FRAC_BITS));
- MOV(LE, 0, u, reg_imm(width, LSL, FRAC_BITS));
- MOV(LE, 0, width, imm(0));
- MOV(GT, 0, width, imm(1 << shift));
- MOV(AL, 1, u, reg_imm(u, ASR, FRAC_BITS));
- MOV(MI, 0, u, imm(0));
- MOV(MI, 0, width, imm(0));
- }
- CONTEXT_STORE(width, generated_vars.rt);
-
- const int stride = width;
- CONTEXT_LOAD(stride, generated_vars.texture[i].stride);
- if (tmu.twrap == GGL_NEEDS_WRAP_REPEAT) {
- // v has already been REPEATed
- MOV(AL, 1, v, reg_imm(v, ASR, FRAC_BITS));
- MOV(MI, 0, v, height);
- CMP(AL, v, height);
- MOV(LT, 0, height, imm(1 << shift));
- if (shift)
- MOV(GE, 0, height, reg_imm(height, LSL, shift));
- RSB(GE, 0, height, height, imm(0));
- MUL(AL, 0, height, stride, height);
- } else {
- // v has not been CLAMPed yet
- CMP(AL, height, reg_imm(v, ASR, FRAC_BITS));
- MOV(LE, 0, v, reg_imm(height, LSL, FRAC_BITS));
- MOV(LE, 0, height, imm(0));
- if (shift) {
- MOV(GT, 0, height, reg_imm(stride, LSL, shift));
- } else {
- MOV(GT, 0, height, stride);
- }
- MOV(AL, 1, v, reg_imm(v, ASR, FRAC_BITS));
- MOV(MI, 0, v, imm(0));
- MOV(MI, 0, height, imm(0));
- }
- CONTEXT_STORE(height, generated_vars.lb);
- }
-
- scratches.recycle(width);
- scratches.recycle(height);
-
- // iterate texture coordinates...
- comment("iterate s,t");
- int dsdx = scratches.obtain();
- int dtdx = scratches.obtain();
-
- if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
- return;
-
- CONTEXT_LOAD(dsdx, generated_vars.texture[i].dsdx);
- CONTEXT_LOAD(dtdx, generated_vars.texture[i].dtdx);
- ADD(AL, 0, s.reg, s.reg, dsdx);
- ADD(AL, 0, t.reg, t.reg, dtdx);
- if ((mOptLevel&1)==0) {
- CONTEXT_STORE(s.reg, generated_vars.texture[i].spill[0]);
- CONTEXT_STORE(t.reg, generated_vars.texture[i].spill[1]);
- scratches.recycle(s.reg);
- scratches.recycle(t.reg);
- }
- scratches.recycle(dsdx);
- scratches.recycle(dtdx);
-
- // merge base & offset...
- comment("merge base & offset");
- texel.setTo(regs.obtain(), &tmu.format);
- txPtr.setTo(texel.reg, tmu.bits);
- int stride = scratches.obtain();
-
- if (registerFile().status() & RegisterFile::OUT_OF_REGISTERS)
- return;
-
- CONTEXT_LOAD(stride, generated_vars.texture[i].stride);
- CONTEXT_ADDR_LOAD(txPtr.reg, generated_vars.texture[i].data);
- SMLABB(AL, u, v, stride, u); // u+v*stride
- base_offset(txPtr, txPtr, u);
-
- // load texel
- if (!tmu.linear) {
- comment("fetch texel");
- load(txPtr, texel, 0);
- } else {
- // recycle registers we don't need anymore
- scratches.recycle(u);
- scratches.recycle(v);
- scratches.recycle(stride);
-
- comment("fetch texel, bilinear");
- switch (tmu.format.size) {
- case 1: filter8(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
- case 2: filter16(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
- case 3: filter24(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
- case 4: filter32(parts, texel, tmu, U, V, txPtr, FRAC_BITS); break;
- }
- }
- }
- }
-}
-
-void GGLAssembler::build_iterate_texture_coordinates(
- const fragment_parts_t& parts)
-{
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT; i++) {
- const texture_unit_t& tmu = mTextureMachine.tmu[i];
- if (tmu.format_idx == 0)
- continue;
-
- if ((tmu.swrap == GGL_NEEDS_WRAP_11) &&
- (tmu.twrap == GGL_NEEDS_WRAP_11))
- { // 1:1 textures
- const pointer_t& txPtr = parts.coords[i].ptr;
- ADD(AL, 0, txPtr.reg, txPtr.reg, imm(txPtr.size>>3));
- } else {
- Scratch scratches(registerFile());
- int s = parts.coords[i].s.reg;
- int t = parts.coords[i].t.reg;
- if ((mOptLevel&1)==0) {
- s = scratches.obtain();
- t = scratches.obtain();
- CONTEXT_LOAD(s, generated_vars.texture[i].spill[0]);
- CONTEXT_LOAD(t, generated_vars.texture[i].spill[1]);
- }
- int dsdx = scratches.obtain();
- int dtdx = scratches.obtain();
- CONTEXT_LOAD(dsdx, generated_vars.texture[i].dsdx);
- CONTEXT_LOAD(dtdx, generated_vars.texture[i].dtdx);
- ADD(AL, 0, s, s, dsdx);
- ADD(AL, 0, t, t, dtdx);
- if ((mOptLevel&1)==0) {
- CONTEXT_STORE(s, generated_vars.texture[i].spill[0]);
- CONTEXT_STORE(t, generated_vars.texture[i].spill[1]);
- }
- }
- }
-}
-
-void GGLAssembler::filter8(
- const fragment_parts_t& /*parts*/,
- pixel_t& texel, const texture_unit_t& tmu,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS)
-{
- if (tmu.format.components != GGL_ALPHA &&
- tmu.format.components != GGL_LUMINANCE)
- {
- // this is a packed format, and we don't support
- // linear filtering (it's probably RGB 332)
- // Should not happen with OpenGL|ES
- LDRB(AL, texel.reg, txPtr.reg);
- return;
- }
-
- // ------------------------
- // about ~22 cycles / pixel
- Scratch scratches(registerFile());
-
- int pixel= scratches.obtain();
- int d = scratches.obtain();
- int u = scratches.obtain();
- int k = scratches.obtain();
- int rt = scratches.obtain();
- int lb = scratches.obtain();
-
- // RB -> U * V
-
- CONTEXT_LOAD(rt, generated_vars.rt);
- CONTEXT_LOAD(lb, generated_vars.lb);
-
- int offset = pixel;
- ADD(AL, 0, offset, lb, rt);
- LDRB(AL, pixel, txPtr.reg, reg_scale_pre(offset));
- SMULBB(AL, u, U, V);
- SMULBB(AL, d, pixel, u);
- RSB(AL, 0, k, u, imm(1<<(FRAC_BITS*2)));
-
- // LB -> (1-U) * V
- RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
- LDRB(AL, pixel, txPtr.reg, reg_scale_pre(lb));
- SMULBB(AL, u, U, V);
- SMLABB(AL, d, pixel, u, d);
- SUB(AL, 0, k, k, u);
-
- // LT -> (1-U)*(1-V)
- RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
- LDRB(AL, pixel, txPtr.reg);
- SMULBB(AL, u, U, V);
- SMLABB(AL, d, pixel, u, d);
-
- // RT -> U*(1-V)
- LDRB(AL, pixel, txPtr.reg, reg_scale_pre(rt));
- SUB(AL, 0, u, k, u);
- SMLABB(AL, texel.reg, pixel, u, d);
-
- for (int i=0 ; i<4 ; i++) {
- if (!texel.format.c[i].h) continue;
- texel.format.c[i].h = FRAC_BITS*2+8;
- texel.format.c[i].l = FRAC_BITS*2; // keeping 8 bits in enough
- }
- texel.format.size = 4;
- texel.format.bitsPerPixel = 32;
- texel.flags |= CLEAR_LO;
-}
-
-void GGLAssembler::filter16(
- const fragment_parts_t& /*parts*/,
- pixel_t& texel, const texture_unit_t& tmu,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS)
-{
- // compute the mask
- // XXX: it would be nice if the mask below could be computed
- // automatically.
- uint32_t mask = 0;
- int shift = 0;
- int prec = 0;
- switch (tmu.format_idx) {
- case GGL_PIXEL_FORMAT_RGB_565:
- // source: 00000ggg.ggg00000 | rrrrr000.000bbbbb
- // result: gggggggg.gggrrrrr | rrrrr0bb.bbbbbbbb
- mask = 0x07E0F81F;
- shift = 16;
- prec = 5;
- break;
- case GGL_PIXEL_FORMAT_RGBA_4444:
- // 0000,1111,0000,1111 | 0000,1111,0000,1111
- mask = 0x0F0F0F0F;
- shift = 12;
- prec = 4;
- break;
- case GGL_PIXEL_FORMAT_LA_88:
- // 0000,0000,1111,1111 | 0000,0000,1111,1111
- // AALL -> 00AA | 00LL
- mask = 0x00FF00FF;
- shift = 8;
- prec = 8;
- break;
- default:
- // unsupported format, do something sensical...
- ALOGE("Unsupported 16-bits texture format (%d)", tmu.format_idx);
- LDRH(AL, texel.reg, txPtr.reg);
- return;
- }
-
- const int adjust = FRAC_BITS*2 - prec;
- const int round = 0;
-
- // update the texel format
- texel.format.size = 4;
- texel.format.bitsPerPixel = 32;
- texel.flags |= CLEAR_HI|CLEAR_LO;
- for (int i=0 ; i<4 ; i++) {
- if (!texel.format.c[i].h) continue;
- const uint32_t offset = (mask & tmu.format.mask(i)) ? 0 : shift;
- texel.format.c[i].h = tmu.format.c[i].h + offset + prec;
- texel.format.c[i].l = texel.format.c[i].h - (tmu.format.bits(i) + prec);
- }
-
- // ------------------------
- // about ~40 cycles / pixel
- Scratch scratches(registerFile());
-
- int pixel= scratches.obtain();
- int d = scratches.obtain();
- int u = scratches.obtain();
- int k = scratches.obtain();
-
- // RB -> U * V
- int offset = pixel;
- CONTEXT_LOAD(offset, generated_vars.rt);
- CONTEXT_LOAD(u, generated_vars.lb);
- ADD(AL, 0, offset, offset, u);
-
- LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
- SMULBB(AL, u, U, V);
- ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
- build_and_immediate(pixel, pixel, mask, 32);
- if (adjust) {
- if (round)
- ADD(AL, 0, u, u, imm(1<<(adjust-1)));
- MOV(AL, 0, u, reg_imm(u, LSR, adjust));
- }
- MUL(AL, 0, d, pixel, u);
- RSB(AL, 0, k, u, imm(1<<prec));
-
- // LB -> (1-U) * V
- CONTEXT_LOAD(offset, generated_vars.lb);
- RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
- LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
- SMULBB(AL, u, U, V);
- ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
- build_and_immediate(pixel, pixel, mask, 32);
- if (adjust) {
- if (round)
- ADD(AL, 0, u, u, imm(1<<(adjust-1)));
- MOV(AL, 0, u, reg_imm(u, LSR, adjust));
- }
- MLA(AL, 0, d, pixel, u, d);
- SUB(AL, 0, k, k, u);
-
- // LT -> (1-U)*(1-V)
- RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
- LDRH(AL, pixel, txPtr.reg);
- SMULBB(AL, u, U, V);
- ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
- build_and_immediate(pixel, pixel, mask, 32);
- if (adjust) {
- if (round)
- ADD(AL, 0, u, u, imm(1<<(adjust-1)));
- MOV(AL, 0, u, reg_imm(u, LSR, adjust));
- }
- MLA(AL, 0, d, pixel, u, d);
-
- // RT -> U*(1-V)
- CONTEXT_LOAD(offset, generated_vars.rt);
- LDRH(AL, pixel, txPtr.reg, reg_pre(offset));
- SUB(AL, 0, u, k, u);
- ORR(AL, 0, pixel, pixel, reg_imm(pixel, LSL, shift));
- build_and_immediate(pixel, pixel, mask, 32);
- MLA(AL, 0, texel.reg, pixel, u, d);
-}
-
-void GGLAssembler::filter24(
- const fragment_parts_t& /*parts*/,
- pixel_t& texel, const texture_unit_t& /*tmu*/,
- int /*U*/, int /*V*/, pointer_t& txPtr,
- int /*FRAC_BITS*/)
-{
- // not supported yet (currently disabled)
- load(txPtr, texel, 0);
-}
-
-void GGLAssembler::filter32(
- const fragment_parts_t& /*parts*/,
- pixel_t& texel, const texture_unit_t& /*tmu*/,
- int U, int V, pointer_t& txPtr,
- int FRAC_BITS)
-{
- const int adjust = FRAC_BITS*2 - 8;
- const int round = 0;
-
- // ------------------------
- // about ~38 cycles / pixel
- Scratch scratches(registerFile());
-
- int pixel= scratches.obtain();
- int dh = scratches.obtain();
- int u = scratches.obtain();
- int k = scratches.obtain();
-
- int temp = scratches.obtain();
- int dl = scratches.obtain();
- int mask = scratches.obtain();
-
- MOV(AL, 0, mask, imm(0xFF));
- ORR(AL, 0, mask, mask, imm(0xFF0000));
-
- // RB -> U * V
- int offset = pixel;
- CONTEXT_LOAD(offset, generated_vars.rt);
- CONTEXT_LOAD(u, generated_vars.lb);
- ADD(AL, 0, offset, offset, u);
-
- LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
- SMULBB(AL, u, U, V);
- AND(AL, 0, temp, mask, pixel);
- if (adjust) {
- if (round)
- ADD(AL, 0, u, u, imm(1<<(adjust-1)));
- MOV(AL, 0, u, reg_imm(u, LSR, adjust));
- }
- MUL(AL, 0, dh, temp, u);
- AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
- MUL(AL, 0, dl, temp, u);
- RSB(AL, 0, k, u, imm(0x100));
-
- // LB -> (1-U) * V
- CONTEXT_LOAD(offset, generated_vars.lb);
- RSB(AL, 0, U, U, imm(1<<FRAC_BITS));
- LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
- SMULBB(AL, u, U, V);
- AND(AL, 0, temp, mask, pixel);
- if (adjust) {
- if (round)
- ADD(AL, 0, u, u, imm(1<<(adjust-1)));
- MOV(AL, 0, u, reg_imm(u, LSR, adjust));
- }
- MLA(AL, 0, dh, temp, u, dh);
- AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
- MLA(AL, 0, dl, temp, u, dl);
- SUB(AL, 0, k, k, u);
-
- // LT -> (1-U)*(1-V)
- RSB(AL, 0, V, V, imm(1<<FRAC_BITS));
- LDR(AL, pixel, txPtr.reg);
- SMULBB(AL, u, U, V);
- AND(AL, 0, temp, mask, pixel);
- if (adjust) {
- if (round)
- ADD(AL, 0, u, u, imm(1<<(adjust-1)));
- MOV(AL, 0, u, reg_imm(u, LSR, adjust));
- }
- MLA(AL, 0, dh, temp, u, dh);
- AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
- MLA(AL, 0, dl, temp, u, dl);
-
- // RT -> U*(1-V)
- CONTEXT_LOAD(offset, generated_vars.rt);
- LDR(AL, pixel, txPtr.reg, reg_scale_pre(offset));
- SUB(AL, 0, u, k, u);
- AND(AL, 0, temp, mask, pixel);
- MLA(AL, 0, dh, temp, u, dh);
- AND(AL, 0, temp, mask, reg_imm(pixel, LSR, 8));
- MLA(AL, 0, dl, temp, u, dl);
-
- AND(AL, 0, dh, mask, reg_imm(dh, LSR, 8));
- AND(AL, 0, dl, dl, reg_imm(mask, LSL, 8));
- ORR(AL, 0, texel.reg, dh, dl);
-}
-
-void GGLAssembler::build_texture_environment(
- component_t& fragment,
- const fragment_parts_t& parts,
- int component,
- Scratch& regs)
-{
- const uint32_t component_mask = 1<<component;
- const bool multiTexture = mTextureMachine.activeUnits > 1;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- texture_unit_t& tmu = mTextureMachine.tmu[i];
-
- if (tmu.mask & component_mask) {
- // replace or modulate with this texture
- if ((tmu.replaced & component_mask) == 0) {
- // not replaced by a later tmu...
-
- Scratch scratches(registerFile());
- pixel_t texel(parts.texel[i]);
-
- if (multiTexture &&
- tmu.swrap == GGL_NEEDS_WRAP_11 &&
- tmu.twrap == GGL_NEEDS_WRAP_11)
- {
- texel.reg = scratches.obtain();
- texel.flags |= CORRUPTIBLE;
- comment("fetch texel (multitexture 1:1)");
- load(parts.coords[i].ptr, texel, WRITE_BACK);
- }
-
- component_t incoming(fragment);
- modify(fragment, regs);
-
- switch (tmu.env) {
- case GGL_REPLACE:
- extract(fragment, texel, component);
- break;
- case GGL_MODULATE:
- modulate(fragment, incoming, texel, component);
- break;
- case GGL_DECAL:
- decal(fragment, incoming, texel, component);
- break;
- case GGL_BLEND:
- blend(fragment, incoming, texel, component, i);
- break;
- case GGL_ADD:
- add(fragment, incoming, texel, component);
- break;
- }
- }
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::wrapping(
- int d,
- int coord, int size,
- int tx_wrap, int tx_linear)
-{
- // notes:
- // if tx_linear is set, we need 4 extra bits of precision on the result
- // SMULL/UMULL is 3 cycles
- Scratch scratches(registerFile());
- int c = coord;
- if (tx_wrap == GGL_NEEDS_WRAP_REPEAT) {
- // UMULL takes 4 cycles (interlocked), and we can get away with
- // 2 cycles using SMULWB, but we're loosing 16 bits of precision
- // out of 32 (this is not a problem because the iterator keeps
- // its full precision)
- // UMULL(AL, 0, size, d, c, size);
- // note: we can't use SMULTB because it's signed.
- MOV(AL, 0, d, reg_imm(c, LSR, 16-tx_linear));
- SMULWB(AL, d, d, size);
- } else if (tx_wrap == GGL_NEEDS_WRAP_CLAMP_TO_EDGE) {
- if (tx_linear) {
- // 1 cycle
- MOV(AL, 0, d, reg_imm(coord, ASR, 16-tx_linear));
- } else {
- // 4 cycles (common case)
- MOV(AL, 0, d, reg_imm(coord, ASR, 16));
- BIC(AL, 0, d, d, reg_imm(d, ASR, 31));
- CMP(AL, d, size);
- SUB(GE, 0, d, size, imm(1));
- }
- }
-}
-
-// ---------------------------------------------------------------------------
-
-void GGLAssembler::modulate(
- component_t& dest,
- const component_t& incoming,
- const pixel_t& incomingTexel, int component)
-{
- Scratch locals(registerFile());
- integer_t texel(locals.obtain(), 32, CORRUPTIBLE);
- extract(texel, incomingTexel, component);
-
- const int Nt = texel.size();
- // Nt should always be less than 10 bits because it comes
- // from the TMU.
-
- int Ni = incoming.size();
- // Ni could be big because it comes from previous MODULATEs
-
- if (Nt == 1) {
- // texel acts as a bit-mask
- // dest = incoming & ((texel << incoming.h)-texel)
- RSB(AL, 0, dest.reg, texel.reg, reg_imm(texel.reg, LSL, incoming.h));
- AND(AL, 0, dest.reg, dest.reg, incoming.reg);
- dest.l = incoming.l;
- dest.h = incoming.h;
- dest.flags |= (incoming.flags & CLEAR_LO);
- } else if (Ni == 1) {
- MOV(AL, 0, dest.reg, reg_imm(incoming.reg, LSL, 31-incoming.h));
- AND(AL, 0, dest.reg, texel.reg, reg_imm(dest.reg, ASR, 31));
- dest.l = 0;
- dest.h = Nt;
- } else {
- int inReg = incoming.reg;
- int shift = incoming.l;
- if ((Nt + Ni) > 32) {
- // we will overflow, reduce the precision of Ni to 8 bits
- // (Note Nt cannot be more than 10 bits which happens with
- // 565 textures and GGL_LINEAR)
- shift += Ni-8;
- Ni = 8;
- }
-
- // modulate by the component with the lowest precision
- if (Nt >= Ni) {
- if (shift) {
- // XXX: we should be able to avoid this shift
- // when shift==16 && Nt<16 && Ni<16, in which
- // we could use SMULBT below.
- MOV(AL, 0, dest.reg, reg_imm(inReg, LSR, shift));
- inReg = dest.reg;
- shift = 0;
- }
- // operation: (Cf*Ct)/((1<<Ni)-1)
- // approximated with: Cf*(Ct + Ct>>(Ni-1))>>Ni
- // this operation doesn't change texel's size
- ADD(AL, 0, dest.reg, inReg, reg_imm(inReg, LSR, Ni-1));
- if (Nt<16 && Ni<16) SMULBB(AL, dest.reg, texel.reg, dest.reg);
- else MUL(AL, 0, dest.reg, texel.reg, dest.reg);
- dest.l = Ni;
- dest.h = Nt + Ni;
- } else {
- if (shift && (shift != 16)) {
- // if shift==16, we can use 16-bits mul instructions later
- MOV(AL, 0, dest.reg, reg_imm(inReg, LSR, shift));
- inReg = dest.reg;
- shift = 0;
- }
- // operation: (Cf*Ct)/((1<<Nt)-1)
- // approximated with: Ct*(Cf + Cf>>(Nt-1))>>Nt
- // this operation doesn't change incoming's size
- Scratch scratches(registerFile());
- int t = (texel.flags & CORRUPTIBLE) ? texel.reg : dest.reg;
- if (t == inReg)
- t = scratches.obtain();
- ADD(AL, 0, t, texel.reg, reg_imm(texel.reg, LSR, Nt-1));
- if (Nt<16 && Ni<16) {
- if (shift==16) SMULBT(AL, dest.reg, t, inReg);
- else SMULBB(AL, dest.reg, t, inReg);
- } else MUL(AL, 0, dest.reg, t, inReg);
- dest.l = Nt;
- dest.h = Nt + Ni;
- }
-
- // low bits are not valid
- dest.flags |= CLEAR_LO;
-
- // no need to keep more than 8 bits/component
- if (dest.size() > 8)
- dest.l = dest.h-8;
- }
-}
-
-void GGLAssembler::decal(
- component_t& dest,
- const component_t& incoming,
- const pixel_t& incomingTexel, int component)
-{
- // RGBA:
- // Cv = Cf*(1 - At) + Ct*At = Cf + (Ct - Cf)*At
- // Av = Af
- Scratch locals(registerFile());
- integer_t texel(locals.obtain(), 32, CORRUPTIBLE);
- integer_t factor(locals.obtain(), 32, CORRUPTIBLE);
- extract(texel, incomingTexel, component);
- extract(factor, incomingTexel, GGLFormat::ALPHA);
-
- // no need to keep more than 8-bits for decal
- int Ni = incoming.size();
- int shift = incoming.l;
- if (Ni > 8) {
- shift += Ni-8;
- Ni = 8;
- }
- integer_t incomingNorm(incoming.reg, Ni, incoming.flags);
- if (shift) {
- MOV(AL, 0, dest.reg, reg_imm(incomingNorm.reg, LSR, shift));
- incomingNorm.reg = dest.reg;
- incomingNorm.flags |= CORRUPTIBLE;
- }
- ADD(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, LSR, factor.s-1));
- build_blendOneMinusFF(dest, factor, incomingNorm, texel);
-}
-
-void GGLAssembler::blend(
- component_t& dest,
- const component_t& incoming,
- const pixel_t& incomingTexel, int component, int tmu)
-{
- // RGBA:
- // Cv = (1 - Ct)*Cf + Ct*Cc = Cf + (Cc - Cf)*Ct
- // Av = At*Af
-
- if (component == GGLFormat::ALPHA) {
- modulate(dest, incoming, incomingTexel, component);
- return;
- }
-
- Scratch locals(registerFile());
- integer_t color(locals.obtain(), 8, CORRUPTIBLE);
- integer_t factor(locals.obtain(), 32, CORRUPTIBLE);
- LDRB(AL, color.reg, mBuilderContext.Rctx,
- immed12_pre(GGL_OFFSETOF(state.texture[tmu].env_color[component])));
- extract(factor, incomingTexel, component);
-
- // no need to keep more than 8-bits for blend
- int Ni = incoming.size();
- int shift = incoming.l;
- if (Ni > 8) {
- shift += Ni-8;
- Ni = 8;
- }
- integer_t incomingNorm(incoming.reg, Ni, incoming.flags);
- if (shift) {
- MOV(AL, 0, dest.reg, reg_imm(incomingNorm.reg, LSR, shift));
- incomingNorm.reg = dest.reg;
- incomingNorm.flags |= CORRUPTIBLE;
- }
- ADD(AL, 0, factor.reg, factor.reg, reg_imm(factor.reg, LSR, factor.s-1));
- build_blendOneMinusFF(dest, factor, incomingNorm, color);
-}
-
-void GGLAssembler::add(
- component_t& dest,
- const component_t& incoming,
- const pixel_t& incomingTexel, int component)
-{
- // RGBA:
- // Cv = Cf + Ct;
- Scratch locals(registerFile());
-
- component_t incomingTemp(incoming);
-
- // use "dest" as a temporary for extracting the texel, unless "dest"
- // overlaps "incoming".
- integer_t texel(dest.reg, 32, CORRUPTIBLE);
- if (dest.reg == incomingTemp.reg)
- texel.reg = locals.obtain();
- extract(texel, incomingTexel, component);
-
- if (texel.s < incomingTemp.size()) {
- expand(texel, texel, incomingTemp.size());
- } else if (texel.s > incomingTemp.size()) {
- if (incomingTemp.flags & CORRUPTIBLE) {
- expand(incomingTemp, incomingTemp, texel.s);
- } else {
- incomingTemp.reg = locals.obtain();
- expand(incomingTemp, incoming, texel.s);
- }
- }
-
- if (incomingTemp.l) {
- ADD(AL, 0, dest.reg, texel.reg,
- reg_imm(incomingTemp.reg, LSR, incomingTemp.l));
- } else {
- ADD(AL, 0, dest.reg, texel.reg, incomingTemp.reg);
- }
- dest.l = 0;
- dest.h = texel.size();
- component_sat(dest);
-}
-
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
diff --git a/libpixelflinger/codeflinger/tinyutils/smartpointer.h b/libpixelflinger/codeflinger/tinyutils/smartpointer.h
deleted file mode 100644
index 23a5f7e..0000000
--- a/libpixelflinger/codeflinger/tinyutils/smartpointer.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2005 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 ANDROID_PIXELFLINGER_SMART_POINTER_H
-#define ANDROID_PIXELFLINGER_SMART_POINTER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <stdlib.h>
-
-// ---------------------------------------------------------------------------
-namespace android {
-namespace tinyutils {
-
-// ---------------------------------------------------------------------------
-
-#define COMPARE(_op_) \
-inline bool operator _op_ (const sp<T>& o) const { \
- return m_ptr _op_ o.m_ptr; \
-} \
-inline bool operator _op_ (const T* o) const { \
- return m_ptr _op_ o; \
-} \
-template<typename U> \
-inline bool operator _op_ (const sp<U>& o) const { \
- return m_ptr _op_ o.m_ptr; \
-} \
-template<typename U> \
-inline bool operator _op_ (const U* o) const { \
- return m_ptr _op_ o; \
-}
-
-// ---------------------------------------------------------------------------
-
-template <typename T>
-class sp
-{
-public:
- inline sp() : m_ptr(0) { }
-
- sp(T* other); // NOLINT, implicit
- sp(const sp<T>& other);
- template<typename U> sp(U* other); // NOLINT, implicit
- template<typename U> sp(const sp<U>& other); // NOLINT, implicit
-
- ~sp();
-
- // Assignment
-
- sp& operator = (T* other);
- sp& operator = (const sp<T>& other);
-
- template<typename U> sp& operator = (const sp<U>& other);
- template<typename U> sp& operator = (U* other);
-
- // Reset
- void clear();
-
- // Accessors
-
- inline T& operator* () const { return *m_ptr; }
- inline T* operator-> () const { return m_ptr; }
- inline T* get() const { return m_ptr; }
-
- // Operators
-
- COMPARE(==)
- COMPARE(!=)
- COMPARE(>)
- COMPARE(<)
- COMPARE(<=)
- COMPARE(>=)
-
-private:
- template<typename Y> friend class sp;
-
- T* m_ptr;
-};
-
-// ---------------------------------------------------------------------------
-// No user serviceable parts below here.
-
-template<typename T>
-sp<T>::sp(T* other)
- : m_ptr(other)
-{
- if (other) other->incStrong(this);
-}
-
-template<typename T>
-sp<T>::sp(const sp<T>& other)
- : m_ptr(other.m_ptr)
-{
- if (m_ptr) m_ptr->incStrong(this);
-}
-
-template<typename T> template<typename U>
-sp<T>::sp(U* other) : m_ptr(other)
-{
- if (other) other->incStrong(this);
-}
-
-template<typename T> template<typename U>
-sp<T>::sp(const sp<U>& other)
- : m_ptr(other.m_ptr)
-{
- if (m_ptr) m_ptr->incStrong(this);
-}
-
-template<typename T>
-sp<T>::~sp()
-{
- if (m_ptr) m_ptr->decStrong(this);
-}
-
-template<typename T>
-sp<T>& sp<T>::operator = (const sp<T>& other) {
- if (other.m_ptr) other.m_ptr->incStrong(this);
- if (m_ptr) m_ptr->decStrong(this);
- m_ptr = other.m_ptr;
- return *this;
-}
-
-template<typename T>
-sp<T>& sp<T>::operator = (T* other)
-{
- if (other) other->incStrong(this);
- if (m_ptr) m_ptr->decStrong(this);
- m_ptr = other;
- return *this;
-}
-
-template<typename T> template<typename U>
-sp<T>& sp<T>::operator = (const sp<U>& other)
-{
- if (other.m_ptr) other.m_ptr->incStrong(this);
- if (m_ptr) m_ptr->decStrong(this);
- m_ptr = other.m_ptr;
- return *this;
-}
-
-template<typename T> template<typename U>
-sp<T>& sp<T>::operator = (U* other)
-{
- if (other) other->incStrong(this);
- if (m_ptr) m_ptr->decStrong(this);
- m_ptr = other;
- return *this;
-}
-
-template<typename T>
-void sp<T>::clear()
-{
- if (m_ptr) {
- m_ptr->decStrong(this);
- m_ptr = 0;
- }
-}
-
-// ---------------------------------------------------------------------------
-
-} // namespace tinyutils
-} // namespace android
-
-// ---------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_SMART_POINTER_H
diff --git a/libpixelflinger/col32cb16blend.S b/libpixelflinger/col32cb16blend.S
deleted file mode 100644
index 39f94e1..0000000
--- a/libpixelflinger/col32cb16blend.S
+++ /dev/null
@@ -1,77 +0,0 @@
-/* libs/pixelflinger/col32cb16blend.S
- *
- * Copyright (C) 2009 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.
- */
-
- .text
- .balign 4
-
- .global scanline_col32cb16blend_arm
-
-//
-// This function alpha blends a fixed color into a destination scanline, using
-// the formula:
-//
-// d = s + (((a + (a >> 7)) * d) >> 8)
-//
-// where d is the destination pixel,
-// s is the source color,
-// a is the alpha channel of the source color.
-//
-
-// r0 = destination buffer pointer
-// r1 = color value
-// r2 = count
-
-
-scanline_col32cb16blend_arm:
- push {r4-r10, lr} // stack ARM regs
-
- mov r5, r1, lsr #24 // shift down alpha
- mov r9, #0xff // create mask
- add r5, r5, r5, lsr #7 // add in top bit
- rsb r5, r5, #256 // invert alpha
- and r10, r1, #0xff // extract red
- and r12, r9, r1, lsr #8 // extract green
- and r4, r9, r1, lsr #16 // extract blue
- mov r10, r10, lsl #5 // prescale red
- mov r12, r12, lsl #6 // prescale green
- mov r4, r4, lsl #5 // prescale blue
- mov r9, r9, lsr #2 // create dest green mask
-
-1:
- ldrh r8, [r0] // load dest pixel
- subs r2, r2, #1 // decrement loop counter
- mov r6, r8, lsr #11 // extract dest red
- and r7, r9, r8, lsr #5 // extract dest green
- and r8, r8, #0x1f // extract dest blue
-
- smlabb r6, r6, r5, r10 // dest red * alpha + src red
- smlabb r7, r7, r5, r12 // dest green * alpha + src green
- smlabb r8, r8, r5, r4 // dest blue * alpha + src blue
-
- mov r6, r6, lsr #8 // shift down red
- mov r7, r7, lsr #8 // shift down green
- mov r6, r6, lsl #11 // shift red into 565
- orr r6, r7, lsl #5 // shift green into 565
- orr r6, r8, lsr #8 // shift blue into 565
-
- strh r6, [r0], #2 // store pixel to dest, update ptr
- bne 1b // if count != 0, loop
-
- pop {r4-r10, pc} // return
-
-
-
diff --git a/libpixelflinger/col32cb16blend_neon.S b/libpixelflinger/col32cb16blend_neon.S
deleted file mode 100644
index 7ad34b0..0000000
--- a/libpixelflinger/col32cb16blend_neon.S
+++ /dev/null
@@ -1,153 +0,0 @@
-/* libs/pixelflinger/col32cb16blend_neon.S
- *
- * Copyright (C) 2009 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.
- */
-
-
- .text
- .balign 4
-
- .global scanline_col32cb16blend_neon
-
-//
-// This function alpha blends a fixed color into a destination scanline, using
-// the formula:
-//
-// d = s + (((a + (a >> 7)) * d) >> 8)
-//
-// where d is the destination pixel,
-// s is the source color,
-// a is the alpha channel of the source color.
-//
-// The NEON implementation processes 16 pixels per iteration. The remaining 0 - 15
-// pixels are processed in ARM code.
-//
-
-// r0 = destination buffer pointer
-// r1 = color pointer
-// r2 = count
-
-
-scanline_col32cb16blend_neon:
- push {r4-r11, lr} // stack ARM regs
-
- vmov.u16 q15, #256 // create alpha constant
- movs r3, r2, lsr #4 // calc. sixteens iterations
- vmov.u16 q14, #0x1f // create blue mask
-
- beq 2f // if r3 == 0, branch to singles
-
- vld4.8 {d0[], d2[], d4[], d6[]}, [r1] // load color into four registers
- // split and duplicate them, such that
- // d0 = 8 equal red values
- // d2 = 8 equal green values
- // d4 = 8 equal blue values
- // d6 = 8 equal alpha values
- vshll.u8 q0, d0, #5 // shift up red and widen
- vshll.u8 q1, d2, #6 // shift up green and widen
- vshll.u8 q2, d4, #5 // shift up blue and widen
-
- vshr.u8 d7, d6, #7 // extract top bit of alpha
- vaddl.u8 q3, d6, d7 // add top bit into alpha
- vsub.u16 q3, q15, q3 // invert alpha
-
-1:
- // This loop processes 16 pixels per iteration. In the comments, references to
- // the first eight pixels are suffixed with "0" (red0, green0, blue0),
- // the second eight are suffixed "1".
- // q8 = dst red0
- // q9 = dst green0
- // q10 = dst blue0
- // q13 = dst red1
- // q12 = dst green1
- // q11 = dst blue1
-
- vld1.16 {d20, d21, d22, d23}, [r0] // load 16 dest pixels
- vshr.u16 q8, q10, #11 // shift dst red0 to low 5 bits
- pld [r0, #63] // preload next dest pixels
- vshl.u16 q9, q10, #5 // shift dst green0 to top 6 bits
- vand q10, q10, q14 // extract dst blue0
- vshr.u16 q9, q9, #10 // shift dst green0 to low 6 bits
- vmul.u16 q8, q8, q3 // multiply dst red0 by src alpha
- vshl.u16 q12, q11, #5 // shift dst green1 to top 6 bits
- vmul.u16 q9, q9, q3 // multiply dst green0 by src alpha
- vshr.u16 q13, q11, #11 // shift dst red1 to low 5 bits
- vmul.u16 q10, q10, q3 // multiply dst blue0 by src alpha
- vshr.u16 q12, q12, #10 // shift dst green1 to low 6 bits
- vand q11, q11, q14 // extract dst blue1
- vadd.u16 q8, q8, q0 // add src red to dst red0
- vmul.u16 q13, q13, q3 // multiply dst red1 by src alpha
- vadd.u16 q9, q9, q1 // add src green to dst green0
- vmul.u16 q12, q12, q3 // multiply dst green1 by src alpha
- vadd.u16 q10, q10, q2 // add src blue to dst blue0
- vmul.u16 q11, q11, q3 // multiply dst blue1 by src alpha
- vshr.u16 q8, q8, #8 // shift down red0
- vadd.u16 q13, q13, q0 // add src red to dst red1
- vshr.u16 q9, q9, #8 // shift down green0
- vadd.u16 q12, q12, q1 // add src green to dst green1
- vshr.u16 q10, q10, #8 // shift down blue0
- vadd.u16 q11, q11, q2 // add src blue to dst blue1
- vsli.u16 q10, q9, #5 // shift & insert green0 into blue0
- vshr.u16 q13, q13, #8 // shift down red1
- vsli.u16 q10, q8, #11 // shift & insert red0 into blue0
- vshr.u16 q12, q12, #8 // shift down green1
- vshr.u16 q11, q11, #8 // shift down blue1
- subs r3, r3, #1 // decrement loop counter
- vsli.u16 q11, q12, #5 // shift & insert green1 into blue1
- vsli.u16 q11, q13, #11 // shift & insert red1 into blue1
-
- vst1.16 {d20, d21, d22, d23}, [r0]! // write 16 pixels back to dst
- bne 1b // if count != 0, loop
-
-2:
- ands r3, r2, #15 // calc. single iterations
- beq 4f // if r3 == 0, exit
-
- ldr r4, [r1] // load source color
- mov r5, r4, lsr #24 // shift down alpha
- add r5, r5, r5, lsr #7 // add in top bit
- rsb r5, r5, #256 // invert alpha
- and r11, r4, #0xff // extract red
- ubfx r12, r4, #8, #8 // extract green
- ubfx r4, r4, #16, #8 // extract blue
- mov r11, r11, lsl #5 // prescale red
- mov r12, r12, lsl #6 // prescale green
- mov r4, r4, lsl #5 // prescale blue
-
-3:
- ldrh r8, [r0] // load dest pixel
- subs r3, r3, #1 // decrement loop counter
- mov r6, r8, lsr #11 // extract dest red
- ubfx r7, r8, #5, #6 // extract dest green
- and r8, r8, #0x1f // extract dest blue
-
- smlabb r6, r6, r5, r11 // dest red * alpha + src red
- smlabb r7, r7, r5, r12 // dest green * alpha + src green
- smlabb r8, r8, r5, r4 // dest blue * alpha + src blue
-
- mov r6, r6, lsr #8 // shift down red
- mov r7, r7, lsr #8 // shift down green
- mov r6, r6, lsl #11 // shift red into 565
- orr r6, r7, lsl #5 // shift green into 565
- orr r6, r8, lsr #8 // shift blue into 565
-
- strh r6, [r0], #2 // store pixel to dest, update ptr
- bne 3b // if count != 0, loop
-4:
-
- pop {r4-r11, pc} // return
-
-
-
diff --git a/libpixelflinger/fixed.cpp b/libpixelflinger/fixed.cpp
deleted file mode 100644
index de6b479..0000000
--- a/libpixelflinger/fixed.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/* libs/pixelflinger/fixed.cpp
-**
-** Copyright 2006, 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 <stdio.h>
-
-#include <private/pixelflinger/ggl_context.h>
-#include <private/pixelflinger/ggl_fixed.h>
-
-
-// ------------------------------------------------------------------------
-
-int32_t gglRecipQNormalized(int32_t x, int* exponent)
-{
- const int32_t s = x>>31;
- uint32_t a = s ? -x : x;
-
- // the result will overflow, so just set it to the biggest/inf value
- if (ggl_unlikely(a <= 2LU)) {
- *exponent = 0;
- return s ? FIXED_MIN : FIXED_MAX;
- }
-
- // Newton-Raphson iteration:
- // x = r*(2 - a*r)
-
- const int32_t lz = gglClz(a);
- a <<= lz; // 0.32
- uint32_t r = a;
- // note: if a == 0x80000000, this means x was a power-of-2, in this
- // case we don't need to compute anything. We get the reciprocal for
- // (almost) free.
- if (a != 0x80000000) {
- r = (0x2E800 << (30-16)) - (r>>(2-1)); // 2.30, r = 2.90625 - 2*a
- // 0.32 + 2.30 = 2.62 -> 2.30
- // 2.30 + 2.30 = 4.60 -> 2.30
- r = (((2LU<<30) - uint32_t((uint64_t(a)*r) >> 32)) * uint64_t(r)) >> 30;
- r = (((2LU<<30) - uint32_t((uint64_t(a)*r) >> 32)) * uint64_t(r)) >> 30;
- }
-
- // shift right 1-bit to make room for the sign bit
- *exponent = 30-lz-1;
- r >>= 1;
- return s ? -r : r;
-}
-
-int32_t gglRecipQ(GGLfixed x, int q)
-{
- int shift;
- x = gglRecipQNormalized(x, &shift);
- shift += 16-q;
- if (shift > 0)
- x += 1L << (shift-1); // rounding
- x >>= shift;
- return x;
-}
-
-// ------------------------------------------------------------------------
-
-static const GGLfixed ggl_sqrt_reciproc_approx_tab[8] = {
- // 1/sqrt(x) with x = 1-N/16, N=[8...1]
- 0x16A09, 0x15555, 0x143D1, 0x134BF, 0x1279A, 0x11C01, 0x111AC, 0x10865
-};
-
-GGLfixed gglSqrtRecipx(GGLfixed x)
-{
- if (x == 0) return FIXED_MAX;
- if (x == FIXED_ONE) return x;
- const GGLfixed a = x;
- const int32_t lz = gglClz(x);
- x = ggl_sqrt_reciproc_approx_tab[(a>>(28-lz))&0x7];
- const int32_t exp = lz - 16;
- if (exp <= 0) x >>= -exp>>1;
- else x <<= (exp>>1) + (exp & 1);
- if (exp & 1) {
- x = gglMulx(x, ggl_sqrt_reciproc_approx_tab[0])>>1;
- }
- // 2 Newton-Raphson iterations: x = x/2*(3-(a*x)*x)
- x = gglMulx((x>>1),(0x30000 - gglMulx(gglMulx(a,x),x)));
- x = gglMulx((x>>1),(0x30000 - gglMulx(gglMulx(a,x),x)));
- return x;
-}
-
-GGLfixed gglSqrtx(GGLfixed a)
-{
- // Compute a full precision square-root (24 bits accuracy)
- GGLfixed r = 0;
- GGLfixed bit = 0x800000;
- int32_t bshift = 15;
- do {
- GGLfixed temp = bit + (r<<1);
- if (bshift >= 8) temp <<= (bshift-8);
- else temp >>= (8-bshift);
- if (a >= temp) {
- r += bit;
- a -= temp;
- }
- bshift--;
- } while (bit>>=1);
- return r;
-}
-
-// ------------------------------------------------------------------------
-
-static const GGLfixed ggl_log_approx_tab[] = {
- // -ln(x)/ln(2) with x = N/16, N=[8...16]
- 0xFFFF, 0xd47f, 0xad96, 0x8a62, 0x6a3f, 0x4caf, 0x3151, 0x17d6, 0x0000
-};
-
-static const GGLfixed ggl_alog_approx_tab[] = { // domain [0 - 1.0]
- 0xffff, 0xeac0, 0xd744, 0xc567, 0xb504, 0xa5fe, 0x9837, 0x8b95, 0x8000
-};
-
-GGLfixed gglPowx(GGLfixed x, GGLfixed y)
-{
- // prerequisite: 0 <= x <= 1, and y >=0
-
- // pow(x,y) = 2^(y*log2(x))
- // = 2^(y*log2(x*(2^exp)*(2^-exp))))
- // = 2^(y*(log2(X)-exp))
- // = 2^(log2(X)*y - y*exp)
- // = 2^( - (-log2(X)*y + y*exp) )
-
- int32_t exp = gglClz(x) - 16;
- GGLfixed f = x << exp;
- x = (f & 0x0FFF)<<4;
- f = (f >> 12) & 0x7;
- GGLfixed p = gglMulAddx(
- ggl_log_approx_tab[f+1] - ggl_log_approx_tab[f], x,
- ggl_log_approx_tab[f]);
- p = gglMulAddx(p, y, y*exp);
- exp = gglFixedToIntFloor(p);
- if (exp < 31) {
- p = gglFracx(p);
- x = (p & 0x1FFF)<<3;
- p >>= 13;
- p = gglMulAddx(
- ggl_alog_approx_tab[p+1] - ggl_alog_approx_tab[p], x,
- ggl_alog_approx_tab[p]);
- p >>= exp;
- } else {
- p = 0;
- }
- return p;
- // ( powf((a*65536.0f), (b*65536.0f)) ) * 65536.0f;
-}
-
-// ------------------------------------------------------------------------
-
-int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i)
-{
- //int32_t r =int32_t((int64_t(n)<<i)/d);
- const int32_t ds = n^d;
- if (n<0) n = -n;
- if (d<0) d = -d;
- int nd = gglClz(d) - gglClz(n);
- i += nd + 1;
- if (nd > 0) d <<= nd;
- else n <<= -nd;
- uint32_t q = 0;
-
- int j = i & 7;
- i >>= 3;
-
- // gcc deals with the code below pretty well.
- // we get 3.75 cycles per bit in the main loop
- // and 8 cycles per bit in the termination loop
- if (ggl_likely(i)) {
- n -= d;
- do {
- q <<= 8;
- if (n>=0) q |= 128;
- else n += d;
- n = n*2 - d;
- if (n>=0) q |= 64;
- else n += d;
- n = n*2 - d;
- if (n>=0) q |= 32;
- else n += d;
- n = n*2 - d;
- if (n>=0) q |= 16;
- else n += d;
- n = n*2 - d;
- if (n>=0) q |= 8;
- else n += d;
- n = n*2 - d;
- if (n>=0) q |= 4;
- else n += d;
- n = n*2 - d;
- if (n>=0) q |= 2;
- else n += d;
- n = n*2 - d;
- if (n>=0) q |= 1;
- else n += d;
-
- if (--i == 0)
- goto finish;
-
- n = n*2 - d;
- } while(true);
- do {
- q <<= 1;
- n = n*2 - d;
- if (n>=0) q |= 1;
- else n += d;
- finish: ;
- } while (j--);
- return (ds<0) ? -q : q;
- }
-
- n -= d;
- if (n>=0) q |= 1;
- else n += d;
- j--;
- goto finish;
-}
-
-// ------------------------------------------------------------------------
-
-// assumes that the int32_t values of a, b, and c are all positive
-// use when both a and b are larger than c
-
-template <typename T>
-static inline void swap(T& a, T& b) {
- T t(a);
- a = b;
- b = t;
-}
-
-static __attribute__((noinline))
-int32_t slow_muldiv(uint32_t a, uint32_t b, uint32_t c)
-{
- // first we compute a*b as a 64-bit integer
- // (GCC generates umull with the code below)
- uint64_t ab = uint64_t(a)*b;
- uint32_t hi = ab>>32;
- uint32_t lo = ab;
- uint32_t result;
-
- // now perform the division
- if (hi >= c) {
- overflow:
- result = 0x7fffffff; // basic overflow
- } else if (hi == 0) {
- result = lo/c; // note: c can't be 0
- if ((result >> 31) != 0) // result must fit in 31 bits
- goto overflow;
- } else {
- uint32_t r = hi;
- int bits = 31;
- result = 0;
- do {
- r = (r << 1) | (lo >> 31);
- lo <<= 1;
- result <<= 1;
- if (r >= c) {
- r -= c;
- result |= 1;
- }
- } while (bits--);
- }
- return int32_t(result);
-}
-
-// assumes a >= 0 and c >= b >= 0
-static inline
-int32_t quick_muldiv(int32_t a, int32_t b, int32_t c)
-{
- int32_t r = 0, q = 0, i;
- int leading = gglClz(a);
- i = 32 - leading;
- a <<= leading;
- do {
- r <<= 1;
- if (a < 0)
- r += b;
- a <<= 1;
- q <<= 1;
- if (r >= c) {
- r -= c;
- q++;
- }
- asm(""::); // gcc generates better code this way
- if (r >= c) {
- r -= c;
- q++;
- }
- }
- while (--i);
- return q;
-}
-
-// this function computes a*b/c with 64-bit intermediate accuracy
-// overflows (e.g. division by 0) are handled and return INT_MAX
-
-int32_t gglMulDivi(int32_t a, int32_t b, int32_t c)
-{
- int32_t result;
- int32_t sign = a^b^c;
-
- if (a < 0) a = -a;
- if (b < 0) b = -b;
- if (c < 0) c = -c;
-
- if (a < b) {
- swap(a, b);
- }
-
- if (b <= c) result = quick_muldiv(a, b, c);
- else result = slow_muldiv((uint32_t)a, (uint32_t)b, (uint32_t)c);
-
- if (sign < 0)
- result = -result;
-
- return result;
-}
diff --git a/libpixelflinger/format.cpp b/libpixelflinger/format.cpp
deleted file mode 100644
index 6546e8c..0000000
--- a/libpixelflinger/format.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/* libs/pixelflinger/format.cpp
-**
-** Copyright 2006, 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 <stdio.h>
-#include <pixelflinger/format.h>
-
-namespace android {
-
-static GGLFormat const gPixelFormatInfos[] =
-{ // Alpha Red Green Blue
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 4, 32, {{32,24, 8, 0, 16, 8, 24,16 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_8888
- { 4, 24, {{ 0, 0, 8, 0, 16, 8, 24,16 }}, GGL_RGB }, // PIXEL_FORMAT_RGBX_8888
- { 3, 24, {{ 0, 0, 8, 0, 16, 8, 24,16 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_888
- { 2, 16, {{ 0, 0, 16,11, 11, 5, 5, 0 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_565
- { 4, 32, {{32,24, 24,16, 16, 8, 8, 0 }}, GGL_RGBA }, // PIXEL_FORMAT_BGRA_8888
- { 2, 16, {{ 1, 0, 16,11, 11, 6, 6, 1 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_5551
- { 2, 16, {{ 4, 0, 16,12, 12, 8, 8, 4 }}, GGL_RGBA }, // PIXEL_FORMAT_RGBA_4444
- { 1, 8, {{ 8, 0, 0, 0, 0, 0, 0, 0 }}, GGL_ALPHA}, // PIXEL_FORMAT_A8
- { 1, 8, {{ 0, 0, 8, 0, 8, 0, 8, 0 }}, GGL_LUMINANCE},//PIXEL_FORMAT_L8
- { 2, 16, {{16, 8, 8, 0, 8, 0, 8, 0 }}, GGL_LUMINANCE_ALPHA},// PIXEL_FORMAT_LA_88
- { 1, 8, {{ 0, 0, 8, 5, 5, 2, 2, 0 }}, GGL_RGB }, // PIXEL_FORMAT_RGB_332
-
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
-
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
-
- { 2, 16, {{ 0, 0, 16, 0, 0, 0, 0, 0 }}, GGL_DEPTH_COMPONENT},
- { 1, 8, {{ 8, 0, 0, 0, 0, 0, 0, 0 }}, GGL_STENCIL_INDEX },
- { 4, 24, {{ 0, 0, 24, 0, 0, 0, 0, 0 }}, GGL_DEPTH_COMPONENT},
- { 4, 8, {{ 32,24, 0, 0, 0, 0, 0, 0 }}, GGL_STENCIL_INDEX },
-
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
-
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
- { 0, 0, {{ 0, 0, 0, 0, 0, 0, 0, 0 }}, 0 }, // PIXEL_FORMAT_NONE
-
-};
-
-}; // namespace android
-
-
-const GGLFormat* gglGetPixelFormatTable(size_t* numEntries)
-{
- if (numEntries) {
- *numEntries = sizeof(android::gPixelFormatInfos)/sizeof(GGLFormat);
- }
- return android::gPixelFormatInfos;
-}
diff --git a/libpixelflinger/include/pixelflinger/format.h b/libpixelflinger/include/pixelflinger/format.h
deleted file mode 100644
index d429477..0000000
--- a/libpixelflinger/include/pixelflinger/format.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_PIXELFLINGER_FORMAT_H
-#define ANDROID_PIXELFLINGER_FORMAT_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-enum GGLPixelFormat {
- // these constants need to match those
- // in graphics/PixelFormat.java, ui/PixelFormat.h, BlitHardware.h
- GGL_PIXEL_FORMAT_UNKNOWN = 0,
- GGL_PIXEL_FORMAT_NONE = 0,
-
- GGL_PIXEL_FORMAT_RGBA_8888 = 1, // 4x8-bit ARGB
- GGL_PIXEL_FORMAT_RGBX_8888 = 2, // 3x8-bit RGB stored in 32-bit chunks
- GGL_PIXEL_FORMAT_RGB_888 = 3, // 3x8-bit RGB
- GGL_PIXEL_FORMAT_RGB_565 = 4, // 16-bit RGB
- GGL_PIXEL_FORMAT_BGRA_8888 = 5, // 4x8-bit BGRA
- GGL_PIXEL_FORMAT_RGBA_5551 = 6, // 16-bit RGBA
- GGL_PIXEL_FORMAT_RGBA_4444 = 7, // 16-bit RGBA
-
- GGL_PIXEL_FORMAT_A_8 = 8, // 8-bit A
- GGL_PIXEL_FORMAT_L_8 = 9, // 8-bit L (R=G=B = L)
- GGL_PIXEL_FORMAT_LA_88 = 0xA, // 16-bit LA
- GGL_PIXEL_FORMAT_RGB_332 = 0xB, // 8-bit RGB (non paletted)
-
- // reserved range. don't use.
- GGL_PIXEL_FORMAT_RESERVED_10 = 0x10,
- GGL_PIXEL_FORMAT_RESERVED_11 = 0x11,
- GGL_PIXEL_FORMAT_RESERVED_12 = 0x12,
- GGL_PIXEL_FORMAT_RESERVED_13 = 0x13,
- GGL_PIXEL_FORMAT_RESERVED_14 = 0x14,
- GGL_PIXEL_FORMAT_RESERVED_15 = 0x15,
- GGL_PIXEL_FORMAT_RESERVED_16 = 0x16,
- GGL_PIXEL_FORMAT_RESERVED_17 = 0x17,
-
- // reserved/special formats
- GGL_PIXEL_FORMAT_Z_16 = 0x18,
- GGL_PIXEL_FORMAT_S_8 = 0x19,
- GGL_PIXEL_FORMAT_SZ_24 = 0x1A,
- GGL_PIXEL_FORMAT_SZ_8 = 0x1B,
-
- // reserved range. don't use.
- GGL_PIXEL_FORMAT_RESERVED_20 = 0x20,
- GGL_PIXEL_FORMAT_RESERVED_21 = 0x21,
-};
-
-enum GGLFormatComponents {
- GGL_STENCIL_INDEX = 0x1901,
- GGL_DEPTH_COMPONENT = 0x1902,
- GGL_ALPHA = 0x1906,
- GGL_RGB = 0x1907,
- GGL_RGBA = 0x1908,
- GGL_LUMINANCE = 0x1909,
- GGL_LUMINANCE_ALPHA = 0x190A,
-};
-
-enum GGLFormatComponentIndex {
- GGL_INDEX_ALPHA = 0,
- GGL_INDEX_RED = 1,
- GGL_INDEX_GREEN = 2,
- GGL_INDEX_BLUE = 3,
- GGL_INDEX_STENCIL = 0,
- GGL_INDEX_DEPTH = 1,
- GGL_INDEX_Y = 0,
- GGL_INDEX_CB = 1,
- GGL_INDEX_CR = 2,
-};
-
-typedef struct GGLFormat {
-#ifdef __cplusplus
- enum {
- ALPHA = GGL_INDEX_ALPHA,
- RED = GGL_INDEX_RED,
- GREEN = GGL_INDEX_GREEN,
- BLUE = GGL_INDEX_BLUE,
- STENCIL = GGL_INDEX_STENCIL,
- DEPTH = GGL_INDEX_DEPTH,
- LUMA = GGL_INDEX_Y,
- CHROMAB = GGL_INDEX_CB,
- CHROMAR = GGL_INDEX_CR,
- };
- inline uint32_t mask(int i) const {
- return ((1<<(c[i].h-c[i].l))-1)<<c[i].l;
- }
- inline uint32_t bits(int i) const {
- return c[i].h - c[i].l;
- }
-#endif
- uint8_t size; // bytes per pixel
- uint8_t bitsPerPixel;
- union {
- struct {
- uint8_t ah; // alpha high bit position + 1
- uint8_t al; // alpha low bit position
- uint8_t rh; // red high bit position + 1
- uint8_t rl; // red low bit position
- uint8_t gh; // green high bit position + 1
- uint8_t gl; // green low bit position
- uint8_t bh; // blue high bit position + 1
- uint8_t bl; // blue low bit position
- };
- struct {
- uint8_t h;
- uint8_t l;
- } __attribute__((__packed__)) c[4];
- } __attribute__((__packed__));
- uint16_t components; // GGLFormatComponents
-} GGLFormat;
-
-
-#ifdef __cplusplus
-extern "C" const GGLFormat* gglGetPixelFormatTable(size_t* numEntries = 0);
-#else
-const GGLFormat* gglGetPixelFormatTable(size_t* numEntries);
-#endif
-
-
-// ----------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_FORMAT_H
diff --git a/libpixelflinger/include/pixelflinger/pixelflinger.h b/libpixelflinger/include/pixelflinger/pixelflinger.h
deleted file mode 100644
index 8a2b442..0000000
--- a/libpixelflinger/include/pixelflinger/pixelflinger.h
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2007 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 ANDROID_PIXELFLINGER_H
-#define ANDROID_PIXELFLINGER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <pixelflinger/format.h>
-
-// GGL types
-
-typedef int8_t GGLbyte; // b
-typedef int16_t GGLshort; // s
-typedef int32_t GGLint; // i
-typedef ssize_t GGLsizei; // i
-typedef int32_t GGLfixed; // x
-typedef int32_t GGLclampx; // x
-typedef float GGLfloat; // f
-typedef float GGLclampf; // f
-typedef double GGLdouble; // d
-typedef double GGLclampd; // d
-typedef uint8_t GGLubyte; // ub
-typedef uint8_t GGLboolean; // ub
-typedef uint16_t GGLushort; // us
-typedef uint32_t GGLuint; // ui
-typedef unsigned int GGLenum; // ui
-typedef unsigned int GGLbitfield; // ui
-typedef void GGLvoid;
-typedef int32_t GGLfixed32;
-typedef int32_t GGLcolor;
-typedef int32_t GGLcoord;
-
-// ----------------------------------------------------------------------------
-
-#define GGL_MAX_VIEWPORT_DIMS 4096
-#define GGL_MAX_TEXTURE_SIZE 4096
-#define GGL_MAX_ALIASED_POINT_SIZE 0x7FFFFFF
-#define GGL_MAX_SMOOTH_POINT_SIZE 2048
-#define GGL_MAX_SMOOTH_LINE_WIDTH 2048
-
-// ----------------------------------------------------------------------------
-
-// All these names are compatible with their OpenGL equivalents
-// some of them are listed only for completeness
-enum GGLNames {
- GGL_FALSE = 0,
- GGL_TRUE = 1,
-
- // enable/disable
- GGL_SCISSOR_TEST = 0x0C11,
- GGL_TEXTURE_2D = 0x0DE1,
- GGL_ALPHA_TEST = 0x0BC0,
- GGL_BLEND = 0x0BE2,
- GGL_COLOR_LOGIC_OP = 0x0BF2,
- GGL_DITHER = 0x0BD0,
- GGL_STENCIL_TEST = 0x0B90,
- GGL_DEPTH_TEST = 0x0B71,
- GGL_AA = 0x80000001,
- GGL_W_LERP = 0x80000004,
- GGL_POINT_SMOOTH_NICE = 0x80000005,
-
- // buffers, pixel drawing/reading
- GGL_COLOR = 0x1800,
-
- // fog
- GGL_FOG = 0x0B60,
-
- // shade model
- GGL_FLAT = 0x1D00,
- GGL_SMOOTH = 0x1D01,
-
- // Texture parameter name
- GGL_TEXTURE_MIN_FILTER = 0x2801,
- GGL_TEXTURE_MAG_FILTER = 0x2800,
- GGL_TEXTURE_WRAP_S = 0x2802,
- GGL_TEXTURE_WRAP_T = 0x2803,
- GGL_TEXTURE_WRAP_R = 0x2804,
-
- // Texture Filter
- GGL_NEAREST = 0x2600,
- GGL_LINEAR = 0x2601,
- GGL_NEAREST_MIPMAP_NEAREST = 0x2700,
- GGL_LINEAR_MIPMAP_NEAREST = 0x2701,
- GGL_NEAREST_MIPMAP_LINEAR = 0x2702,
- GGL_LINEAR_MIPMAP_LINEAR = 0x2703,
-
- // Texture Wrap Mode
- GGL_CLAMP = 0x2900,
- GGL_REPEAT = 0x2901,
- GGL_CLAMP_TO_EDGE = 0x812F,
-
- // Texture Env Mode
- GGL_REPLACE = 0x1E01,
- GGL_MODULATE = 0x2100,
- GGL_DECAL = 0x2101,
- GGL_ADD = 0x0104,
-
- // Texture Env Parameter
- GGL_TEXTURE_ENV_MODE = 0x2200,
- GGL_TEXTURE_ENV_COLOR = 0x2201,
-
- // Texture Env Target
- GGL_TEXTURE_ENV = 0x2300,
-
- // Texture coord generation
- GGL_TEXTURE_GEN_MODE = 0x2500,
- GGL_S = 0x2000,
- GGL_T = 0x2001,
- GGL_R = 0x2002,
- GGL_Q = 0x2003,
- GGL_ONE_TO_ONE = 0x80000002,
- GGL_AUTOMATIC = 0x80000003,
-
- // AlphaFunction
- GGL_NEVER = 0x0200,
- GGL_LESS = 0x0201,
- GGL_EQUAL = 0x0202,
- GGL_LEQUAL = 0x0203,
- GGL_GREATER = 0x0204,
- GGL_NOTEQUAL = 0x0205,
- GGL_GEQUAL = 0x0206,
- GGL_ALWAYS = 0x0207,
-
- // LogicOp
- GGL_CLEAR = 0x1500, // 0
- GGL_AND = 0x1501, // s & d
- GGL_AND_REVERSE = 0x1502, // s & ~d
- GGL_COPY = 0x1503, // s
- GGL_AND_INVERTED = 0x1504, // ~s & d
- GGL_NOOP = 0x1505, // d
- GGL_XOR = 0x1506, // s ^ d
- GGL_OR = 0x1507, // s | d
- GGL_NOR = 0x1508, // ~(s | d)
- GGL_EQUIV = 0x1509, // ~(s ^ d)
- GGL_INVERT = 0x150A, // ~d
- GGL_OR_REVERSE = 0x150B, // s | ~d
- GGL_COPY_INVERTED = 0x150C, // ~s
- GGL_OR_INVERTED = 0x150D, // ~s | d
- GGL_NAND = 0x150E, // ~(s & d)
- GGL_SET = 0x150F, // 1
-
- // blending equation & function
- GGL_ZERO = 0, // SD
- GGL_ONE = 1, // SD
- GGL_SRC_COLOR = 0x0300, // D
- GGL_ONE_MINUS_SRC_COLOR = 0x0301, // D
- GGL_SRC_ALPHA = 0x0302, // SD
- GGL_ONE_MINUS_SRC_ALPHA = 0x0303, // SD
- GGL_DST_ALPHA = 0x0304, // SD
- GGL_ONE_MINUS_DST_ALPHA = 0x0305, // SD
- GGL_DST_COLOR = 0x0306, // S
- GGL_ONE_MINUS_DST_COLOR = 0x0307, // S
- GGL_SRC_ALPHA_SATURATE = 0x0308, // S
-
- // clear bits
- GGL_DEPTH_BUFFER_BIT = 0x00000100,
- GGL_STENCIL_BUFFER_BIT = 0x00000400,
- GGL_COLOR_BUFFER_BIT = 0x00004000,
-
- // errors
- GGL_NO_ERROR = 0,
- GGL_INVALID_ENUM = 0x0500,
- GGL_INVALID_VALUE = 0x0501,
- GGL_INVALID_OPERATION = 0x0502,
- GGL_STACK_OVERFLOW = 0x0503,
- GGL_STACK_UNDERFLOW = 0x0504,
- GGL_OUT_OF_MEMORY = 0x0505
-};
-
-// ----------------------------------------------------------------------------
-
-typedef struct {
- GGLsizei version; // always set to sizeof(GGLSurface)
- GGLuint width; // width in pixels
- GGLuint height; // height in pixels
- GGLint stride; // stride in pixels
- GGLubyte* data; // pointer to the bits
- GGLubyte format; // pixel format
- GGLubyte rfu[3]; // must be zero
- // these values are dependent on the used format
- union {
- GGLint compressedFormat;
- GGLint vstride;
- };
- void* reserved;
-} GGLSurface;
-
-
-typedef struct {
- // immediate rendering
- void (*pointx)(void *con, const GGLcoord* v, GGLcoord r);
- void (*linex)(void *con,
- const GGLcoord* v0, const GGLcoord* v1, GGLcoord width);
- void (*recti)(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
- void (*trianglex)(void* c,
- GGLcoord const* v0, GGLcoord const* v1, GGLcoord const* v2);
-
- // scissor
- void (*scissor)(void* c, GGLint x, GGLint y, GGLsizei width, GGLsizei height);
-
- // Set the textures and color buffers
- void (*activeTexture)(void* c, GGLuint tmu);
- void (*bindTexture)(void* c, const GGLSurface* surface);
- void (*colorBuffer)(void* c, const GGLSurface* surface);
- void (*readBuffer)(void* c, const GGLSurface* surface);
- void (*depthBuffer)(void* c, const GGLSurface* surface);
- void (*bindTextureLod)(void* c, GGLuint tmu, const GGLSurface* surface);
-
- // enable/disable features
- void (*enable)(void* c, GGLenum name);
- void (*disable)(void* c, GGLenum name);
- void (*enableDisable)(void* c, GGLenum name, GGLboolean en);
-
- // specify the fragment's color
- void (*shadeModel)(void* c, GGLenum mode);
- void (*color4xv)(void* c, const GGLclampx* color);
- // specify color iterators (16.16)
- void (*colorGrad12xv)(void* c, const GGLcolor* grad);
-
- // specify Z coordinate iterators (0.32)
- void (*zGrad3xv)(void* c, const GGLfixed32* grad);
-
- // specify W coordinate iterators (16.16)
- void (*wGrad3xv)(void* c, const GGLfixed* grad);
-
- // specify fog iterator & color (16.16)
- void (*fogGrad3xv)(void* c, const GGLfixed* grad);
- void (*fogColor3xv)(void* c, const GGLclampx* color);
-
- // specify blending parameters
- void (*blendFunc)(void* c, GGLenum src, GGLenum dst);
- void (*blendFuncSeparate)(void* c, GGLenum src, GGLenum dst,
- GGLenum srcAlpha, GGLenum dstAplha);
-
- // texture environnement (REPLACE / MODULATE / DECAL / BLEND)
- void (*texEnvi)(void* c, GGLenum target,
- GGLenum pname,
- GGLint param);
-
- void (*texEnvxv)(void* c, GGLenum target,
- GGLenum pname, const GGLfixed* params);
-
- // texture parameters (Wrapping, filter)
- void (*texParameteri)(void* c, GGLenum target,
- GGLenum pname,
- GGLint param);
-
- // texture iterators (16.16)
- void (*texCoord2i)(void* c, GGLint s, GGLint t);
- void (*texCoord2x)(void* c, GGLfixed s, GGLfixed t);
-
- // s, dsdx, dsdy, scale, t, dtdx, dtdy, tscale
- // This api uses block floating-point for S and T texture coordinates.
- // All values are given in 16.16, scaled by 'scale'. In other words,
- // set scale to 0, for 16.16 values.
- void (*texCoordGradScale8xv)(void* c, GGLint tmu, const int32_t* grad8);
-
- void (*texGeni)(void* c, GGLenum coord, GGLenum pname, GGLint param);
-
- // masking
- void (*colorMask)(void* c, GGLboolean red,
- GGLboolean green,
- GGLboolean blue,
- GGLboolean alpha);
-
- void (*depthMask)(void* c, GGLboolean flag);
-
- void (*stencilMask)(void* c, GGLuint mask);
-
- // alpha func
- void (*alphaFuncx)(void* c, GGLenum func, GGLclampx ref);
-
- // depth func
- void (*depthFunc)(void* c, GGLenum func);
-
- // logic op
- void (*logicOp)(void* c, GGLenum opcode);
-
- // clear
- void (*clear)(void* c, GGLbitfield mask);
- void (*clearColorx)(void* c,
- GGLclampx r, GGLclampx g, GGLclampx b, GGLclampx a);
- void (*clearDepthx)(void* c, GGLclampx depth);
- void (*clearStencil)(void* c, GGLint s);
-
- // framebuffer operations
- void (*copyPixels)(void* c, GGLint x, GGLint y,
- GGLsizei width, GGLsizei height, GGLenum type);
- void (*rasterPos2x)(void* c, GGLfixed x, GGLfixed y);
- void (*rasterPos2i)(void* c, GGLint x, GGLint y);
-} GGLContext;
-
-// ----------------------------------------------------------------------------
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// construct / destroy the context
-ssize_t gglInit(GGLContext** context);
-ssize_t gglUninit(GGLContext* context);
-
-GGLint gglBitBlit(
- GGLContext* c,
- int tmu,
- GGLint crop[4],
- GGLint where[4]);
-
-#ifdef __cplusplus
-};
-#endif
-
-// ----------------------------------------------------------------------------
-
-#endif // ANDROID_PIXELFLINGER_H
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_context.h b/libpixelflinger/include/private/pixelflinger/ggl_context.h
deleted file mode 100644
index 563b0f1..0000000
--- a/libpixelflinger/include/private/pixelflinger/ggl_context.h
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright (C) 2006 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 ANDROID_GGL_CONTEXT_H
-#define ANDROID_GGL_CONTEXT_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/types.h>
-#include <endian.h>
-
-#include <pixelflinger/pixelflinger.h>
-#include <private/pixelflinger/ggl_fixed.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-
-inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) {
- return v;
-}
-inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) {
- return v;
-}
-
-#else
-
-inline uint32_t GGL_RGBA_TO_HOST(uint32_t v) {
-#if defined(__mips__) && __mips_isa_rev>=2
- uint32_t r;
- __asm__("wsbh %0, %1;"
- "rotr %0, %0, 16"
- : "=r" (r)
- : "r" (v)
- );
- return r;
-#else
- return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
-#endif
-}
-inline uint32_t GGL_HOST_TO_RGBA(uint32_t v) {
-#if defined(__mips__) && __mips_isa_rev>=2
- uint32_t r;
- __asm__("wsbh %0, %1;"
- "rotr %0, %0, 16"
- : "=r" (r)
- : "r" (v)
- );
- return r;
-#else
- return (v<<24) | (v>>24) | ((v<<8)&0xff0000) | ((v>>8)&0xff00);
-#endif
-}
-
-#endif
-
-// ----------------------------------------------------------------------------
-
-const int GGL_DITHER_BITS = 6; // dither weights stored on 6 bits
-const int GGL_DITHER_ORDER_SHIFT= 3;
-const int GGL_DITHER_ORDER = (1<<GGL_DITHER_ORDER_SHIFT);
-const int GGL_DITHER_SIZE = GGL_DITHER_ORDER * GGL_DITHER_ORDER;
-const int GGL_DITHER_MASK = GGL_DITHER_ORDER-1;
-
-// ----------------------------------------------------------------------------
-
-const int GGL_SUBPIXEL_BITS = 4;
-
-// TRI_FRACTION_BITS defines the number of bits we want to use
-// for the sub-pixel coordinates during the edge stepping, the
-// value shouldn't be more than 7, or bad things are going to
-// happen when drawing large triangles (8 doesn't work because
-// 32 bit muls will loose the sign bit)
-
-#define TRI_FRACTION_BITS (GGL_SUBPIXEL_BITS)
-#define TRI_ONE (1 << TRI_FRACTION_BITS)
-#define TRI_HALF (1 << (TRI_FRACTION_BITS-1))
-#define TRI_FROM_INT(x) ((x) << TRI_FRACTION_BITS)
-#define TRI_FRAC(x) ((x) & (TRI_ONE-1))
-#define TRI_FLOOR(x) ((x) & ~(TRI_ONE-1))
-#define TRI_CEIL(x) (((x) + (TRI_ONE-1)) & ~(TRI_ONE-1))
-#define TRI_ROUND(x) (((x) + TRI_HALF ) & ~(TRI_ONE-1))
-
-#define TRI_ROUDNING (1 << (16 - TRI_FRACTION_BITS - 1))
-#define TRI_FROM_FIXED(x) (((x)+TRI_ROUDNING) >> (16-TRI_FRACTION_BITS))
-
-#define TRI_SNAP_NEXT_HALF(x) (TRI_CEIL((x)+TRI_HALF) - TRI_HALF)
-#define TRI_SNAP_PREV_HALF(x) (TRI_CEIL((x)-TRI_HALF) - TRI_HALF)
-
-// ----------------------------------------------------------------------------
-
-const int GGL_COLOR_BITS = 24;
-
-// To maintain 8-bits color chanels, with a maximum GGLSurface
-// size of 4096 and GGL_SUBPIXEL_BITS=4, we need 8 + 12 + 4 = 24 bits
-// for encoding the color iterators
-
-inline GGLcolor gglFixedToIteratedColor(GGLfixed c) {
- return (c << 8) - c;
-}
-
-// ----------------------------------------------------------------------------
-
-template<bool> struct CTA;
-template<> struct CTA<true> { };
-
-#define GGL_CONTEXT(con, c) context_t *(con) = static_cast<context_t *>(c) /* NOLINT */
-#define GGL_OFFSETOF(field) uintptr_t(&(((context_t*)0)->field))
-#define GGL_INIT_PROC(p, f) p.f = ggl_ ## f;
-#define GGL_BETWEEN(x, L, H) (uint32_t((x)-(L)) <= ((H)-(L)))
-
-#define ggl_likely(x) __builtin_expect(!!(x), 1)
-#define ggl_unlikely(x) __builtin_expect(!!(x), 0)
-
-const int GGL_TEXTURE_UNIT_COUNT = 2;
-const int GGL_TMU_STATE = 0x00000001;
-const int GGL_CB_STATE = 0x00000002;
-const int GGL_PIXEL_PIPELINE_STATE = 0x00000004;
-
-// ----------------------------------------------------------------------------
-
-#define GGL_RESERVE_NEEDS(name, l, s) \
- const uint32_t GGL_NEEDS_##name##_MASK = (((1LU<<(s))-1)<<(l)); \
- const uint32_t GGL_NEEDS_##name##_SHIFT = (l);
-
-#define GGL_BUILD_NEEDS(val, name) \
- (((val)<<(GGL_NEEDS_##name##_SHIFT)) & GGL_NEEDS_##name##_MASK)
-
-#define GGL_READ_NEEDS(name, n) \
- (uint32_t((n) & GGL_NEEDS_##name##_MASK) >> GGL_NEEDS_##name##_SHIFT)
-
-#define GGL_NEED_MASK(name) (uint32_t(GGL_NEEDS_##name##_MASK))
-#define GGL_NEED(name, val) GGL_BUILD_NEEDS(val, name)
-
-GGL_RESERVE_NEEDS( CB_FORMAT, 0, 6 )
-GGL_RESERVE_NEEDS( SHADE, 6, 1 )
-GGL_RESERVE_NEEDS( W, 7, 1 )
-GGL_RESERVE_NEEDS( BLEND_SRC, 8, 4 )
-GGL_RESERVE_NEEDS( BLEND_DST, 12, 4 )
-GGL_RESERVE_NEEDS( BLEND_SRCA, 16, 4 )
-GGL_RESERVE_NEEDS( BLEND_DSTA, 20, 4 )
-GGL_RESERVE_NEEDS( LOGIC_OP, 24, 4 )
-GGL_RESERVE_NEEDS( MASK_ARGB, 28, 4 )
-
-GGL_RESERVE_NEEDS( P_ALPHA_TEST, 0, 3 )
-GGL_RESERVE_NEEDS( P_AA, 3, 1 )
-GGL_RESERVE_NEEDS( P_DEPTH_TEST, 4, 3 )
-GGL_RESERVE_NEEDS( P_MASK_Z, 7, 1 )
-GGL_RESERVE_NEEDS( P_DITHER, 8, 1 )
-GGL_RESERVE_NEEDS( P_FOG, 9, 1 )
-GGL_RESERVE_NEEDS( P_RESERVED1, 10,22 )
-
-GGL_RESERVE_NEEDS( T_FORMAT, 0, 6 )
-GGL_RESERVE_NEEDS( T_RESERVED0, 6, 1 )
-GGL_RESERVE_NEEDS( T_POT, 7, 1 )
-GGL_RESERVE_NEEDS( T_S_WRAP, 8, 2 )
-GGL_RESERVE_NEEDS( T_T_WRAP, 10, 2 )
-GGL_RESERVE_NEEDS( T_ENV, 12, 3 )
-GGL_RESERVE_NEEDS( T_LINEAR, 15, 1 )
-
-const int GGL_NEEDS_WRAP_CLAMP_TO_EDGE = 0;
-const int GGL_NEEDS_WRAP_REPEAT = 1;
-const int GGL_NEEDS_WRAP_11 = 2;
-
-inline uint32_t ggl_wrap_to_needs(uint32_t e) {
- switch (e) {
- case GGL_CLAMP: return GGL_NEEDS_WRAP_CLAMP_TO_EDGE;
- case GGL_REPEAT: return GGL_NEEDS_WRAP_REPEAT;
- }
- return 0;
-}
-
-inline uint32_t ggl_blendfactor_to_needs(uint32_t b) {
- if (b <= 1) return b;
- return (b & 0xF)+2;
-}
-
-inline uint32_t ggl_needs_to_blendfactor(uint32_t n) {
- if (n <= 1) return n;
- return (n - 2) + 0x300;
-}
-
-inline uint32_t ggl_env_to_needs(uint32_t e) {
- switch (e) {
- case GGL_REPLACE: return 0;
- case GGL_MODULATE: return 1;
- case GGL_DECAL: return 2;
- case GGL_BLEND: return 3;
- case GGL_ADD: return 4;
- }
- return 0;
-}
-
-inline uint32_t ggl_needs_to_env(uint32_t n) {
- const uint32_t envs[] = { GGL_REPLACE, GGL_MODULATE,
- GGL_DECAL, GGL_BLEND, GGL_ADD };
- return envs[n];
-
-}
-
-// ----------------------------------------------------------------------------
-
-enum {
- GGL_ENABLE_BLENDING = 0x00000001,
- GGL_ENABLE_SMOOTH = 0x00000002,
- GGL_ENABLE_AA = 0x00000004,
- GGL_ENABLE_LOGIC_OP = 0x00000008,
- GGL_ENABLE_ALPHA_TEST = 0x00000010,
- GGL_ENABLE_SCISSOR_TEST = 0x00000020,
- GGL_ENABLE_TMUS = 0x00000040,
- GGL_ENABLE_DEPTH_TEST = 0x00000080,
- GGL_ENABLE_STENCIL_TEST = 0x00000100,
- GGL_ENABLE_W = 0x00000200,
- GGL_ENABLE_DITHER = 0x00000400,
- GGL_ENABLE_FOG = 0x00000800,
- GGL_ENABLE_POINT_AA_NICE= 0x00001000
-};
-
-// ----------------------------------------------------------------------------
-
-struct needs_filter_t;
-struct needs_t {
- inline int match(const needs_filter_t& filter);
- inline bool operator == (const needs_t& rhs) const {
- return (n==rhs.n) &&
- (p==rhs.p) &&
- (t[0]==rhs.t[0]) &&
- (t[1]==rhs.t[1]);
- }
- inline bool operator != (const needs_t& rhs) const {
- return !operator == (rhs);
- }
- uint32_t n;
- uint32_t p;
- uint32_t t[GGL_TEXTURE_UNIT_COUNT];
-};
-
-inline int compare_type(const needs_t& lhs, const needs_t& rhs) {
- return memcmp(&lhs, &rhs, sizeof(needs_t));
-}
-
-struct needs_filter_t {
- needs_t value;
- needs_t mask;
-};
-
-int needs_t::match(const needs_filter_t& filter) {
- uint32_t result =
- ((filter.value.n ^ n) & filter.mask.n) |
- ((filter.value.p ^ p) & filter.mask.p) |
- ((filter.value.t[0] ^ t[0]) & filter.mask.t[0]) |
- ((filter.value.t[1] ^ t[1]) & filter.mask.t[1]);
- return (result == 0);
-}
-
-// ----------------------------------------------------------------------------
-
-struct context_t;
-class Assembly;
-
-struct blend_state_t {
- uint32_t src;
- uint32_t dst;
- uint32_t src_alpha;
- uint32_t dst_alpha;
- uint8_t reserved;
- uint8_t alpha_separate;
- uint8_t operation;
- uint8_t equation;
-};
-
-struct mask_state_t {
- uint8_t color;
- uint8_t depth;
- uint32_t stencil;
-};
-
-struct clear_state_t {
- GGLclampx r;
- GGLclampx g;
- GGLclampx b;
- GGLclampx a;
- GGLclampx depth;
- GGLint stencil;
- uint32_t colorPacked;
- uint32_t depthPacked;
- uint32_t stencilPacked;
- uint32_t dirty;
-};
-
-struct fog_state_t {
- uint8_t color[4];
-};
-
-struct logic_op_state_t {
- uint16_t opcode;
-};
-
-struct alpha_test_state_t {
- uint16_t func;
- GGLcolor ref;
-};
-
-struct depth_test_state_t {
- uint16_t func;
- GGLclampx clearValue;
-};
-
-struct scissor_t {
- uint32_t user_left;
- uint32_t user_right;
- uint32_t user_top;
- uint32_t user_bottom;
- uint32_t left;
- uint32_t right;
- uint32_t top;
- uint32_t bottom;
-};
-
-struct pixel_t {
- uint32_t c[4];
- uint8_t s[4];
-};
-
-struct surface_t {
- union {
- GGLSurface s;
- // Keep the following struct field types in line with the corresponding
- // GGLSurface fields to avoid mismatches leading to errors.
- struct {
- GGLsizei reserved;
- GGLuint width;
- GGLuint height;
- GGLint stride;
- GGLubyte* data;
- GGLubyte format;
- GGLubyte dirty;
- GGLubyte pad[2];
- };
- };
- void (*read) (const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, pixel_t* pixel);
- void (*write)(const surface_t* s, context_t* c,
- uint32_t x, uint32_t y, const pixel_t* pixel);
-};
-
-// ----------------------------------------------------------------------------
-
-struct texture_shade_t {
- union {
- struct {
- int32_t is0;
- int32_t idsdx;
- int32_t idsdy;
- int sscale;
- int32_t it0;
- int32_t idtdx;
- int32_t idtdy;
- int tscale;
- };
- struct {
- int32_t v;
- int32_t dx;
- int32_t dy;
- int scale;
- } st[2];
- };
-};
-
-struct texture_iterators_t {
- // these are not encoded in the same way than in the
- // texture_shade_t structure
- union {
- struct {
- GGLfixed ydsdy;
- GGLfixed dsdx;
- GGLfixed dsdy;
- int sscale;
- GGLfixed ydtdy;
- GGLfixed dtdx;
- GGLfixed dtdy;
- int tscale;
- };
- struct {
- GGLfixed ydvdy;
- GGLfixed dvdx;
- GGLfixed dvdy;
- int scale;
- } st[2];
- };
-};
-
-struct texture_t {
- surface_t surface;
- texture_iterators_t iterators;
- texture_shade_t shade;
- uint32_t s_coord;
- uint32_t t_coord;
- uint16_t s_wrap;
- uint16_t t_wrap;
- uint16_t min_filter;
- uint16_t mag_filter;
- uint16_t env;
- uint8_t env_color[4];
- uint8_t enable;
- uint8_t dirty;
-};
-
-struct raster_t {
- GGLfixed x;
- GGLfixed y;
-};
-
-struct framebuffer_t {
- surface_t color;
- surface_t read;
- surface_t depth;
- surface_t stencil;
- int16_t *coverage;
- size_t coverageBufferSize;
-};
-
-// ----------------------------------------------------------------------------
-
-struct iterators_t {
- int32_t xl;
- int32_t xr;
- int32_t y;
- GGLcolor ydady;
- GGLcolor ydrdy;
- GGLcolor ydgdy;
- GGLcolor ydbdy;
- GGLfixed ydzdy;
- GGLfixed ydwdy;
- GGLfixed ydfdy;
-};
-
-struct shade_t {
- GGLcolor a0;
- GGLcolor dadx;
- GGLcolor dady;
- GGLcolor r0;
- GGLcolor drdx;
- GGLcolor drdy;
- GGLcolor g0;
- GGLcolor dgdx;
- GGLcolor dgdy;
- GGLcolor b0;
- GGLcolor dbdx;
- GGLcolor dbdy;
- uint32_t z0;
- GGLfixed32 dzdx;
- GGLfixed32 dzdy;
- GGLfixed w0;
- GGLfixed dwdx;
- GGLfixed dwdy;
- uint32_t f0;
- GGLfixed dfdx;
- GGLfixed dfdy;
-};
-
-// these are used in the generated code
-// we use this mirror structure to improve
-// data locality in the pixel pipeline
-struct generated_tex_vars_t {
- uint32_t width;
- uint32_t height;
- uint32_t stride;
- uintptr_t data;
- int32_t dsdx;
- int32_t dtdx;
- int32_t spill[2];
-};
-
-struct generated_vars_t {
- struct {
- int32_t c;
- int32_t dx;
- } argb[4];
- int32_t aref;
- int32_t dzdx;
- int32_t zbase;
- int32_t f;
- int32_t dfdx;
- int32_t spill[3];
- generated_tex_vars_t texture[GGL_TEXTURE_UNIT_COUNT];
- int32_t rt;
- int32_t lb;
-};
-
-// ----------------------------------------------------------------------------
-
-struct state_t {
- framebuffer_t buffers;
- texture_t texture[GGL_TEXTURE_UNIT_COUNT];
- scissor_t scissor;
- raster_t raster;
- blend_state_t blend;
- alpha_test_state_t alpha_test;
- depth_test_state_t depth_test;
- mask_state_t mask;
- clear_state_t clear;
- fog_state_t fog;
- logic_op_state_t logic_op;
- uint32_t enables;
- uint32_t enabled_tmu;
- needs_t needs;
-};
-
-// ----------------------------------------------------------------------------
-
-struct context_t {
- GGLContext procs;
- state_t state;
- shade_t shade;
- iterators_t iterators;
- generated_vars_t generated_vars __attribute__((aligned(32)));
- uint8_t ditherMatrix[GGL_DITHER_SIZE] __attribute__((aligned(32)));
- uint32_t packed;
- uint32_t packed8888;
- const GGLFormat* formats;
- uint32_t dirty;
- texture_t* activeTMU;
- uint32_t activeTMUIndex;
-
- void (*init_y)(context_t* c, int32_t y);
- void (*step_y)(context_t* c);
- void (*scanline)(context_t* c);
- void (*span)(context_t* c);
- void (*rect)(context_t* c, size_t yc);
-
- void* base;
- Assembly* scanline_as;
- GGLenum error;
-};
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_context(context_t* context);
-void ggl_uninit_context(context_t* context);
-void ggl_error(context_t* c, GGLenum error);
-int64_t ggl_system_time();
-
-// ----------------------------------------------------------------------------
-
-};
-
-#endif // ANDROID_GGL_CONTEXT_H
-
diff --git a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h b/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
deleted file mode 100644
index 4217a89..0000000
--- a/libpixelflinger/include/private/pixelflinger/ggl_fixed.h
+++ /dev/null
@@ -1,878 +0,0 @@
-/*
- * Copyright (C) 2005 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 ANDROID_GGL_FIXED_H
-#define ANDROID_GGL_FIXED_H
-
-#include <math.h>
-#include <pixelflinger/pixelflinger.h>
-
-// ----------------------------------------------------------------------------
-
-#define CONST __attribute__((const))
-#define ALWAYS_INLINE __attribute__((always_inline))
-
-const GGLfixed FIXED_BITS = 16;
-const GGLfixed FIXED_EPSILON = 1;
-const GGLfixed FIXED_ONE = 1L<<FIXED_BITS;
-const GGLfixed FIXED_HALF = 1L<<(FIXED_BITS-1);
-const GGLfixed FIXED_MIN = 0x80000000L;
-const GGLfixed FIXED_MAX = 0x7FFFFFFFL;
-
-inline GGLfixed gglIntToFixed(GGLfixed i) ALWAYS_INLINE ;
-inline GGLfixed gglFixedToIntRound(GGLfixed f) ALWAYS_INLINE ;
-inline GGLfixed gglFixedToIntFloor(GGLfixed f) ALWAYS_INLINE ;
-inline GGLfixed gglFixedToIntCeil(GGLfixed f) ALWAYS_INLINE ;
-inline GGLfixed gglFracx(GGLfixed v) ALWAYS_INLINE ;
-inline GGLfixed gglFloorx(GGLfixed v) ALWAYS_INLINE ;
-inline GGLfixed gglCeilx(GGLfixed v) ALWAYS_INLINE ;
-inline GGLfixed gglCenterx(GGLfixed v) ALWAYS_INLINE ;
-inline GGLfixed gglRoundx(GGLfixed v) ALWAYS_INLINE ;
-
-GGLfixed gglIntToFixed(GGLfixed i) {
- return i<<FIXED_BITS;
-}
-GGLfixed gglFixedToIntRound(GGLfixed f) {
- return (f + FIXED_HALF)>>FIXED_BITS;
-}
-GGLfixed gglFixedToIntFloor(GGLfixed f) {
- return f>>FIXED_BITS;
-}
-GGLfixed gglFixedToIntCeil(GGLfixed f) {
- return (f + ((1<<FIXED_BITS) - 1))>>FIXED_BITS;
-}
-
-GGLfixed gglFracx(GGLfixed v) {
- return v & ((1<<FIXED_BITS)-1);
-}
-GGLfixed gglFloorx(GGLfixed v) {
- return gglFixedToIntFloor(v)<<FIXED_BITS;
-}
-GGLfixed gglCeilx(GGLfixed v) {
- return gglFixedToIntCeil(v)<<FIXED_BITS;
-}
-GGLfixed gglCenterx(GGLfixed v) {
- return gglFloorx(v + FIXED_HALF) | FIXED_HALF;
-}
-GGLfixed gglRoundx(GGLfixed v) {
- return gglFixedToIntRound(v)<<FIXED_BITS;
-}
-
-// conversion from (unsigned) int, short, byte to fixed...
-#define GGL_B_TO_X(_x) GGLfixed( ((int32_t(_x)+1)>>1)<<10 )
-#define GGL_S_TO_X(_x) GGLfixed( ((int32_t(_x)+1)>>1)<<2 )
-#define GGL_I_TO_X(_x) GGLfixed( ((int32_t(_x)>>1)+1)>>14 )
-#define GGL_UB_TO_X(_x) GGLfixed( uint32_t(_x) + \
- (uint32_t(_x)<<8) + \
- (uint32_t(_x)>>7) )
-#define GGL_US_TO_X(_x) GGLfixed( (_x) + ((_x)>>15) )
-#define GGL_UI_TO_X(_x) GGLfixed( (((_x)>>1)+1)>>15 )
-
-// ----------------------------------------------------------------------------
-
-GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST;
-GGLfixed gglSqrtx(GGLfixed a) CONST;
-GGLfixed gglSqrtRecipx(GGLfixed x) CONST;
-int32_t gglMulDivi(int32_t a, int32_t b, int32_t c);
-
-int32_t gglRecipQNormalized(int32_t x, int* exponent);
-int32_t gglRecipQ(GGLfixed x, int q) CONST;
-
-inline GGLfixed gglRecip(GGLfixed x) CONST;
-inline GGLfixed gglRecip(GGLfixed x) {
- return gglRecipQ(x, 16);
-}
-
-inline GGLfixed gglRecip28(GGLfixed x) CONST;
-int32_t gglRecip28(GGLfixed x) {
- return gglRecipQ(x, 28);
-}
-
-// ----------------------------------------------------------------------------
-
-#if defined(__arm__) && !defined(__thumb__)
-
-// inline ARM implementations
-inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST;
-__attribute__((always_inline)) inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) {
- GGLfixed result, t;
- if (__builtin_constant_p(shift)) {
- asm("smull %[lo], %[hi], %[x], %[y] \n"
- "movs %[lo], %[lo], lsr %[rshift] \n"
- "adc %[lo], %[lo], %[hi], lsl %[lshift] \n"
- : [lo]"=r"(result), [hi]"=r"(t), [x]"=r"(x)
- : "%[x]"(x), [y]"r"(y), [lshift] "I"(32-shift), [rshift] "I"(shift)
- : "cc"
- );
- } else {
- asm("smull %[lo], %[hi], %[x], %[y] \n"
- "movs %[lo], %[lo], lsr %[rshift] \n"
- "adc %[lo], %[lo], %[hi], lsl %[lshift] \n"
- : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
- : "%[x]"(x), [y]"r"(y), [lshift] "r"(32-shift), [rshift] "r"(shift)
- : "cc"
- );
- }
- return result;
-}
-
-inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
-__attribute__((always_inline)) inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a,
- int shift) {
- GGLfixed result, t;
- if (__builtin_constant_p(shift)) {
- asm("smull %[lo], %[hi], %[x], %[y] \n"
- "add %[lo], %[a], %[lo], lsr %[rshift] \n"
- "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
- : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
- : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
- );
- } else {
- asm("smull %[lo], %[hi], %[x], %[y] \n"
- "add %[lo], %[a], %[lo], lsr %[rshift] \n"
- "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
- : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
- : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift)
- );
- }
- return result;
-}
-
-inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) {
- GGLfixed result, t;
- if (__builtin_constant_p(shift)) {
- asm("smull %[lo], %[hi], %[x], %[y] \n"
- "rsb %[lo], %[a], %[lo], lsr %[rshift] \n"
- "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
- : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
- : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
- );
- } else {
- asm("smull %[lo], %[hi], %[x], %[y] \n"
- "rsb %[lo], %[a], %[lo], lsr %[rshift] \n"
- "add %[lo], %[lo], %[hi], lsl %[lshift] \n"
- : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
- : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift)
- );
- }
- return result;
-}
-
-inline int64_t gglMulii(int32_t x, int32_t y) CONST;
-inline int64_t gglMulii(int32_t x, int32_t y)
-{
- // 64-bits result: r0=low, r1=high
- union {
- struct {
- int32_t lo;
- int32_t hi;
- } s;
- int64_t res;
- };
- asm("smull %0, %1, %2, %3 \n"
- : "=r"(s.lo), "=&r"(s.hi)
- : "%r"(x), "r"(y)
- :
- );
- return res;
-}
-#elif defined(__mips__) && __mips_isa_rev < 6
-
-/*inline MIPS implementations*/
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
- GGLfixed result,tmp,tmp1,tmp2;
-
- if (__builtin_constant_p(shift)) {
- if (shift == 0) {
- asm ("mult %[a], %[b] \t\n"
- "mflo %[res] \t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp)
- : [a]"r"(a),[b]"r"(b)
- : "%hi","%lo"
- );
- } else if (shift == 32)
- {
- asm ("mult %[a], %[b] \t\n"
- "li %[tmp],1\t\n"
- "sll %[tmp],%[tmp],0x1f\t\n"
- "mflo %[res] \t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp]\t\n" /*obit*/
- "sra %[tmp],%[tmp],0x1f \t\n"
- "mfhi %[res] \t\n"
- "addu %[res],%[res],%[tmp]\t\n"
- "addu %[res],%[res],%[tmp1]\t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1)
- : [a]"r"(a),[b]"r"(b),[shift]"I"(shift)
- : "%hi","%lo"
- );
- } else if ((shift >0) && (shift < 32))
- {
- asm ("mult %[a], %[b] \t\n"
- "li %[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[shiftm1] \t\n"
- "mflo %[res] \t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/
- "addu %[res],%[res],%[tmp] \t\n"
- "mfhi %[tmp] \t\n"
- "addu %[tmp],%[tmp],%[tmp1] \t\n"
- "sll %[tmp],%[tmp],%[lshift] \t\n"
- "srl %[res],%[res],%[rshift] \t\n"
- "or %[res],%[res],%[tmp] \t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[lshift]"I"(32-shift),[rshift]"I"(shift),[shiftm1]"I"(shift-1)
- : "%hi","%lo"
- );
- } else {
- asm ("mult %[a], %[b] \t\n"
- "li %[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[shiftm1] \t\n"
- "mflo %[res] \t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/
- "sra %[tmp2],%[tmp],0x1f \t\n"
- "addu %[res],%[res],%[tmp] \t\n"
- "mfhi %[tmp] \t\n"
- "addu %[tmp],%[tmp],%[tmp2] \t\n"
- "addu %[tmp],%[tmp],%[tmp1] \t\n" /*tmp=hi*/
- "srl %[tmp2],%[res],%[rshift] \t\n"
- "srav %[res], %[tmp],%[rshift]\t\n"
- "sll %[tmp],%[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[norbits] \t\n"
- "or %[tmp],%[tmp],%[tmp2] \t\n"
- "movz %[res],%[tmp],%[bit5] \t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[norbits]"I"(~(shift)),[rshift]"I"(shift),[shiftm1] "I"(shift-1),[bit5]"I"(shift & 0x20)
- : "%hi","%lo"
- );
- }
- } else {
- asm ("mult %[a], %[b] \t\n"
- "li %[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[shiftm1] \t\n"
- "mflo %[res] \t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/
- "sra %[tmp2],%[tmp],0x1f \t\n"
- "addu %[res],%[res],%[tmp] \t\n"
- "mfhi %[tmp] \t\n"
- "addu %[tmp],%[tmp],%[tmp2] \t\n"
- "addu %[tmp],%[tmp],%[tmp1] \t\n" /*tmp=hi*/
- "srl %[tmp2],%[res],%[rshift] \t\n"
- "srav %[res], %[tmp],%[rshift]\t\n"
- "sll %[tmp],%[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[norbits] \t\n"
- "or %[tmp],%[tmp],%[tmp2] \t\n"
- "movz %[res],%[tmp],%[bit5] \t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[norbits]"r"(~(shift)),[rshift] "r"(shift),[shiftm1]"r"(shift-1),[bit5] "r"(shift & 0x20)
- : "%hi","%lo"
- );
- }
-
- return result;
-}
-
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
- GGLfixed result,t,tmp1,tmp2;
-
- if (__builtin_constant_p(shift)) {
- if (shift == 0) {
- asm ("mult %[a], %[b] \t\n"
- "mflo %[lo] \t\n"
- "addu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- : "%hi","%lo"
- );
- } else if (shift == 32) {
- asm ("mult %[a], %[b] \t\n"
- "mfhi %[lo] \t\n"
- "addu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- : "%hi","%lo"
- );
- } else if ((shift>0) && (shift<32)) {
- asm ("mult %[a], %[b] \t\n"
- "mflo %[res] \t\n"
- "mfhi %[t] \t\n"
- "srl %[res],%[res],%[rshift] \t\n"
- "sll %[t],%[t],%[lshift] \t\n"
- "or %[res],%[res],%[t] \t\n"
- "addu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
- : "%hi","%lo"
- );
- } else {
- asm ("mult %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "mflo %[res] \t\n"
- "mfhi %[t] \t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "movz %[res],%[tmp1],%[tmp2]\t\n"
- "addu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
- : "%hi","%lo"
- );
- }
- } else {
- asm ("mult %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "mflo %[res] \t\n"
- "mfhi %[t] \t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "movz %[res],%[tmp1],%[tmp2]\t\n"
- "addu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift)
- : "%hi","%lo"
- );
- }
- return result;
-}
-
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
- GGLfixed result,t,tmp1,tmp2;
-
- if (__builtin_constant_p(shift)) {
- if (shift == 0) {
- asm ("mult %[a], %[b] \t\n"
- "mflo %[lo] \t\n"
- "subu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- : "%hi","%lo"
- );
- } else if (shift == 32) {
- asm ("mult %[a], %[b] \t\n"
- "mfhi %[lo] \t\n"
- "subu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- : "%hi","%lo"
- );
- } else if ((shift>0) && (shift<32)) {
- asm ("mult %[a], %[b] \t\n"
- "mflo %[res] \t\n"
- "mfhi %[t] \t\n"
- "srl %[res],%[res],%[rshift] \t\n"
- "sll %[t],%[t],%[lshift] \t\n"
- "or %[res],%[res],%[t] \t\n"
- "subu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
- : "%hi","%lo"
- );
- } else {
- asm ("mult %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "mflo %[res] \t\n"
- "mfhi %[t] \t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "movz %[res],%[tmp1],%[tmp2]\t\n"
- "subu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
- : "%hi","%lo"
- );
- }
- } else {
- asm ("mult %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "mflo %[res] \t\n"
- "mfhi %[t] \t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "movz %[res],%[tmp1],%[tmp2]\t\n"
- "subu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift)
- : "%hi","%lo"
- );
- }
- return result;
-}
-
-inline int64_t gglMulii(int32_t x, int32_t y) CONST;
-inline int64_t gglMulii(int32_t x, int32_t y) {
- union {
- struct {
-#if defined(__MIPSEL__)
- int32_t lo;
- int32_t hi;
-#elif defined(__MIPSEB__)
- int32_t hi;
- int32_t lo;
-#endif
- } s;
- int64_t res;
- }u;
- asm("mult %2, %3 \t\n"
- "mfhi %1 \t\n"
- "mflo %0 \t\n"
- : "=r"(u.s.lo), "=&r"(u.s.hi)
- : "%r"(x), "r"(y)
- : "%hi","%lo"
- );
- return u.res;
-}
-
-#elif defined(__aarch64__)
-
-// inline AArch64 implementations
-
-inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST;
-inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift)
-{
- GGLfixed result;
- GGLfixed round;
-
- asm("mov %x[round], #1 \n"
- "lsl %x[round], %x[round], %x[shift] \n"
- "lsr %x[round], %x[round], #1 \n"
- "smaddl %x[result], %w[x], %w[y],%x[round] \n"
- "lsr %x[result], %x[result], %x[shift] \n"
- : [round]"=&r"(round), [result]"=&r"(result) \
- : [x]"r"(x), [y]"r"(y), [shift] "r"(shift) \
- :
- );
- return result;
-}
-inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
-inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift)
-{
- GGLfixed result;
- asm("smull %x[result], %w[x], %w[y] \n"
- "lsr %x[result], %x[result], %x[shift] \n"
- "add %w[result], %w[result], %w[a] \n"
- : [result]"=&r"(result) \
- : [x]"r"(x), [y]"r"(y), [a]"r"(a), [shift] "r"(shift) \
- :
- );
- return result;
-}
-
-inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift)
-{
-
- GGLfixed result;
-
- asm("smull %x[result], %w[x], %w[y] \n"
- "lsr %x[result], %x[result], %x[shift] \n"
- "sub %w[result], %w[result], %w[a] \n"
- : [result]"=&r"(result) \
- : [x]"r"(x), [y]"r"(y), [a]"r"(a), [shift] "r"(shift) \
- :
- );
- return result;
-}
-inline int64_t gglMulii(int32_t x, int32_t y) CONST;
-inline int64_t gglMulii(int32_t x, int32_t y)
-{
- int64_t res;
- asm("smull %x0, %w1, %w2 \n"
- : "=r"(res)
- : "%r"(x), "r"(y)
- :
- );
- return res;
-}
-
-#elif defined(__mips__) && __mips_isa_rev == 6
-
-/*inline MIPS implementations*/
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
- GGLfixed result,tmp,tmp1,tmp2;
-
- if (__builtin_constant_p(shift)) {
- if (shift == 0) {
- asm ("mul %[res], %[a], %[b] \t\n"
- : [res]"=&r"(result)
- : [a]"r"(a),[b]"r"(b)
- );
- } else if (shift == 32)
- {
- asm ("mul %[res], %[a], %[b] \t\n"
- "li %[tmp],1\t\n"
- "sll %[tmp],%[tmp],0x1f\t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "muh %[res], %[a], %[b] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp]\t\n" /*obit*/
- "sra %[tmp],%[tmp],0x1f \t\n"
- "addu %[res],%[res],%[tmp]\t\n"
- "addu %[res],%[res],%[tmp1]\t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1)
- : [a]"r"(a),[b]"r"(b),[shift]"I"(shift)
- );
- } else if ((shift >0) && (shift < 32))
- {
- asm ("mul %[res], %[a], %[b] \t\n"
- "li %[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[shiftm1] \t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/
- "addu %[res],%[res],%[tmp] \t\n"
- "muh %[tmp], %[a], %[b] \t\n"
- "addu %[tmp],%[tmp],%[tmp1] \t\n"
- "sll %[tmp],%[tmp],%[lshift] \t\n"
- "srl %[res],%[res],%[rshift] \t\n"
- "or %[res],%[res],%[tmp] \t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[lshift]"I"(32-shift),[rshift]"I"(shift),[shiftm1]"I"(shift-1)
- );
- } else {
- asm ("mul %[res], %[a], %[b] \t\n"
- "li %[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[shiftm1] \t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/
- "sra %[tmp2],%[tmp],0x1f \t\n"
- "addu %[res],%[res],%[tmp] \t\n"
- "muh %[tmp], %[a], %[b] \t\n"
- "addu %[tmp],%[tmp],%[tmp2] \t\n"
- "addu %[tmp],%[tmp],%[tmp1] \t\n" /*tmp=hi*/
- "srl %[tmp2],%[res],%[rshift] \t\n"
- "srav %[res], %[tmp],%[rshift]\t\n"
- "sll %[tmp],%[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[norbits] \t\n"
- "or %[tmp],%[tmp],%[tmp2] \t\n"
- "seleqz %[tmp],%[tmp],%[bit5] \t\n"
- "selnez %[res],%[res],%[bit5] \t\n"
- "or %[res],%[res],%[tmp] \t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[norbits]"I"(~(shift)),[rshift]"I"(shift),[shiftm1] "I"(shift-1),[bit5]"I"(shift & 0x20)
- );
- }
- } else {
- asm ("mul %[res], %[a], %[b] \t\n"
- "li %[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[shiftm1] \t\n"
- "addu %[tmp1],%[tmp],%[res] \t\n"
- "sltu %[tmp1],%[tmp1],%[tmp] \t\n" /*obit?*/
- "sra %[tmp2],%[tmp],0x1f \t\n"
- "addu %[res],%[res],%[tmp] \t\n"
- "muh %[tmp], %[a], %[b] \t\n"
- "addu %[tmp],%[tmp],%[tmp2] \t\n"
- "addu %[tmp],%[tmp],%[tmp1] \t\n" /*tmp=hi*/
- "srl %[tmp2],%[res],%[rshift] \t\n"
- "srav %[res], %[tmp],%[rshift]\t\n"
- "sll %[tmp],%[tmp],1 \t\n"
- "sll %[tmp],%[tmp],%[norbits] \t\n"
- "or %[tmp],%[tmp],%[tmp2] \t\n"
- "seleqz %[tmp],%[tmp],%[bit5] \t\n"
- "selnez %[res],%[res],%[bit5] \t\n"
- "or %[res],%[res],%[tmp] \t\n"
- : [res]"=&r"(result),[tmp]"=&r"(tmp),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[norbits]"r"(~(shift)),[rshift] "r"(shift),[shiftm1]"r"(shift-1),[bit5] "r"(shift & 0x20)
- );
- }
- return result;
-}
-
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
- GGLfixed result,t,tmp1,tmp2;
-
- if (__builtin_constant_p(shift)) {
- if (shift == 0) {
- asm ("mul %[lo], %[a], %[b] \t\n"
- "addu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- );
- } else if (shift == 32) {
- asm ("muh %[lo], %[a], %[b] \t\n"
- "addu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- );
- } else if ((shift>0) && (shift<32)) {
- asm ("mul %[res], %[a], %[b] \t\n"
- "muh %[t], %[a], %[b] \t\n"
- "srl %[res],%[res],%[rshift] \t\n"
- "sll %[t],%[t],%[lshift] \t\n"
- "or %[res],%[res],%[t] \t\n"
- "addu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
- );
- } else {
- asm ("mul %[res], %[a], %[b] \t\n"
- "muh %[t], %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
- "selnez %[res],%[res],%[tmp2]\t\n"
- "or %[res],%[res],%[tmp1]\t\n"
- "addu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
- );
- }
- } else {
- asm ("mul %[res], %[a], %[b] \t\n"
- "muh %[t], %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
- "selnez %[res],%[res],%[tmp2]\t\n"
- "or %[res],%[res],%[tmp1]\t\n"
- "addu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift)
- );
- }
- return result;
-}
-
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
- GGLfixed result,t,tmp1,tmp2;
-
- if (__builtin_constant_p(shift)) {
- if (shift == 0) {
- asm ("mul %[lo], %[a], %[b] \t\n"
- "subu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- );
- } else if (shift == 32) {
- asm ("muh %[lo], %[a], %[b] \t\n"
- "subu %[lo],%[lo],%[c] \t\n"
- : [lo]"=&r"(result)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c)
- );
- } else if ((shift>0) && (shift<32)) {
- asm ("mul %[res], %[a], %[b] \t\n"
- "muh %[t], %[a], %[b] \t\n"
- "srl %[res],%[res],%[rshift] \t\n"
- "sll %[t],%[t],%[lshift] \t\n"
- "or %[res],%[res],%[t] \t\n"
- "subu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[lshift]"I"(32-shift),[rshift]"I"(shift)
- );
- } else {
- asm ("mul %[res], %[a], %[b] \t\n"
- "muh %[t], %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
- "selnez %[res],%[res],%[tmp2]\t\n"
- "or %[res],%[res],%[tmp1]\t\n"
- "subu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"I"(shift)
- );
- }
- } else {
- asm ("mul %[res], %[a], %[b] \t\n"
- "muh %[t], %[a], %[b] \t\n"
- "nor %[tmp1],$zero,%[shift]\t\n"
- "srl %[res],%[res],%[shift] \t\n"
- "sll %[tmp2],%[t],1 \t\n"
- "sllv %[tmp2],%[tmp2],%[tmp1] \t\n"
- "or %[tmp1],%[tmp2],%[res] \t\n"
- "srav %[res],%[t],%[shift] \t\n"
- "andi %[tmp2],%[shift],0x20\t\n"
- "seleqz %[tmp1],%[tmp1],%[tmp2]\t\n"
- "selnez %[res],%[res],%[tmp2]\t\n"
- "or %[res],%[res],%[tmp1]\t\n"
- "subu %[res],%[res],%[c] \t\n"
- : [res]"=&r"(result),[t]"=&r"(t),[tmp1]"=&r"(tmp1),[tmp2]"=&r"(tmp2)
- : [a]"r"(a),[b]"r"(b),[c]"r"(c),[shift]"r"(shift)
- );
- }
- return result;
-}
-
-inline int64_t gglMulii(int32_t x, int32_t y) CONST;
-inline int64_t gglMulii(int32_t x, int32_t y) {
- union {
- struct {
-#if defined(__MIPSEL__)
- int32_t lo;
- int32_t hi;
-#elif defined(__MIPSEB__)
- int32_t hi;
- int32_t lo;
-#endif
- } s;
- int64_t res;
- }u;
- asm("mul %0, %2, %3 \t\n"
- "muh %1, %2, %3 \t\n"
- : "=r"(u.s.lo), "=&r"(u.s.hi)
- : "%r"(x), "r"(y)
- );
- return u.res;
-}
-
-#else // ----------------------------------------------------------------------
-
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
- return GGLfixed((int64_t(a)*b + (1<<(shift-1)))>>shift);
-}
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
- return GGLfixed((int64_t(a)*b)>>shift) + c;
-}
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
- return GGLfixed((int64_t(a)*b)>>shift) - c;
-}
-inline int64_t gglMulii(int32_t a, int32_t b) CONST;
-inline int64_t gglMulii(int32_t a, int32_t b) {
- return int64_t(a)*b;
-}
-
-#endif
-
-// ------------------------------------------------------------------------
-
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) CONST;
-inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) {
- return gglMulx(a, b, 16);
-}
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
-inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) {
- return gglMulAddx(a, b, c, 16);
-}
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
-inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) {
- return gglMulSubx(a, b, c, 16);
-}
-
-// ------------------------------------------------------------------------
-
-inline int32_t gglClz(int32_t x) CONST;
-inline int32_t gglClz(int32_t x)
-{
-#if (defined(__arm__) && !defined(__thumb__)) || defined(__mips__) || defined(__aarch64__)
- return __builtin_clz(x);
-#else
- if (!x) return 32;
- int32_t exp = 31;
- if (x & 0xFFFF0000) { exp -=16; x >>= 16; }
- if (x & 0x0000ff00) { exp -= 8; x >>= 8; }
- if (x & 0x000000f0) { exp -= 4; x >>= 4; }
- if (x & 0x0000000c) { exp -= 2; x >>= 2; }
- if (x & 0x00000002) { exp -= 1; }
- return exp;
-#endif
-}
-
-// ------------------------------------------------------------------------
-
-int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i) CONST;
-
-inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) CONST;
-inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) {
- return gglDivQ(n, d, 16);
-}
-
-inline int32_t gglDivx(GGLfixed n, GGLfixed d) CONST;
-inline int32_t gglDivx(GGLfixed n, GGLfixed d) {
- return gglDivQ(n, d, 16);
-}
-
-// ------------------------------------------------------------------------
-
-inline GGLfixed gglRecipFast(GGLfixed x) CONST;
-inline GGLfixed gglRecipFast(GGLfixed x)
-{
- // This is a really bad approximation of 1/x, but it's also
- // very fast. x must be strictly positive.
- // if x between [0.5, 1[ , then 1/x = 3-2*x
- // (we use 2.30 fixed-point)
- const int32_t lz = gglClz(x);
- return (0xC0000000 - (x << (lz - 1))) >> (30-lz);
-}
-
-// ------------------------------------------------------------------------
-
-inline GGLfixed gglClampx(GGLfixed c) CONST;
-inline GGLfixed gglClampx(GGLfixed c)
-{
-#if defined(__thumb__)
- // clamp without branches
- c &= ~(c>>31); c = FIXED_ONE - c;
- c &= ~(c>>31); c = FIXED_ONE - c;
-#else
-#if defined(__arm__)
- // I don't know why gcc thinks its smarter than me! The code below
- // clamps to zero in one instruction, but gcc won't generate it and
- // replace it by a cmp + movlt (it's quite amazing actually).
- asm("bic %0, %1, %1, asr #31\n" : "=r"(c) : "r"(c));
-#elif defined(__aarch64__)
- asm("bic %w0, %w1, %w1, asr #31\n" : "=r"(c) : "r"(c));
-#else
- c &= ~(c>>31);
-#endif
- if (c>FIXED_ONE)
- c = FIXED_ONE;
-#endif
- return c;
-}
-
-// ------------------------------------------------------------------------
-
-#endif // ANDROID_GGL_FIXED_H
diff --git a/libpixelflinger/picker.cpp b/libpixelflinger/picker.cpp
deleted file mode 100644
index aa55229..0000000
--- a/libpixelflinger/picker.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/* libs/pixelflinger/picker.cpp
-**
-** Copyright 2006, 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 <stdio.h>
-
-#include "buffer.h"
-#include "scanline.h"
-#include "picker.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_picker(context_t* /*c*/)
-{
-}
-
-void ggl_pick(context_t* c)
-{
- if (ggl_likely(!c->dirty))
- return;
-
- // compute needs, see if they changed...
- const uint32_t enables = c->state.enables;
- needs_t new_needs(c->state.needs);
-
- if (c->dirty & GGL_CB_STATE) {
- new_needs.n &= ~GGL_NEEDS_CB_FORMAT_MASK;
- new_needs.n |= GGL_BUILD_NEEDS(c->state.buffers.color.format, CB_FORMAT);
- if (enables & GGL_ENABLE_BLENDING)
- c->dirty |= GGL_PIXEL_PIPELINE_STATE;
- }
-
- if (c->dirty & GGL_PIXEL_PIPELINE_STATE) {
- uint32_t n = GGL_BUILD_NEEDS(c->state.buffers.color.format, CB_FORMAT);
- uint32_t p = 0;
- if (enables & GGL_ENABLE_BLENDING) {
- uint32_t src = c->state.blend.src;
- uint32_t dst = c->state.blend.dst;
- uint32_t src_alpha = c->state.blend.src_alpha;
- uint32_t dst_alpha = c->state.blend.dst_alpha;
- const GGLFormat& cbf = c->formats[ c->state.buffers.color.format ];
- if (!cbf.c[GGLFormat::ALPHA].h) {
- if ((src == GGL_ONE_MINUS_DST_ALPHA) ||
- (src == GGL_DST_ALPHA)) {
- src = GGL_ONE;
- }
- if ((src_alpha == GGL_ONE_MINUS_DST_ALPHA) ||
- (src_alpha == GGL_DST_ALPHA)) {
- src_alpha = GGL_ONE;
- }
- if ((dst == GGL_ONE_MINUS_DST_ALPHA) ||
- (dst == GGL_DST_ALPHA)) {
- dst = GGL_ONE;
- }
- if ((dst_alpha == GGL_ONE_MINUS_DST_ALPHA) ||
- (dst_alpha == GGL_DST_ALPHA)) {
- dst_alpha = GGL_ONE;
- }
- }
-
- src = ggl_blendfactor_to_needs(src);
- dst = ggl_blendfactor_to_needs(dst);
- src_alpha = ggl_blendfactor_to_needs(src_alpha);
- dst_alpha = ggl_blendfactor_to_needs(dst_alpha);
-
- n |= GGL_BUILD_NEEDS( src, BLEND_SRC );
- n |= GGL_BUILD_NEEDS( dst, BLEND_DST );
- if (c->state.blend.alpha_separate) {
- n |= GGL_BUILD_NEEDS( src_alpha, BLEND_SRCA );
- n |= GGL_BUILD_NEEDS( dst_alpha, BLEND_DSTA );
- } else {
- n |= GGL_BUILD_NEEDS( src, BLEND_SRCA );
- n |= GGL_BUILD_NEEDS( dst, BLEND_DSTA );
- }
- } else {
- n |= GGL_BUILD_NEEDS( GGL_ONE, BLEND_SRC );
- n |= GGL_BUILD_NEEDS( GGL_ZERO, BLEND_DST );
- n |= GGL_BUILD_NEEDS( GGL_ONE, BLEND_SRCA );
- n |= GGL_BUILD_NEEDS( GGL_ZERO, BLEND_DSTA );
- }
-
-
- n |= GGL_BUILD_NEEDS(c->state.mask.color^0xF, MASK_ARGB);
- n |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_SMOOTH) ?1:0, SHADE);
- if (enables & GGL_ENABLE_TMUS) {
- n |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_W) ?1:0, W);
- }
- p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_DITHER) ?1:0, P_DITHER);
- p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_AA) ?1:0, P_AA);
- p |= GGL_BUILD_NEEDS((enables & GGL_ENABLE_FOG) ?1:0, P_FOG);
-
- if (enables & GGL_ENABLE_LOGIC_OP) {
- n |= GGL_BUILD_NEEDS(c->state.logic_op.opcode, LOGIC_OP);
- } else {
- n |= GGL_BUILD_NEEDS(GGL_COPY, LOGIC_OP);
- }
-
- if (enables & GGL_ENABLE_ALPHA_TEST) {
- p |= GGL_BUILD_NEEDS(c->state.alpha_test.func, P_ALPHA_TEST);
- } else {
- p |= GGL_BUILD_NEEDS(GGL_ALWAYS, P_ALPHA_TEST);
- }
-
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- p |= GGL_BUILD_NEEDS(c->state.depth_test.func, P_DEPTH_TEST);
- p |= GGL_BUILD_NEEDS(c->state.mask.depth&1, P_MASK_Z);
- } else {
- p |= GGL_BUILD_NEEDS(GGL_ALWAYS, P_DEPTH_TEST);
- // writing to the z-buffer is always disabled if depth-test
- // is disabled.
- }
- new_needs.n = n;
- new_needs.p = p;
- }
-
- if (c->dirty & GGL_TMU_STATE) {
- int idx = 0;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- const texture_t& tx = c->state.texture[i];
- if (tx.enable) {
- uint32_t t = 0;
- t |= GGL_BUILD_NEEDS(tx.surface.format, T_FORMAT);
- t |= GGL_BUILD_NEEDS(ggl_env_to_needs(tx.env), T_ENV);
- t |= GGL_BUILD_NEEDS(0, T_POT); // XXX: not used yet
- if (tx.s_coord==GGL_ONE_TO_ONE && tx.t_coord==GGL_ONE_TO_ONE) {
- // we encode 1-to-1 into the wrap mode
- t |= GGL_BUILD_NEEDS(GGL_NEEDS_WRAP_11, T_S_WRAP);
- t |= GGL_BUILD_NEEDS(GGL_NEEDS_WRAP_11, T_T_WRAP);
- } else {
- t |= GGL_BUILD_NEEDS(ggl_wrap_to_needs(tx.s_wrap), T_S_WRAP);
- t |= GGL_BUILD_NEEDS(ggl_wrap_to_needs(tx.t_wrap), T_T_WRAP);
- }
- if (tx.mag_filter == GGL_LINEAR) {
- t |= GGL_BUILD_NEEDS(1, T_LINEAR);
- }
- if (tx.min_filter == GGL_LINEAR) {
- t |= GGL_BUILD_NEEDS(1, T_LINEAR);
- }
- new_needs.t[idx++] = t;
- } else {
- new_needs.t[i] = 0;
- }
- }
- }
-
- if (new_needs != c->state.needs) {
- c->state.needs = new_needs;
- ggl_pick_texture(c);
- ggl_pick_cb(c);
- ggl_pick_scanline(c);
- }
- c->dirty = 0;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libpixelflinger/picker.h b/libpixelflinger/picker.h
deleted file mode 100644
index 9cdbc3c..0000000
--- a/libpixelflinger/picker.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* libs/pixelflinger/picker.h
-**
-** Copyright 2006, 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 ANDROID_PICKER_H
-#define ANDROID_PICKER_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_picker(context_t* c);
-void ggl_pick(context_t* c);
-
-}; // namespace android
-
-#endif
diff --git a/libpixelflinger/pixelflinger.cpp b/libpixelflinger/pixelflinger.cpp
deleted file mode 100644
index fd449b2..0000000
--- a/libpixelflinger/pixelflinger.cpp
+++ /dev/null
@@ -1,836 +0,0 @@
-/* libs/pixelflinger/pixelflinger.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include <sys/time.h>
-
-#include <pixelflinger/pixelflinger.h>
-#include <private/pixelflinger/ggl_context.h>
-
-#include "buffer.h"
-#include "clear.h"
-#include "picker.h"
-#include "raster.h"
-#include "scanline.h"
-#include "trap.h"
-
-#include "codeflinger/GGLAssembler.h"
-#include "codeflinger/CodeCache.h"
-
-#include <stdio.h>
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// 8x8 Bayer dither matrix
-static const uint8_t gDitherMatrix[GGL_DITHER_SIZE] = {
- 0, 32, 8, 40, 2, 34, 10, 42,
- 48, 16, 56, 24, 50, 18, 58, 26,
- 12, 44, 4, 36, 14, 46, 6, 38,
- 60, 28, 52, 20, 62, 30, 54, 22,
- 3, 35, 11, 43, 1, 33, 9, 41,
- 51, 19, 59, 27, 49, 17, 57, 25,
- 15, 47, 7, 39, 13, 45, 5, 37,
- 63, 31, 55, 23, 61, 29, 53, 21
-};
-
-static void ggl_init_procs(context_t* c);
-static void ggl_set_scissor(context_t* c);
-
-static void ggl_enable_blending(context_t* c, int enable);
-static void ggl_enable_scissor_test(context_t* c, int enable);
-static void ggl_enable_alpha_test(context_t* c, int enable);
-static void ggl_enable_logic_op(context_t* c, int enable);
-static void ggl_enable_dither(context_t* c, int enable);
-static void ggl_enable_stencil_test(context_t* c, int enable);
-static void ggl_enable_depth_test(context_t* c, int enable);
-static void ggl_enable_aa(context_t* c, int enable);
-static void ggl_enable_point_aa_nice(context_t* c, int enable);
-static void ggl_enable_texture2d(context_t* c, int enable);
-static void ggl_enable_w_lerp(context_t* c, int enable);
-static void ggl_enable_fog(context_t* c, int enable);
-
-static inline int min(int a, int b) CONST;
-static inline int min(int a, int b) {
- return a < b ? a : b;
-}
-
-static inline int max(int a, int b) CONST;
-static inline int max(int a, int b) {
- return a < b ? b : a;
-}
-
-// ----------------------------------------------------------------------------
-
-void ggl_error(context_t* c, GGLenum error)
-{
- if (c->error == GGL_NO_ERROR)
- c->error = error;
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_bindTexture(void* con, const GGLSurface* surface)
-{
- GGL_CONTEXT(c, con);
- if (surface->format != c->activeTMU->surface.format)
- ggl_state_changed(c, GGL_TMU_STATE);
- ggl_set_surface(c, &(c->activeTMU->surface), surface);
-}
-
-
-static void ggl_bindTextureLod(void* con, GGLuint tmu,const GGLSurface* surface)
-{
- GGL_CONTEXT(c, con);
- // All LODs must have the same format
- ggl_set_surface(c, &c->state.texture[tmu].surface, surface);
-}
-
-static void ggl_colorBuffer(void* con, const GGLSurface* surface)
-{
- GGL_CONTEXT(c, con);
- if (surface->format != c->state.buffers.color.format)
- ggl_state_changed(c, GGL_CB_STATE);
-
- if (surface->width > c->state.buffers.coverageBufferSize) {
- // allocate the coverage factor buffer
- free(c->state.buffers.coverage);
- c->state.buffers.coverage = (int16_t*)malloc(surface->width * 2);
- c->state.buffers.coverageBufferSize =
- c->state.buffers.coverage ? surface->width : 0;
- }
- ggl_set_surface(c, &(c->state.buffers.color), surface);
- if (c->state.buffers.read.format == 0) {
- ggl_set_surface(c, &(c->state.buffers.read), surface);
- }
- ggl_set_scissor(c);
-}
-
-static void ggl_readBuffer(void* con, const GGLSurface* surface)
-{
- GGL_CONTEXT(c, con);
- ggl_set_surface(c, &(c->state.buffers.read), surface);
-}
-
-static void ggl_depthBuffer(void* con, const GGLSurface* surface)
-{
- GGL_CONTEXT(c, con);
- if (surface->format == GGL_PIXEL_FORMAT_Z_16) {
- ggl_set_surface(c, &(c->state.buffers.depth), surface);
- } else {
- c->state.buffers.depth.format = GGL_PIXEL_FORMAT_NONE;
- ggl_enable_depth_test(c, 0);
- }
-}
-
-static void ggl_scissor(void* con, GGLint x, GGLint y,
- GGLsizei width, GGLsizei height)
-{
- GGL_CONTEXT(c, con);
- c->state.scissor.user_left = x;
- c->state.scissor.user_top = y;
- c->state.scissor.user_right = x + width;
- c->state.scissor.user_bottom = y + height;
- ggl_set_scissor(c);
-}
-
-// ----------------------------------------------------------------------------
-
-static void enable_disable(context_t* c, GGLenum name, int en)
-{
- switch (name) {
- case GGL_BLEND: ggl_enable_blending(c, en); break;
- case GGL_SCISSOR_TEST: ggl_enable_scissor_test(c, en); break;
- case GGL_ALPHA_TEST: ggl_enable_alpha_test(c, en); break;
- case GGL_COLOR_LOGIC_OP: ggl_enable_logic_op(c, en); break;
- case GGL_DITHER: ggl_enable_dither(c, en); break;
- case GGL_STENCIL_TEST: ggl_enable_stencil_test(c, en); break;
- case GGL_DEPTH_TEST: ggl_enable_depth_test(c, en); break;
- case GGL_AA: ggl_enable_aa(c, en); break;
- case GGL_TEXTURE_2D: ggl_enable_texture2d(c, en); break;
- case GGL_W_LERP: ggl_enable_w_lerp(c, en); break;
- case GGL_FOG: ggl_enable_fog(c, en); break;
- case GGL_POINT_SMOOTH_NICE: ggl_enable_point_aa_nice(c, en); break;
- }
-}
-
-static void ggl_enable(void* con, GGLenum name)
-{
- GGL_CONTEXT(c, con);
- enable_disable(c, name, 1);
-}
-
-static void ggl_disable(void* con, GGLenum name)
-{
- GGL_CONTEXT(c, con);
- enable_disable(c, name, 0);
-}
-
-static void ggl_enableDisable(void* con, GGLenum name, GGLboolean en)
-{
- GGL_CONTEXT(c, con);
- enable_disable(c, name, en ? 1 : 0);
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_shadeModel(void* con, GGLenum mode)
-{
- GGL_CONTEXT(c, con);
- switch (mode) {
- case GGL_FLAT:
- if (c->state.enables & GGL_ENABLE_SMOOTH) {
- c->state.enables &= ~GGL_ENABLE_SMOOTH;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
- break;
- case GGL_SMOOTH:
- if (!(c->state.enables & GGL_ENABLE_SMOOTH)) {
- c->state.enables |= GGL_ENABLE_SMOOTH;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
- break;
- default:
- ggl_error(c, GGL_INVALID_ENUM);
- }
-}
-
-static void ggl_color4xv(void* con, const GGLclampx* color)
-{
- GGL_CONTEXT(c, con);
- c->shade.r0 = gglFixedToIteratedColor(color[0]);
- c->shade.g0 = gglFixedToIteratedColor(color[1]);
- c->shade.b0 = gglFixedToIteratedColor(color[2]);
- c->shade.a0 = gglFixedToIteratedColor(color[3]);
-}
-
-static void ggl_colorGrad12xv(void* con, const GGLcolor* grad)
-{
- GGL_CONTEXT(c, con);
- // it is very important to round the iterated value here because
- // the rasterizer doesn't clamp them, therefore the iterated value
- //must absolutely be correct.
- // GGLColor is encoded as 8.16 value
- const int32_t round = 0x8000;
- c->shade.r0 = grad[ 0] + round;
- c->shade.drdx = grad[ 1];
- c->shade.drdy = grad[ 2];
- c->shade.g0 = grad[ 3] + round;
- c->shade.dgdx = grad[ 4];
- c->shade.dgdy = grad[ 5];
- c->shade.b0 = grad[ 6] + round;
- c->shade.dbdx = grad[ 7];
- c->shade.dbdy = grad[ 8];
- c->shade.a0 = grad[ 9] + round;
- c->shade.dadx = grad[10];
- c->shade.dady = grad[11];
-}
-
-static void ggl_zGrad3xv(void* con, const GGLfixed32* grad)
-{
- GGL_CONTEXT(c, con);
- // z iterators are encoded as 0.32 fixed point and the z-buffer
- // holds 16 bits, the rounding value is 0x8000.
- const uint32_t round = 0x8000;
- c->shade.z0 = grad[0] + round;
- c->shade.dzdx = grad[1];
- c->shade.dzdy = grad[2];
-}
-
-static void ggl_wGrad3xv(void* con, const GGLfixed* grad)
-{
- GGL_CONTEXT(c, con);
- c->shade.w0 = grad[0];
- c->shade.dwdx = grad[1];
- c->shade.dwdy = grad[2];
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_fogGrad3xv(void* con, const GGLfixed* grad)
-{
- GGL_CONTEXT(c, con);
- c->shade.f0 = grad[0];
- c->shade.dfdx = grad[1];
- c->shade.dfdy = grad[2];
-}
-
-static void ggl_fogColor3xv(void* con, const GGLclampx* color)
-{
- GGL_CONTEXT(c, con);
- const int32_t r = gglClampx(color[0]);
- const int32_t g = gglClampx(color[1]);
- const int32_t b = gglClampx(color[2]);
- c->state.fog.color[GGLFormat::ALPHA]= 0xFF; // unused
- c->state.fog.color[GGLFormat::RED] = (r - (r>>8))>>8;
- c->state.fog.color[GGLFormat::GREEN]= (g - (g>>8))>>8;
- c->state.fog.color[GGLFormat::BLUE] = (b - (b>>8))>>8;
-}
-
-static void ggl_enable_fog(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_FOG)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_FOG;
- else c->state.enables &= ~GGL_ENABLE_FOG;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_blendFunc(void* con, GGLenum src, GGLenum dst)
-{
- GGL_CONTEXT(c, con);
- c->state.blend.src = src;
- c->state.blend.src_alpha = src;
- c->state.blend.dst = dst;
- c->state.blend.dst_alpha = dst;
- c->state.blend.alpha_separate = 0;
- if (c->state.enables & GGL_ENABLE_BLENDING) {
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-static void ggl_blendFuncSeparate(void* con,
- GGLenum src, GGLenum dst,
- GGLenum srcAlpha, GGLenum dstAplha)
-{
- GGL_CONTEXT(c, con);
- c->state.blend.src = src;
- c->state.blend.src_alpha = srcAlpha;
- c->state.blend.dst = dst;
- c->state.blend.dst_alpha = dstAplha;
- c->state.blend.alpha_separate = 1;
- if (c->state.enables & GGL_ENABLE_BLENDING) {
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_texEnvi(void* con, GGLenum target,
- GGLenum pname,
- GGLint param)
-{
- GGL_CONTEXT(c, con);
- if (target != GGL_TEXTURE_ENV || pname != GGL_TEXTURE_ENV_MODE) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
- switch (param) {
- case GGL_REPLACE:
- case GGL_MODULATE:
- case GGL_DECAL:
- case GGL_BLEND:
- case GGL_ADD:
- if (c->activeTMU->env != param) {
- c->activeTMU->env = param;
- ggl_state_changed(c, GGL_TMU_STATE);
- }
- break;
- default:
- ggl_error(c, GGL_INVALID_ENUM);
- }
-}
-
-static void ggl_texEnvxv(void* con, GGLenum target,
- GGLenum pname, const GGLfixed* params)
-{
- GGL_CONTEXT(c, con);
- if (target != GGL_TEXTURE_ENV) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
- switch (pname) {
- case GGL_TEXTURE_ENV_MODE:
- ggl_texEnvi(con, target, pname, params[0]);
- break;
- case GGL_TEXTURE_ENV_COLOR: {
- uint8_t* const color = c->activeTMU->env_color;
- const GGLclampx r = gglClampx(params[0]);
- const GGLclampx g = gglClampx(params[1]);
- const GGLclampx b = gglClampx(params[2]);
- const GGLclampx a = gglClampx(params[3]);
- color[0] = (a-(a>>8))>>8;
- color[1] = (r-(r>>8))>>8;
- color[2] = (g-(g>>8))>>8;
- color[3] = (b-(b>>8))>>8;
- break;
- }
- default:
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
-}
-
-
-static void ggl_texParameteri(void* con,
- GGLenum target,
- GGLenum pname,
- GGLint param)
-{
- GGL_CONTEXT(c, con);
- if (target != GGL_TEXTURE_2D) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
-
- if (param == GGL_CLAMP_TO_EDGE)
- param = GGL_CLAMP;
-
- uint16_t* what = 0;
- switch (pname) {
- case GGL_TEXTURE_WRAP_S:
- if ((param == GGL_CLAMP) ||
- (param == GGL_REPEAT)) {
- what = &c->activeTMU->s_wrap;
- }
- break;
- case GGL_TEXTURE_WRAP_T:
- if ((param == GGL_CLAMP) ||
- (param == GGL_REPEAT)) {
- what = &c->activeTMU->t_wrap;
- }
- break;
- case GGL_TEXTURE_MIN_FILTER:
- if ((param == GGL_NEAREST) ||
- (param == GGL_NEAREST_MIPMAP_NEAREST) ||
- (param == GGL_NEAREST_MIPMAP_LINEAR)) {
- what = &c->activeTMU->min_filter;
- param = GGL_NEAREST;
- }
- if ((param == GGL_LINEAR) ||
- (param == GGL_LINEAR_MIPMAP_NEAREST) ||
- (param == GGL_LINEAR_MIPMAP_LINEAR)) {
- what = &c->activeTMU->min_filter;
- param = GGL_LINEAR;
- }
- break;
- case GGL_TEXTURE_MAG_FILTER:
- if ((param == GGL_NEAREST) ||
- (param == GGL_LINEAR)) {
- what = &c->activeTMU->mag_filter;
- }
- break;
- }
-
- if (!what) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
-
- if (*what != param) {
- *what = param;
- ggl_state_changed(c, GGL_TMU_STATE);
- }
-}
-
-static void ggl_texCoordGradScale8xv(void* con, GGLint tmu, const int32_t* grad)
-{
- GGL_CONTEXT(c, con);
- texture_t& u = c->state.texture[tmu];
- u.shade.is0 = grad[0];
- u.shade.idsdx = grad[1];
- u.shade.idsdy = grad[2];
- u.shade.it0 = grad[3];
- u.shade.idtdx = grad[4];
- u.shade.idtdy = grad[5];
- u.shade.sscale= grad[6];
- u.shade.tscale= grad[7];
-}
-
-static void ggl_texCoord2x(void* con, GGLfixed s, GGLfixed t)
-{
- GGL_CONTEXT(c, con);
- c->activeTMU->shade.is0 = s;
- c->activeTMU->shade.it0 = t;
- c->activeTMU->shade.sscale= 0;
- c->activeTMU->shade.tscale= 0;
-}
-
-static void ggl_texCoord2i(void* con, GGLint s, GGLint t)
-{
- ggl_texCoord2x(con, s<<16, t<<16);
-}
-
-static void ggl_texGeni(void* con, GGLenum coord, GGLenum pname, GGLint param)
-{
- GGL_CONTEXT(c, con);
- if (pname != GGL_TEXTURE_GEN_MODE) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
-
- uint32_t* coord_ptr = 0;
- if (coord == GGL_S) coord_ptr = &(c->activeTMU->s_coord);
- else if (coord == GGL_T) coord_ptr = &(c->activeTMU->t_coord);
-
- if (coord_ptr) {
- if (*coord_ptr != uint32_t(param)) {
- *coord_ptr = uint32_t(param);
- ggl_state_changed(c, GGL_TMU_STATE);
- }
- } else {
- ggl_error(c, GGL_INVALID_ENUM);
- }
-}
-
-static void ggl_activeTexture(void* con, GGLuint tmu)
-{
- GGL_CONTEXT(c, con);
- if (tmu >= GGLuint(GGL_TEXTURE_UNIT_COUNT)) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
- c->activeTMUIndex = tmu;
- c->activeTMU = &(c->state.texture[tmu]);
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_colorMask(void* con, GGLboolean r,
- GGLboolean g,
- GGLboolean b,
- GGLboolean a)
-{
- GGL_CONTEXT(c, con);
- int mask = 0;
- if (a) mask |= 1 << GGLFormat::ALPHA;
- if (r) mask |= 1 << GGLFormat::RED;
- if (g) mask |= 1 << GGLFormat::GREEN;
- if (b) mask |= 1 << GGLFormat::BLUE;
- if (c->state.mask.color != mask) {
- c->state.mask.color = mask;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-static void ggl_depthMask(void* con, GGLboolean flag)
-{
- GGL_CONTEXT(c, con);
- if (c->state.mask.depth != flag?1:0) {
- c->state.mask.depth = flag?1:0;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-static void ggl_stencilMask(void* con, GGLuint mask)
-{
- GGL_CONTEXT(c, con);
- if (c->state.mask.stencil != mask) {
- c->state.mask.stencil = mask;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_alphaFuncx(void* con, GGLenum func, GGLclampx ref)
-{
- GGL_CONTEXT(c, con);
- if ((func < GGL_NEVER) || (func > GGL_ALWAYS)) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
- c->state.alpha_test.ref = gglFixedToIteratedColor(gglClampx(ref));
- if (c->state.alpha_test.func != func) {
- c->state.alpha_test.func = func;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_depthFunc(void* con, GGLenum func)
-{
- GGL_CONTEXT(c, con);
- if ((func < GGL_NEVER) || (func > GGL_ALWAYS)) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
- if (c->state.depth_test.func != func) {
- c->state.depth_test.func = func;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static void ggl_logicOp(void* con, GGLenum opcode)
-{
- GGL_CONTEXT(c, con);
- if ((opcode < GGL_CLEAR) || (opcode > GGL_SET)) {
- ggl_error(c, GGL_INVALID_ENUM);
- return;
- }
- if (c->state.logic_op.opcode != opcode) {
- c->state.logic_op.opcode = opcode;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-
-// ----------------------------------------------------------------------------
-
-void ggl_set_scissor(context_t* c)
-{
- if (c->state.enables & GGL_ENABLE_SCISSOR_TEST) {
- const int32_t l = c->state.scissor.user_left;
- const int32_t t = c->state.scissor.user_top;
- const int32_t r = c->state.scissor.user_right;
- const int32_t b = c->state.scissor.user_bottom;
- c->state.scissor.left = max(0, l);
- c->state.scissor.right = min(c->state.buffers.color.width, r);
- c->state.scissor.top = max(0, t);
- c->state.scissor.bottom = min(c->state.buffers.color.height, b);
- } else {
- c->state.scissor.left = 0;
- c->state.scissor.top = 0;
- c->state.scissor.right = c->state.buffers.color.width;
- c->state.scissor.bottom = c->state.buffers.color.height;
- }
-}
-
-void ggl_enable_blending(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_BLENDING)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_BLENDING;
- else c->state.enables &= ~GGL_ENABLE_BLENDING;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_scissor_test(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_SCISSOR_TEST)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_SCISSOR_TEST;
- else c->state.enables &= ~GGL_ENABLE_SCISSOR_TEST;
- ggl_set_scissor(c);
- }
-}
-
-void ggl_enable_alpha_test(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_ALPHA_TEST)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_ALPHA_TEST;
- else c->state.enables &= ~GGL_ENABLE_ALPHA_TEST;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_logic_op(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_LOGIC_OP)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_LOGIC_OP;
- else c->state.enables &= ~GGL_ENABLE_LOGIC_OP;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_dither(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_DITHER)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_DITHER;
- else c->state.enables &= ~GGL_ENABLE_DITHER;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_stencil_test(context_t* /*c*/, int /*enable*/)
-{
-}
-
-void ggl_enable_depth_test(context_t* c, int enable)
-{
- if (c->state.buffers.depth.format == 0)
- enable = 0;
- const int e = (c->state.enables & GGL_ENABLE_DEPTH_TEST)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_DEPTH_TEST;
- else c->state.enables &= ~GGL_ENABLE_DEPTH_TEST;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_aa(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_AA)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_AA;
- else c->state.enables &= ~GGL_ENABLE_AA;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_point_aa_nice(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_POINT_AA_NICE)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_POINT_AA_NICE;
- else c->state.enables &= ~GGL_ENABLE_POINT_AA_NICE;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_w_lerp(context_t* c, int enable)
-{
- const int e = (c->state.enables & GGL_ENABLE_W)?1:0;
- if (e != enable) {
- if (enable) c->state.enables |= GGL_ENABLE_W;
- else c->state.enables &= ~GGL_ENABLE_W;
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE);
- }
-}
-
-void ggl_enable_texture2d(context_t* c, int enable)
-{
- if (c->activeTMU->enable != enable) {
- const uint32_t tmu = c->activeTMUIndex;
- c->activeTMU->enable = enable;
- const uint32_t mask = 1UL << tmu;
- if (enable) c->state.enabled_tmu |= mask;
- else c->state.enabled_tmu &= ~mask;
- if (c->state.enabled_tmu) c->state.enables |= GGL_ENABLE_TMUS;
- else c->state.enables &= ~GGL_ENABLE_TMUS;
- ggl_state_changed(c, GGL_TMU_STATE);
- }
-}
-
-
-// ----------------------------------------------------------------------------
-
-int64_t ggl_system_time()
-{
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &t);
- return int64_t(t.tv_sec)*1000000000LL + t.tv_nsec;
-}
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_procs(context_t* c)
-{
- GGLContext& procs = *(GGLContext*)c;
- GGL_INIT_PROC(procs, scissor);
- GGL_INIT_PROC(procs, activeTexture);
- GGL_INIT_PROC(procs, bindTexture);
- GGL_INIT_PROC(procs, bindTextureLod);
- GGL_INIT_PROC(procs, colorBuffer);
- GGL_INIT_PROC(procs, readBuffer);
- GGL_INIT_PROC(procs, depthBuffer);
- GGL_INIT_PROC(procs, enable);
- GGL_INIT_PROC(procs, disable);
- GGL_INIT_PROC(procs, enableDisable);
- GGL_INIT_PROC(procs, shadeModel);
- GGL_INIT_PROC(procs, color4xv);
- GGL_INIT_PROC(procs, colorGrad12xv);
- GGL_INIT_PROC(procs, zGrad3xv);
- GGL_INIT_PROC(procs, wGrad3xv);
- GGL_INIT_PROC(procs, fogGrad3xv);
- GGL_INIT_PROC(procs, fogColor3xv);
- GGL_INIT_PROC(procs, blendFunc);
- GGL_INIT_PROC(procs, blendFuncSeparate);
- GGL_INIT_PROC(procs, texEnvi);
- GGL_INIT_PROC(procs, texEnvxv);
- GGL_INIT_PROC(procs, texParameteri);
- GGL_INIT_PROC(procs, texCoord2i);
- GGL_INIT_PROC(procs, texCoord2x);
- GGL_INIT_PROC(procs, texCoordGradScale8xv);
- GGL_INIT_PROC(procs, texGeni);
- GGL_INIT_PROC(procs, colorMask);
- GGL_INIT_PROC(procs, depthMask);
- GGL_INIT_PROC(procs, stencilMask);
- GGL_INIT_PROC(procs, alphaFuncx);
- GGL_INIT_PROC(procs, depthFunc);
- GGL_INIT_PROC(procs, logicOp);
- ggl_init_clear(c);
-}
-
-void ggl_init_context(context_t* c)
-{
- memset(c, 0, sizeof(context_t));
- ggl_init_procs(c);
- ggl_init_trap(c);
- ggl_init_scanline(c);
- ggl_init_texture(c);
- ggl_init_picker(c);
- ggl_init_raster(c);
- c->formats = gglGetPixelFormatTable();
- c->state.blend.src = GGL_ONE;
- c->state.blend.dst = GGL_ZERO;
- c->state.blend.src_alpha = GGL_ONE;
- c->state.blend.dst_alpha = GGL_ZERO;
- c->state.mask.color = 0xF;
- c->state.mask.depth = 0;
- c->state.mask.stencil = 0xFFFFFFFF;
- c->state.logic_op.opcode = GGL_COPY;
- c->state.alpha_test.func = GGL_ALWAYS;
- c->state.depth_test.func = GGL_LESS;
- c->state.depth_test.clearValue = FIXED_ONE;
- c->shade.w0 = FIXED_ONE;
- memcpy(c->ditherMatrix, gDitherMatrix, sizeof(gDitherMatrix));
-}
-
-void ggl_uninit_context(context_t* c)
-{
- ggl_uninit_scanline(c);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-
-
-using namespace android;
-
-ssize_t gglInit(GGLContext** context)
-{
- void* const base = malloc(sizeof(context_t) + 32);
- if (base) {
- // always align the context on cache lines
- context_t *c = (context_t *)((ptrdiff_t(base)+31) & ~0x1FL);
- ggl_init_context(c);
- c->base = base;
- *context = (GGLContext*)c;
- } else {
- return -1;
- }
- return 0;
-}
-
-ssize_t gglUninit(GGLContext* con)
-{
- GGL_CONTEXT(c, (void*)con);
- ggl_uninit_context(c);
- free(c->base);
- return 0;
-}
-
diff --git a/libpixelflinger/raster.cpp b/libpixelflinger/raster.cpp
deleted file mode 100644
index e95c2c8..0000000
--- a/libpixelflinger/raster.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/* libs/pixelflinger/raster.cpp
-**
-** Copyright 2006, 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 <string.h>
-
-#include "raster.h"
-#include "trap.h"
-
-namespace android {
-
-static void ggl_rasterPos2x(void* con, GGLfixed x, GGLfixed y);
-static void ggl_rasterPos2i(void* con, GGLint x, GGLint y);
-static void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
- GGLsizei width, GGLsizei height, GGLenum type);
-
-void ggl_init_raster(context_t* c)
-{
- GGLContext& procs = *(GGLContext*)c;
- GGL_INIT_PROC(procs, copyPixels);
- GGL_INIT_PROC(procs, rasterPos2x);
- GGL_INIT_PROC(procs, rasterPos2i);
-}
-
-void ggl_rasterPos2x(void* con, GGLfixed x, GGLfixed y)
-{
- GGL_CONTEXT(c, con);
- // raster pos should be processed just like glVertex
- c->state.raster.x = x;
- c->state.raster.y = y;
-}
-
-void ggl_rasterPos2i(void* con, GGLint x, GGLint y)
-{
- ggl_rasterPos2x(con, gglIntToFixed(x), gglIntToFixed(y));
-}
-
-void ggl_copyPixels(void* con, GGLint xs, GGLint ys,
- GGLsizei width, GGLsizei height, GGLenum /*type*/)
-{
- GGL_CONTEXT(c, con);
-
- // color-buffer
- surface_t* cb = &(c->state.buffers.color);
-
- // undefined behaviour if we try to copy from outside the surface
- if (uint32_t(xs) > cb->width)
- return;
- if (uint32_t(ys) > cb->height)
- return;
- if (uint32_t(xs + width) > cb->width)
- return;
- if (uint32_t(ys + height) > cb->height)
- return;
-
- // copy to current raster position
- GGLint xd = gglFixedToIntRound(c->state.raster.x);
- GGLint yd = gglFixedToIntRound(c->state.raster.y);
-
- // clip to scissor
- if (xd < GGLint(c->state.scissor.left)) {
- GGLint offset = GGLint(c->state.scissor.left) - xd;
- xd = GGLint(c->state.scissor.left);
- xs += offset;
- width -= offset;
- }
- if (yd < GGLint(c->state.scissor.top)) {
- GGLint offset = GGLint(c->state.scissor.top) - yd;
- yd = GGLint(c->state.scissor.top);
- ys += offset;
- height -= offset;
- }
- if ((xd + width) > GGLint(c->state.scissor.right)) {
- width = GGLint(c->state.scissor.right) - xd;
- }
- if ((yd + height) > GGLint(c->state.scissor.bottom)) {
- height = GGLint(c->state.scissor.bottom) - yd;
- }
-
- if (width<=0 || height<=0) {
- return; // nothing to copy
- }
-
- if (xs==xd && ys==yd) {
- // nothing to do, but be careful, this might not be true when we support
- // gglPixelTransfer, gglPixelMap and gglPixelZoom
- return;
- }
-
- const GGLFormat* fp = &(c->formats[cb->format]);
- uint8_t* src = reinterpret_cast<uint8_t*>(cb->data)
- + (xs + (cb->stride * ys)) * fp->size;
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data)
- + (xd + (cb->stride * yd)) * fp->size;
- const size_t bpr = cb->stride * fp->size;
- const size_t rowsize = width * fp->size;
- size_t yc = height;
-
- if (ys < yd) {
- // bottom to top
- src += height * bpr;
- dst += height * bpr;
- do {
- dst -= bpr;
- src -= bpr;
- memcpy(dst, src, rowsize);
- } while (--yc);
- } else {
- if (ys == yd) {
- // might be right to left
- do {
- memmove(dst, src, rowsize);
- dst += bpr;
- src += bpr;
- } while (--yc);
- } else {
- // top to bottom
- do {
- memcpy(dst, src, rowsize);
- dst += bpr;
- src += bpr;
- } while (--yc);
- }
- }
-}
-
-}; // namespace android
-
-using namespace android;
-
-GGLint gglBitBlit(GGLContext* con, int tmu, GGLint crop[4], GGLint where[4])
-{
- GGL_CONTEXT(c, (void*)con);
-
- GGLint x = where[0];
- GGLint y = where[1];
- GGLint w = where[2];
- GGLint h = where[3];
-
- // exclsively enable this tmu
- c->procs.activeTexture(c, tmu);
- c->procs.disable(c, GGL_W_LERP);
-
- uint32_t tmus = 1UL<<tmu;
- if (c->state.enabled_tmu != tmus) {
- c->activeTMU->enable = 1;
- c->state.enabled_tmu = tmus;
- c->state.enables |= GGL_ENABLE_TMUS;
- ggl_state_changed(c, GGL_TMU_STATE);
- }
-
- const GGLint Wcr = crop[2];
- const GGLint Hcr = crop[3];
- if ((w == Wcr) && (h == Hcr)) {
- c->procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
- c->procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
- const GGLint Ucr = crop[0];
- const GGLint Vcr = crop[1];
- const GGLint s0 = Ucr - x;
- const GGLint t0 = Vcr - y;
- c->procs.texCoord2i(c, s0, t0);
- c->procs.recti(c, x, y, x+w, y+h);
- } else {
- int32_t texcoords[8];
- x = gglIntToFixed(x);
- y = gglIntToFixed(y);
-
- // we CLAMP here, which works with premultiplied (s,t)
- c->procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
- c->procs.texParameteri(c, GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
- c->procs.texGeni(c, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
- c->procs.texGeni(c, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
-
- const GGLint Ucr = crop[0] << 16;
- const GGLint Vcr = crop[1] << 16;
- const GGLint Wcr = crop[2] << 16;
- const GGLint Hcr = crop[3] << 16;
-
- // computes texture coordinates (pre-multiplied)
- int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
- int32_t dtdy = Hcr / h; // dtdy = ((Hcr/h)/Ht)*Ht
- int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
- int32_t t0 = Vcr - gglMulx(dtdy, y); // t0 = Vcr - y * dtdy
- texcoords[0] = s0;
- texcoords[1] = dsdx;
- texcoords[2] = 0;
- texcoords[3] = t0;
- texcoords[4] = 0;
- texcoords[5] = dtdy;
- texcoords[6] = 0;
- texcoords[7] = 0;
- c->procs.texCoordGradScale8xv(c, tmu, texcoords);
- c->procs.recti(c,
- gglFixedToIntRound(x),
- gglFixedToIntRound(y),
- gglFixedToIntRound(x)+w,
- gglFixedToIntRound(y)+h);
- }
- return 0;
-}
-
diff --git a/libpixelflinger/raster.h b/libpixelflinger/raster.h
deleted file mode 100644
index 9f0f240..0000000
--- a/libpixelflinger/raster.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* libs/pixelflinger/raster.h
-**
-** Copyright 2006, 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 ANDROID_GGL_RASTER_H
-#define ANDROID_GGL_RASTER_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_raster(context_t* c);
-
-void gglCopyPixels(void* c, GGLint x, GGLint y, GGLsizei width, GGLsizei height, GGLenum type);
-void gglRasterPos2d(void* c, GGLint x, GGLint y);
-
-}; // namespace android
-
-#endif // ANDROID_GGL_RASTER_H
diff --git a/libpixelflinger/scanline.cpp b/libpixelflinger/scanline.cpp
deleted file mode 100644
index 4cc23c7..0000000
--- a/libpixelflinger/scanline.cpp
+++ /dev/null
@@ -1,2373 +0,0 @@
-/* libs/pixelflinger/scanline.cpp
-**
-** Copyright 2006-2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "pixelflinger"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <cutils/memory.h>
-#include <log/log.h>
-
-#include "buffer.h"
-#include "scanline.h"
-
-#include "codeflinger/CodeCache.h"
-#include "codeflinger/GGLAssembler.h"
-#if defined(__arm__)
-#include "codeflinger/ARMAssembler.h"
-#elif defined(__aarch64__)
-#include "codeflinger/Arm64Assembler.h"
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-#include "codeflinger/MIPSAssembler.h"
-#elif defined(__mips__) && defined(__LP64__)
-#include "codeflinger/MIPS64Assembler.h"
-#endif
-//#include "codeflinger/ARMAssemblerOptimizer.h"
-
-// ----------------------------------------------------------------------------
-
-#define ANDROID_CODEGEN_GENERIC 0 // force generic pixel pipeline
-#define ANDROID_CODEGEN_C 1 // hand-written C, fallback generic
-#define ANDROID_CODEGEN_ASM 2 // hand-written asm, fallback generic
-#define ANDROID_CODEGEN_GENERATED 3 // hand-written asm, fallback codegen
-
-#ifdef NDEBUG
-# define ANDROID_RELEASE
-# define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED
-#else
-# define ANDROID_DEBUG
-# define ANDROID_CODEGEN ANDROID_CODEGEN_GENERATED
-#endif
-
-#if defined(__arm__) || (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))) || defined(__aarch64__)
-# define ANDROID_ARM_CODEGEN 1
-#else
-# define ANDROID_ARM_CODEGEN 0
-#endif
-
-#define DEBUG__CODEGEN_ONLY 0
-
-/* Set to 1 to dump to the log the states that need a new
- * code-generated scanline callback, i.e. those that don't
- * have a corresponding shortcut function.
- */
-#define DEBUG_NEEDS 0
-
-#if defined( __mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))
-#define ASSEMBLY_SCRATCH_SIZE 4096
-#elif defined(__aarch64__)
-#define ASSEMBLY_SCRATCH_SIZE 8192
-#else
-#define ASSEMBLY_SCRATCH_SIZE 2048
-#endif
-
-// ----------------------------------------------------------------------------
-namespace android {
-// ----------------------------------------------------------------------------
-
-static void init_y(context_t*, int32_t);
-static void init_y_noop(context_t*, int32_t);
-static void init_y_packed(context_t*, int32_t);
-static void init_y_error(context_t*, int32_t);
-
-static void step_y__generic(context_t* c);
-static void step_y__nop(context_t*);
-static void step_y__smooth(context_t* c);
-static void step_y__tmu(context_t* c);
-static void step_y__w(context_t* c);
-
-static void scanline(context_t* c);
-static void scanline_perspective(context_t* c);
-static void scanline_perspective_single(context_t* c);
-static void scanline_t32cb16blend(context_t* c);
-static void scanline_t32cb16blend_dither(context_t* c);
-static void scanline_t32cb16blend_srca(context_t* c);
-static void scanline_t32cb16blend_clamp(context_t* c);
-static void scanline_t32cb16blend_clamp_dither(context_t* c);
-static void scanline_t32cb16blend_clamp_mod(context_t* c);
-static void scanline_x32cb16blend_clamp_mod(context_t* c);
-static void scanline_t32cb16blend_clamp_mod_dither(context_t* c);
-static void scanline_x32cb16blend_clamp_mod_dither(context_t* c);
-static void scanline_t32cb16(context_t* c);
-static void scanline_t32cb16_dither(context_t* c);
-static void scanline_t32cb16_clamp(context_t* c);
-static void scanline_t32cb16_clamp_dither(context_t* c);
-static void scanline_col32cb16blend(context_t* c);
-static void scanline_t16cb16_clamp(context_t* c);
-static void scanline_t16cb16blend_clamp_mod(context_t* c);
-static void scanline_memcpy(context_t* c);
-static void scanline_memset8(context_t* c);
-static void scanline_memset16(context_t* c);
-static void scanline_memset32(context_t* c);
-static void scanline_noop(context_t* c);
-static void scanline_set(context_t* c);
-static void scanline_clear(context_t* c);
-
-static void rect_generic(context_t* c, size_t yc);
-static void rect_memcpy(context_t* c, size_t yc);
-
-#if defined( __arm__)
-extern "C" void scanline_t32cb16blend_arm(uint16_t*, uint32_t*, size_t);
-extern "C" void scanline_t32cb16_arm(uint16_t *dst, uint32_t *src, size_t ct);
-extern "C" void scanline_col32cb16blend_neon(uint16_t *dst, uint32_t *col, size_t ct);
-extern "C" void scanline_col32cb16blend_arm(uint16_t *dst, uint32_t col, size_t ct);
-#elif defined(__aarch64__)
-extern "C" void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
-extern "C" void scanline_col32cb16blend_arm64(uint16_t *dst, uint32_t col, size_t ct);
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-extern "C" void scanline_t32cb16blend_mips(uint16_t*, uint32_t*, size_t);
-#elif defined(__mips__) && defined(__LP64__)
-extern "C" void scanline_t32cb16blend_mips64(uint16_t*, uint32_t*, size_t);
-extern "C" void scanline_col32cb16blend_mips64(uint16_t *dst, uint32_t col, size_t ct);
-#endif
-
-// ----------------------------------------------------------------------------
-
-static inline uint16_t convertAbgr8888ToRgb565(uint32_t pix)
-{
- return uint16_t( ((pix << 8) & 0xf800) |
- ((pix >> 5) & 0x07e0) |
- ((pix >> 19) & 0x001f) );
-}
-
-struct shortcut_t {
- needs_filter_t filter;
- const char* desc;
- void (*scanline)(context_t*);
- void (*init_y)(context_t*, int32_t);
-};
-
-// Keep in sync with needs
-
-/* To understand the values here, have a look at:
- * system/core/include/private/pixelflinger/ggl_context.h
- *
- * Especially the lines defining and using GGL_RESERVE_NEEDS
- *
- * Quick reminders:
- * - the last nibble of the first value is the destination buffer format.
- * - the last nibble of the third value is the source texture format
- * - formats: 4=rgb565 1=abgr8888 2=xbgr8888
- *
- * In the descriptions below:
- *
- * SRC means we copy the source pixels to the destination
- *
- * SRC_OVER means we blend the source pixels to the destination
- * with dstFactor = 1-srcA, srcFactor=1 (premultiplied source).
- * This mode is otherwise called 'blend'.
- *
- * SRCA_OVER means we blend the source pixels to the destination
- * with dstFactor=srcA*(1-srcA) srcFactor=srcA (non-premul source).
- * This mode is otherwise called 'blend_srca'
- *
- * clamp means we fetch source pixels from a texture with u/v clamping
- *
- * mod means the source pixels are modulated (multiplied) by the
- * a/r/g/b of the current context's color. Typically used for
- * fade-in / fade-out.
- *
- * dither means we dither 32 bit values to 16 bits
- */
-static shortcut_t shortcuts[] = {
- { { { 0x03515104, 0x00000077, { 0x00000A01, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, blend SRC_OVER", scanline_t32cb16blend, init_y_noop },
- { { { 0x03010104, 0x00000077, { 0x00000A01, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC", scanline_t32cb16, init_y_noop },
- /* same as first entry, but with dithering */
- { { { 0x03515104, 0x00000177, { 0x00000A01, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, blend SRC_OVER dither", scanline_t32cb16blend_dither, init_y_noop },
- /* same as second entry, but with dithering */
- { { { 0x03010104, 0x00000177, { 0x00000A01, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC dither", scanline_t32cb16_dither, init_y_noop },
- /* this is used during the boot animation - CHEAT: ignore dithering */
- { { { 0x03545404, 0x00000077, { 0x00000A01, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFEFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, blend dst:ONE_MINUS_SRCA src:SRCA", scanline_t32cb16blend_srca, init_y_noop },
- /* special case for arbitrary texture coordinates (think scaling) */
- { { { 0x03515104, 0x00000077, { 0x00000001, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC_OVER clamp", scanline_t32cb16blend_clamp, init_y },
- { { { 0x03515104, 0x00000177, { 0x00000001, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC_OVER clamp dither", scanline_t32cb16blend_clamp_dither, init_y },
- /* another case used during emulation */
- { { { 0x03515104, 0x00000077, { 0x00001001, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC_OVER clamp modulate", scanline_t32cb16blend_clamp_mod, init_y },
- /* and this */
- { { { 0x03515104, 0x00000077, { 0x00001002, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, x888 tx, SRC_OVER clamp modulate", scanline_x32cb16blend_clamp_mod, init_y },
- { { { 0x03515104, 0x00000177, { 0x00001001, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC_OVER clamp modulate dither", scanline_t32cb16blend_clamp_mod_dither, init_y },
- { { { 0x03515104, 0x00000177, { 0x00001002, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, x888 tx, SRC_OVER clamp modulate dither", scanline_x32cb16blend_clamp_mod_dither, init_y },
- { { { 0x03010104, 0x00000077, { 0x00000001, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC clamp", scanline_t32cb16_clamp, init_y },
- { { { 0x03010104, 0x00000077, { 0x00000002, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, x888 tx, SRC clamp", scanline_t32cb16_clamp, init_y },
- { { { 0x03010104, 0x00000177, { 0x00000001, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 8888 tx, SRC clamp dither", scanline_t32cb16_clamp_dither, init_y },
- { { { 0x03010104, 0x00000177, { 0x00000002, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, x888 tx, SRC clamp dither", scanline_t32cb16_clamp_dither, init_y },
- { { { 0x03010104, 0x00000077, { 0x00000004, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 565 tx, SRC clamp", scanline_t16cb16_clamp, init_y },
- { { { 0x03515104, 0x00000077, { 0x00001004, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0x0000003F } } },
- "565 fb, 565 tx, SRC_OVER clamp", scanline_t16cb16blend_clamp_mod, init_y },
- { { { 0x03515104, 0x00000077, { 0x00000000, 0x00000000 } },
- { 0xFFFFFFFF, 0xFFFFFFFF, { 0xFFFFFFFF, 0xFFFFFFFF } } },
- "565 fb, 8888 fixed color", scanline_col32cb16blend, init_y_packed },
- { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
- { 0x00000000, 0x00000007, { 0x00000000, 0x00000000 } } },
- "(nop) alpha test", scanline_noop, init_y_noop },
- { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
- { 0x00000000, 0x00000070, { 0x00000000, 0x00000000 } } },
- "(nop) depth test", scanline_noop, init_y_noop },
- { { { 0x05000000, 0x00000000, { 0x00000000, 0x00000000 } },
- { 0x0F000000, 0x00000080, { 0x00000000, 0x00000000 } } },
- "(nop) logic_op", scanline_noop, init_y_noop },
- { { { 0xF0000000, 0x00000000, { 0x00000000, 0x00000000 } },
- { 0xF0000000, 0x00000080, { 0x00000000, 0x00000000 } } },
- "(nop) color mask", scanline_noop, init_y_noop },
- { { { 0x0F000000, 0x00000077, { 0x00000000, 0x00000000 } },
- { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } },
- "(set) logic_op", scanline_set, init_y_noop },
- { { { 0x00000000, 0x00000077, { 0x00000000, 0x00000000 } },
- { 0xFF000000, 0x000000F7, { 0x00000000, 0x00000000 } } },
- "(clear) logic_op", scanline_clear, init_y_noop },
- { { { 0x03000000, 0x00000077, { 0x00000000, 0x00000000 } },
- { 0xFFFFFF00, 0x000000F7, { 0x00000000, 0x00000000 } } },
- "(clear) blending 0/0", scanline_clear, init_y_noop },
- { { { 0x00000000, 0x00000000, { 0x00000000, 0x00000000 } },
- { 0x0000003F, 0x00000000, { 0x00000000, 0x00000000 } } },
- "(error) invalid color-buffer format", scanline_noop, init_y_error },
-};
-static const needs_filter_t noblend1to1 = {
- // (disregard dithering, see below)
- { 0x03010100, 0x00000077, { 0x00000A00, 0x00000000 } },
- { 0xFFFFFFC0, 0xFFFFFEFF, { 0xFFFFFFC0, 0x0000003F } }
-};
-static const needs_filter_t fill16noblend = {
- { 0x03010100, 0x00000077, { 0x00000000, 0x00000000 } },
- { 0xFFFFFFC0, 0xFFFFFFFF, { 0x0000003F, 0x0000003F } }
-};
-
-// ----------------------------------------------------------------------------
-
-#if ANDROID_ARM_CODEGEN
-
-#if defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__))
-static CodeCache gCodeCache(32 * 1024);
-#elif defined(__aarch64__)
-static CodeCache gCodeCache(48 * 1024);
-#else
-static CodeCache gCodeCache(12 * 1024);
-#endif
-
-class ScanlineAssembly : public Assembly {
- AssemblyKey<needs_t> mKey;
-public:
- ScanlineAssembly(needs_t needs, size_t size)
- : Assembly(size), mKey(needs) { }
- const AssemblyKey<needs_t>& key() const { return mKey; }
-};
-#endif
-
-// ----------------------------------------------------------------------------
-
-void ggl_init_scanline(context_t* c)
-{
- c->init_y = init_y;
- c->step_y = step_y__generic;
- c->scanline = scanline;
-}
-
-void ggl_uninit_scanline(context_t* c)
-{
- if (c->state.buffers.coverage)
- free(c->state.buffers.coverage);
-#if ANDROID_ARM_CODEGEN
- if (c->scanline_as)
- c->scanline_as->decStrong(c);
-#endif
-}
-
-// ----------------------------------------------------------------------------
-
-static void pick_scanline(context_t* c)
-{
-#if (!defined(DEBUG__CODEGEN_ONLY) || (DEBUG__CODEGEN_ONLY == 0))
-
-#if ANDROID_CODEGEN == ANDROID_CODEGEN_GENERIC
- c->init_y = init_y;
- c->step_y = step_y__generic;
- c->scanline = scanline;
- return;
-#endif
-
- //printf("*** needs [%08lx:%08lx:%08lx:%08lx]\n",
- // c->state.needs.n, c->state.needs.p,
- // c->state.needs.t[0], c->state.needs.t[1]);
-
- // first handle the special case that we cannot test with a filter
- const uint32_t cb_format = GGL_READ_NEEDS(CB_FORMAT, c->state.needs.n);
- if (GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0]) == cb_format) {
- if (c->state.needs.match(noblend1to1)) {
- // this will match regardless of dithering state, since both
- // src and dest have the same format anyway, there is no dithering
- // to be done.
- const GGLFormat* f =
- &(c->formats[GGL_READ_NEEDS(T_FORMAT, c->state.needs.t[0])]);
- if ((f->components == GGL_RGB) ||
- (f->components == GGL_RGBA) ||
- (f->components == GGL_LUMINANCE) ||
- (f->components == GGL_LUMINANCE_ALPHA))
- {
- // format must have all of RGB components
- // (so the current color doesn't show through)
- c->scanline = scanline_memcpy;
- c->init_y = init_y_noop;
- return;
- }
- }
- }
-
- if (c->state.needs.match(fill16noblend)) {
- c->init_y = init_y_packed;
- switch (c->formats[cb_format].size) {
- case 1: c->scanline = scanline_memset8; return;
- case 2: c->scanline = scanline_memset16; return;
- case 4: c->scanline = scanline_memset32; return;
- }
- }
-
- const int numFilters = sizeof(shortcuts)/sizeof(shortcut_t);
- for (int i=0 ; i<numFilters ; i++) {
- if (c->state.needs.match(shortcuts[i].filter)) {
- c->scanline = shortcuts[i].scanline;
- c->init_y = shortcuts[i].init_y;
- return;
- }
- }
-
-#if DEBUG_NEEDS
- ALOGI("Needs: n=0x%08x p=0x%08x t0=0x%08x t1=0x%08x",
- c->state.needs.n, c->state.needs.p,
- c->state.needs.t[0], c->state.needs.t[1]);
-#endif
-
-#endif // DEBUG__CODEGEN_ONLY
-
- c->init_y = init_y;
- c->step_y = step_y__generic;
-
-#if ANDROID_ARM_CODEGEN
- // we're going to have to generate some code...
- // here, generate code for our pixel pipeline
- const AssemblyKey<needs_t> key(c->state.needs);
- sp<Assembly> assembly = gCodeCache.lookup(key);
- if (assembly == 0) {
- // create a new assembly region
- sp<ScanlineAssembly> a = new ScanlineAssembly(c->state.needs,
- ASSEMBLY_SCRATCH_SIZE);
- // initialize our assembler
-#if defined(__arm__)
- GGLAssembler assembler( new ARMAssembler(a) );
- //GGLAssembler assembler(
- // new ARMAssemblerOptimizer(new ARMAssembler(a)) );
-#endif
-#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
- GGLAssembler assembler( new ArmToMipsAssembler(a) );
-#elif defined(__mips__) && defined(__LP64__)
- GGLAssembler assembler( new ArmToMips64Assembler(a) );
-#elif defined(__aarch64__)
- GGLAssembler assembler( new ArmToArm64Assembler(a) );
-#endif
- // generate the scanline code for the given needs
- bool err = assembler.scanline(c->state.needs, c) != 0;
- if (ggl_likely(!err)) {
- // finally, cache this assembly
- err = gCodeCache.cache(a->key(), a) < 0;
- }
- if (ggl_unlikely(err)) {
- ALOGE("error generating or caching assembly. Reverting to NOP.");
- c->scanline = scanline_noop;
- c->init_y = init_y_noop;
- c->step_y = step_y__nop;
- return;
- }
- assembly = a;
- }
-
- // release the previous assembly
- if (c->scanline_as) {
- c->scanline_as->decStrong(c);
- }
-
- //ALOGI("using generated pixel-pipeline");
- c->scanline_as = assembly.get();
- c->scanline_as->incStrong(c); // hold on to assembly
- c->scanline = (void(*)(context_t* c))assembly->base();
-#else
-// ALOGW("using generic (slow) pixel-pipeline");
- c->scanline = scanline;
-#endif
-}
-
-void ggl_pick_scanline(context_t* c)
-{
- pick_scanline(c);
- if ((c->state.enables & GGL_ENABLE_W) &&
- (c->state.enables & GGL_ENABLE_TMUS))
- {
- c->span = c->scanline;
- c->scanline = scanline_perspective;
- if (!(c->state.enabled_tmu & (c->state.enabled_tmu - 1))) {
- // only one TMU enabled
- c->scanline = scanline_perspective_single;
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static void blending(context_t* c, pixel_t* fragment, pixel_t* fb);
-static void blend_factor(context_t* c, pixel_t* r, uint32_t factor,
- const pixel_t* src, const pixel_t* dst);
-static void rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv);
-
-#if ANDROID_ARM_CODEGEN && (ANDROID_CODEGEN == ANDROID_CODEGEN_GENERATED)
-
-// no need to compile the generic-pipeline, it can't be reached
-void scanline(context_t*)
-{
-}
-
-#else
-
-void rescale(uint32_t& u, uint8_t& su, uint32_t& v, uint8_t& sv)
-{
- if (su && sv) {
- if (su > sv) {
- v = ggl_expand(v, sv, su);
- sv = su;
- } else if (su < sv) {
- u = ggl_expand(u, su, sv);
- su = sv;
- }
- }
-}
-
-void blending(context_t* c, pixel_t* fragment, pixel_t* fb)
-{
- rescale(fragment->c[0], fragment->s[0], fb->c[0], fb->s[0]);
- rescale(fragment->c[1], fragment->s[1], fb->c[1], fb->s[1]);
- rescale(fragment->c[2], fragment->s[2], fb->c[2], fb->s[2]);
- rescale(fragment->c[3], fragment->s[3], fb->c[3], fb->s[3]);
-
- pixel_t sf, df;
- blend_factor(c, &sf, c->state.blend.src, fragment, fb);
- blend_factor(c, &df, c->state.blend.dst, fragment, fb);
-
- fragment->c[1] =
- gglMulAddx(fragment->c[1], sf.c[1], gglMulx(fb->c[1], df.c[1]));
- fragment->c[2] =
- gglMulAddx(fragment->c[2], sf.c[2], gglMulx(fb->c[2], df.c[2]));
- fragment->c[3] =
- gglMulAddx(fragment->c[3], sf.c[3], gglMulx(fb->c[3], df.c[3]));
-
- if (c->state.blend.alpha_separate) {
- blend_factor(c, &sf, c->state.blend.src_alpha, fragment, fb);
- blend_factor(c, &df, c->state.blend.dst_alpha, fragment, fb);
- }
-
- fragment->c[0] =
- gglMulAddx(fragment->c[0], sf.c[0], gglMulx(fb->c[0], df.c[0]));
-
- // clamp to 1.0
- if (fragment->c[0] >= (1LU<<fragment->s[0]))
- fragment->c[0] = (1<<fragment->s[0])-1;
- if (fragment->c[1] >= (1LU<<fragment->s[1]))
- fragment->c[1] = (1<<fragment->s[1])-1;
- if (fragment->c[2] >= (1LU<<fragment->s[2]))
- fragment->c[2] = (1<<fragment->s[2])-1;
- if (fragment->c[3] >= (1LU<<fragment->s[3]))
- fragment->c[3] = (1<<fragment->s[3])-1;
-}
-
-static inline int blendfactor(uint32_t x, uint32_t size, uint32_t def = 0)
-{
- if (!size)
- return def;
-
- // scale to 16 bits
- if (size > 16) {
- x >>= (size - 16);
- } else if (size < 16) {
- x = ggl_expand(x, size, 16);
- }
- x += x >> 15;
- return x;
-}
-
-void blend_factor(context_t* /*c*/, pixel_t* r,
- uint32_t factor, const pixel_t* src, const pixel_t* dst)
-{
- switch (factor) {
- case GGL_ZERO:
- r->c[1] =
- r->c[2] =
- r->c[3] =
- r->c[0] = 0;
- break;
- case GGL_ONE:
- r->c[1] =
- r->c[2] =
- r->c[3] =
- r->c[0] = FIXED_ONE;
- break;
- case GGL_DST_COLOR:
- r->c[1] = blendfactor(dst->c[1], dst->s[1]);
- r->c[2] = blendfactor(dst->c[2], dst->s[2]);
- r->c[3] = blendfactor(dst->c[3], dst->s[3]);
- r->c[0] = blendfactor(dst->c[0], dst->s[0]);
- break;
- case GGL_SRC_COLOR:
- r->c[1] = blendfactor(src->c[1], src->s[1]);
- r->c[2] = blendfactor(src->c[2], src->s[2]);
- r->c[3] = blendfactor(src->c[3], src->s[3]);
- r->c[0] = blendfactor(src->c[0], src->s[0]);
- break;
- case GGL_ONE_MINUS_DST_COLOR:
- r->c[1] = FIXED_ONE - blendfactor(dst->c[1], dst->s[1]);
- r->c[2] = FIXED_ONE - blendfactor(dst->c[2], dst->s[2]);
- r->c[3] = FIXED_ONE - blendfactor(dst->c[3], dst->s[3]);
- r->c[0] = FIXED_ONE - blendfactor(dst->c[0], dst->s[0]);
- break;
- case GGL_ONE_MINUS_SRC_COLOR:
- r->c[1] = FIXED_ONE - blendfactor(src->c[1], src->s[1]);
- r->c[2] = FIXED_ONE - blendfactor(src->c[2], src->s[2]);
- r->c[3] = FIXED_ONE - blendfactor(src->c[3], src->s[3]);
- r->c[0] = FIXED_ONE - blendfactor(src->c[0], src->s[0]);
- break;
- case GGL_SRC_ALPHA:
- r->c[1] =
- r->c[2] =
- r->c[3] =
- r->c[0] = blendfactor(src->c[0], src->s[0], FIXED_ONE);
- break;
- case GGL_ONE_MINUS_SRC_ALPHA:
- r->c[1] =
- r->c[2] =
- r->c[3] =
- r->c[0] = FIXED_ONE - blendfactor(src->c[0], src->s[0], FIXED_ONE);
- break;
- case GGL_DST_ALPHA:
- r->c[1] =
- r->c[2] =
- r->c[3] =
- r->c[0] = blendfactor(dst->c[0], dst->s[0], FIXED_ONE);
- break;
- case GGL_ONE_MINUS_DST_ALPHA:
- r->c[1] =
- r->c[2] =
- r->c[3] =
- r->c[0] = FIXED_ONE - blendfactor(dst->c[0], dst->s[0], FIXED_ONE);
- break;
- case GGL_SRC_ALPHA_SATURATE:
- // XXX: GGL_SRC_ALPHA_SATURATE
- break;
- }
-}
-
-static GGLfixed wrapping(int32_t coord, uint32_t size, int tx_wrap)
-{
- GGLfixed d;
- if (tx_wrap == GGL_REPEAT) {
- d = (uint32_t(coord)>>16) * size;
- } else if (tx_wrap == GGL_CLAMP) { // CLAMP_TO_EDGE semantics
- const GGLfixed clamp_min = FIXED_HALF;
- const GGLfixed clamp_max = (size << 16) - FIXED_HALF;
- if (coord < clamp_min) coord = clamp_min;
- if (coord > clamp_max) coord = clamp_max;
- d = coord;
- } else { // 1:1
- const GGLfixed clamp_min = 0;
- const GGLfixed clamp_max = (size << 16);
- if (coord < clamp_min) coord = clamp_min;
- if (coord > clamp_max) coord = clamp_max;
- d = coord;
- }
- return d;
-}
-
-static inline
-GGLcolor ADJUST_COLOR_ITERATOR(GGLcolor v, GGLcolor dvdx, int len)
-{
- const int32_t end = dvdx * (len-1) + v;
- if (end < 0)
- v -= end;
- v &= ~(v>>31);
- return v;
-}
-
-void scanline(context_t* c)
-{
- const uint32_t enables = c->state.enables;
- const int xs = c->iterators.xl;
- const int x1 = c->iterators.xr;
- int xc = x1 - xs;
- const int16_t* covPtr = c->state.buffers.coverage + xs;
-
- // All iterated values are sampled at the pixel center
-
- // reset iterators for that scanline...
- GGLcolor r, g, b, a;
- iterators_t& ci = c->iterators;
- if (enables & GGL_ENABLE_SMOOTH) {
- r = (xs * c->shade.drdx) + ci.ydrdy;
- g = (xs * c->shade.dgdx) + ci.ydgdy;
- b = (xs * c->shade.dbdx) + ci.ydbdy;
- a = (xs * c->shade.dadx) + ci.ydady;
- r = ADJUST_COLOR_ITERATOR(r, c->shade.drdx, xc);
- g = ADJUST_COLOR_ITERATOR(g, c->shade.dgdx, xc);
- b = ADJUST_COLOR_ITERATOR(b, c->shade.dbdx, xc);
- a = ADJUST_COLOR_ITERATOR(a, c->shade.dadx, xc);
- } else {
- r = ci.ydrdy;
- g = ci.ydgdy;
- b = ci.ydbdy;
- a = ci.ydady;
- }
-
- // z iterators are 1.31
- GGLfixed z = (xs * c->shade.dzdx) + ci.ydzdy;
- GGLfixed f = (xs * c->shade.dfdx) + ci.ydfdy;
-
- struct {
- GGLfixed s, t;
- } tc[GGL_TEXTURE_UNIT_COUNT];
- if (enables & GGL_ENABLE_TMUS) {
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- if (c->state.texture[i].enable) {
- texture_iterators_t& ti = c->state.texture[i].iterators;
- if (enables & GGL_ENABLE_W) {
- tc[i].s = ti.ydsdy;
- tc[i].t = ti.ydtdy;
- } else {
- tc[i].s = (xs * ti.dsdx) + ti.ydsdy;
- tc[i].t = (xs * ti.dtdx) + ti.ydtdy;
- }
- }
- }
- }
-
- pixel_t fragment;
- pixel_t texel;
- pixel_t fb;
-
- uint32_t x = xs;
- uint32_t y = c->iterators.y;
-
- while (xc--) {
-
- { // just a scope
-
- // read color (convert to 8 bits by keeping only the integer part)
- fragment.s[1] = fragment.s[2] =
- fragment.s[3] = fragment.s[0] = 8;
- fragment.c[1] = r >> (GGL_COLOR_BITS-8);
- fragment.c[2] = g >> (GGL_COLOR_BITS-8);
- fragment.c[3] = b >> (GGL_COLOR_BITS-8);
- fragment.c[0] = a >> (GGL_COLOR_BITS-8);
-
- // texturing
- if (enables & GGL_ENABLE_TMUS) {
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- texture_t& tx = c->state.texture[i];
- if (!tx.enable)
- continue;
- texture_iterators_t& ti = tx.iterators;
- int32_t u, v;
-
- // s-coordinate
- if (tx.s_coord != GGL_ONE_TO_ONE) {
- const int w = tx.surface.width;
- u = wrapping(tc[i].s, w, tx.s_wrap);
- tc[i].s += ti.dsdx;
- } else {
- u = (((tx.shade.is0>>16) + x)<<16) + FIXED_HALF;
- }
-
- // t-coordinate
- if (tx.t_coord != GGL_ONE_TO_ONE) {
- const int h = tx.surface.height;
- v = wrapping(tc[i].t, h, tx.t_wrap);
- tc[i].t += ti.dtdx;
- } else {
- v = (((tx.shade.it0>>16) + y)<<16) + FIXED_HALF;
- }
-
- // read texture
- if (tx.mag_filter == GGL_NEAREST &&
- tx.min_filter == GGL_NEAREST)
- {
- u >>= 16;
- v >>= 16;
- tx.surface.read(&tx.surface, c, u, v, &texel);
- } else {
- const int w = tx.surface.width;
- const int h = tx.surface.height;
- u -= FIXED_HALF;
- v -= FIXED_HALF;
- int u0 = u >> 16;
- int v0 = v >> 16;
- int u1 = u0 + 1;
- int v1 = v0 + 1;
- if (tx.s_wrap == GGL_REPEAT) {
- if (u0<0) u0 += w;
- if (u1<0) u1 += w;
- if (u0>=w) u0 -= w;
- if (u1>=w) u1 -= w;
- } else {
- if (u0<0) u0 = 0;
- if (u1<0) u1 = 0;
- if (u0>=w) u0 = w-1;
- if (u1>=w) u1 = w-1;
- }
- if (tx.t_wrap == GGL_REPEAT) {
- if (v0<0) v0 += h;
- if (v1<0) v1 += h;
- if (v0>=h) v0 -= h;
- if (v1>=h) v1 -= h;
- } else {
- if (v0<0) v0 = 0;
- if (v1<0) v1 = 0;
- if (v0>=h) v0 = h-1;
- if (v1>=h) v1 = h-1;
- }
- pixel_t texels[4];
- uint32_t mm[4];
- tx.surface.read(&tx.surface, c, u0, v0, &texels[0]);
- tx.surface.read(&tx.surface, c, u0, v1, &texels[1]);
- tx.surface.read(&tx.surface, c, u1, v0, &texels[2]);
- tx.surface.read(&tx.surface, c, u1, v1, &texels[3]);
- u = (u >> 12) & 0xF;
- v = (v >> 12) & 0xF;
- u += u>>3;
- v += v>>3;
- mm[0] = (0x10 - u) * (0x10 - v);
- mm[1] = (0x10 - u) * v;
- mm[2] = u * (0x10 - v);
- mm[3] = 0x100 - (mm[0] + mm[1] + mm[2]);
- for (int j=0 ; j<4 ; j++) {
- texel.s[j] = texels[0].s[j];
- if (!texel.s[j]) continue;
- texel.s[j] += 8;
- texel.c[j] = texels[0].c[j]*mm[0] +
- texels[1].c[j]*mm[1] +
- texels[2].c[j]*mm[2] +
- texels[3].c[j]*mm[3] ;
- }
- }
-
- // Texture environnement...
- for (int j=0 ; j<4 ; j++) {
- uint32_t& Cf = fragment.c[j];
- uint32_t& Ct = texel.c[j];
- uint8_t& sf = fragment.s[j];
- uint8_t& st = texel.s[j];
- uint32_t At = texel.c[0];
- uint8_t sat = texel.s[0];
- switch (tx.env) {
- case GGL_REPLACE:
- if (st) {
- Cf = Ct;
- sf = st;
- }
- break;
- case GGL_MODULATE:
- if (st) {
- uint32_t factor = Ct + (Ct>>(st-1));
- Cf = (Cf * factor) >> st;
- }
- break;
- case GGL_DECAL:
- if (sat) {
- rescale(Cf, sf, Ct, st);
- Cf += ((Ct - Cf) * (At + (At>>(sat-1)))) >> sat;
- }
- break;
- case GGL_BLEND:
- if (st) {
- uint32_t Cc = tx.env_color[i];
- if (sf>8) Cc = (Cc * ((1<<sf)-1))>>8;
- else if (sf<8) Cc = (Cc - (Cc>>(8-sf)))>>(8-sf);
- uint32_t factor = Ct + (Ct>>(st-1));
- Cf = ((((1<<st) - factor) * Cf) + Ct*Cc)>>st;
- }
- break;
- case GGL_ADD:
- if (st) {
- rescale(Cf, sf, Ct, st);
- Cf += Ct;
- }
- break;
- }
- }
- }
- }
-
- // coverage application
- if (enables & GGL_ENABLE_AA) {
- int16_t cf = *covPtr++;
- fragment.c[0] = (int64_t(fragment.c[0]) * cf) >> 15;
- }
-
- // alpha-test
- if (enables & GGL_ENABLE_ALPHA_TEST) {
- GGLcolor ref = c->state.alpha_test.ref;
- GGLcolor alpha = (uint64_t(fragment.c[0]) *
- ((1<<GGL_COLOR_BITS)-1)) / ((1<<fragment.s[0])-1);
- switch (c->state.alpha_test.func) {
- case GGL_NEVER: goto discard;
- case GGL_LESS: if (alpha<ref) break; goto discard;
- case GGL_EQUAL: if (alpha==ref) break; goto discard;
- case GGL_LEQUAL: if (alpha<=ref) break; goto discard;
- case GGL_GREATER: if (alpha>ref) break; goto discard;
- case GGL_NOTEQUAL: if (alpha!=ref) break; goto discard;
- case GGL_GEQUAL: if (alpha>=ref) break; goto discard;
- }
- }
-
- // depth test
- if (c->state.buffers.depth.format) {
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- surface_t* cb = &(c->state.buffers.depth);
- uint16_t* p = (uint16_t*)(cb->data)+(x+(cb->stride*y));
- uint16_t zz = uint32_t(z)>>(16);
- uint16_t depth = *p;
- switch (c->state.depth_test.func) {
- case GGL_NEVER: goto discard;
- case GGL_LESS: if (zz<depth) break; goto discard;
- case GGL_EQUAL: if (zz==depth) break; goto discard;
- case GGL_LEQUAL: if (zz<=depth) break; goto discard;
- case GGL_GREATER: if (zz>depth) break; goto discard;
- case GGL_NOTEQUAL: if (zz!=depth) break; goto discard;
- case GGL_GEQUAL: if (zz>=depth) break; goto discard;
- }
- // depth buffer is not enabled, if depth-test is not enabled
-/*
- fragment.s[1] = fragment.s[2] =
- fragment.s[3] = fragment.s[0] = 8;
- fragment.c[1] =
- fragment.c[2] =
- fragment.c[3] =
- fragment.c[0] = 255 - (zz>>8);
-*/
- if (c->state.mask.depth) {
- *p = zz;
- }
- }
- }
-
- // fog
- if (enables & GGL_ENABLE_FOG) {
- for (int i=1 ; i<=3 ; i++) {
- GGLfixed fc = (c->state.fog.color[i] * 0x10000) / 0xFF;
- uint32_t& c = fragment.c[i];
- uint8_t& s = fragment.s[i];
- c = (c * 0x10000) / ((1<<s)-1);
- c = gglMulAddx(c, f, gglMulx(fc, 0x10000 - f));
- s = 16;
- }
- }
-
- // blending
- if (enables & GGL_ENABLE_BLENDING) {
- fb.c[1] = fb.c[2] = fb.c[3] = fb.c[0] = 0; // placate valgrind
- fb.s[1] = fb.s[2] = fb.s[3] = fb.s[0] = 0;
- c->state.buffers.color.read(
- &(c->state.buffers.color), c, x, y, &fb);
- blending( c, &fragment, &fb );
- }
-
- // write
- c->state.buffers.color.write(
- &(c->state.buffers.color), c, x, y, &fragment);
- }
-
-discard:
- // iterate...
- x += 1;
- if (enables & GGL_ENABLE_SMOOTH) {
- r += c->shade.drdx;
- g += c->shade.dgdx;
- b += c->shade.dbdx;
- a += c->shade.dadx;
- }
- z += c->shade.dzdx;
- f += c->shade.dfdx;
- }
-}
-
-#endif // ANDROID_ARM_CODEGEN && (ANDROID_CODEGEN == ANDROID_CODEGEN_GENERATED)
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Scanline
-#endif
-
-/* Used to parse a 32-bit source texture linearly. Usage is:
- *
- * horz_iterator32 hi(context);
- * while (...) {
- * uint32_t src_pixel = hi.get_pixel32();
- * ...
- * }
- *
- * Use only for one-to-one texture mapping.
- */
-struct horz_iterator32 {
- explicit horz_iterator32(context_t* c) {
- const int x = c->iterators.xl;
- const int y = c->iterators.y;
- texture_t& tx = c->state.texture[0];
- const int32_t u = (tx.shade.is0>>16) + x;
- const int32_t v = (tx.shade.it0>>16) + y;
- m_src = reinterpret_cast<uint32_t*>(tx.surface.data)+(u+(tx.surface.stride*v));
- }
- uint32_t get_pixel32() {
- return *m_src++;
- }
-protected:
- uint32_t* m_src;
-};
-
-/* A variant for 16-bit source textures. */
-struct horz_iterator16 {
- explicit horz_iterator16(context_t* c) {
- const int x = c->iterators.xl;
- const int y = c->iterators.y;
- texture_t& tx = c->state.texture[0];
- const int32_t u = (tx.shade.is0>>16) + x;
- const int32_t v = (tx.shade.it0>>16) + y;
- m_src = reinterpret_cast<uint16_t*>(tx.surface.data)+(u+(tx.surface.stride*v));
- }
- uint16_t get_pixel16() {
- return *m_src++;
- }
-protected:
- uint16_t* m_src;
-};
-
-/* A clamp iterator is used to iterate inside a texture with GGL_CLAMP.
- * After initialization, call get_src16() or get_src32() to get the current
- * texture pixel value.
- */
-struct clamp_iterator {
- explicit clamp_iterator(context_t* c) {
- const int xs = c->iterators.xl;
- texture_t& tx = c->state.texture[0];
- texture_iterators_t& ti = tx.iterators;
- m_s = (xs * ti.dsdx) + ti.ydsdy;
- m_t = (xs * ti.dtdx) + ti.ydtdy;
- m_ds = ti.dsdx;
- m_dt = ti.dtdx;
- m_width_m1 = tx.surface.width - 1;
- m_height_m1 = tx.surface.height - 1;
- m_data = tx.surface.data;
- m_stride = tx.surface.stride;
- }
- uint16_t get_pixel16() {
- int u, v;
- get_uv(u, v);
- uint16_t* src = reinterpret_cast<uint16_t*>(m_data) + (u + (m_stride*v));
- return src[0];
- }
- uint32_t get_pixel32() {
- int u, v;
- get_uv(u, v);
- uint32_t* src = reinterpret_cast<uint32_t*>(m_data) + (u + (m_stride*v));
- return src[0];
- }
-private:
- void get_uv(int& u, int& v) {
- int uu = m_s >> 16;
- int vv = m_t >> 16;
- if (uu < 0)
- uu = 0;
- if (uu > m_width_m1)
- uu = m_width_m1;
- if (vv < 0)
- vv = 0;
- if (vv > m_height_m1)
- vv = m_height_m1;
- u = uu;
- v = vv;
- m_s += m_ds;
- m_t += m_dt;
- }
-
- GGLfixed m_s, m_t;
- GGLfixed m_ds, m_dt;
- int m_width_m1, m_height_m1;
- uint8_t* m_data;
- int m_stride;
-};
-
-/*
- * The 'horizontal clamp iterator' variant corresponds to the case where
- * the 'v' coordinate doesn't change. This is useful to avoid one mult and
- * extra adds / checks per pixels, if the blending/processing operation after
- * this is very fast.
- */
-static int is_context_horizontal(const context_t* c) {
- return (c->state.texture[0].iterators.dtdx == 0);
-}
-
-struct horz_clamp_iterator {
- uint16_t get_pixel16() {
- int u = m_s >> 16;
- m_s += m_ds;
- if (u < 0)
- u = 0;
- if (u > m_width_m1)
- u = m_width_m1;
- const uint16_t* src = reinterpret_cast<const uint16_t*>(m_data);
- return src[u];
- }
- uint32_t get_pixel32() {
- int u = m_s >> 16;
- m_s += m_ds;
- if (u < 0)
- u = 0;
- if (u > m_width_m1)
- u = m_width_m1;
- const uint32_t* src = reinterpret_cast<const uint32_t*>(m_data);
- return src[u];
- }
-protected:
- void init(const context_t* c, int shift);
- GGLfixed m_s;
- GGLfixed m_ds;
- int m_width_m1;
- const uint8_t* m_data;
-};
-
-void horz_clamp_iterator::init(const context_t* c, int shift)
-{
- const int xs = c->iterators.xl;
- const texture_t& tx = c->state.texture[0];
- const texture_iterators_t& ti = tx.iterators;
- m_s = (xs * ti.dsdx) + ti.ydsdy;
- m_ds = ti.dsdx;
- m_width_m1 = tx.surface.width-1;
- m_data = tx.surface.data;
-
- GGLfixed t = (xs * ti.dtdx) + ti.ydtdy;
- int v = t >> 16;
- if (v < 0)
- v = 0;
- else if (v >= (int)tx.surface.height)
- v = (int)tx.surface.height-1;
-
- m_data += (tx.surface.stride*v) << shift;
-}
-
-struct horz_clamp_iterator16 : horz_clamp_iterator {
- explicit horz_clamp_iterator16(const context_t* c) {
- init(c,1);
- };
-};
-
-struct horz_clamp_iterator32 : horz_clamp_iterator {
- explicit horz_clamp_iterator32(context_t* c) {
- init(c,2);
- };
-};
-
-/* This is used to perform dithering operations.
- */
-struct ditherer {
- explicit ditherer(const context_t* c) {
- const int x = c->iterators.xl;
- const int y = c->iterators.y;
- m_line = &c->ditherMatrix[ ((y & GGL_DITHER_MASK)<<GGL_DITHER_ORDER_SHIFT) ];
- m_index = x & GGL_DITHER_MASK;
- }
- void step(void) {
- m_index++;
- }
- int get_value(void) {
- int ret = m_line[m_index & GGL_DITHER_MASK];
- m_index++;
- return ret;
- }
- uint16_t abgr8888ToRgb565(uint32_t s) {
- uint32_t r = s & 0xff;
- uint32_t g = (s >> 8) & 0xff;
- uint32_t b = (s >> 16) & 0xff;
- return rgb888ToRgb565(r,g,b);
- }
- /* The following assumes that r/g/b are in the 0..255 range each */
- uint16_t rgb888ToRgb565(uint32_t& r, uint32_t& g, uint32_t &b) {
- int threshold = get_value();
- /* dither in on GGL_DITHER_BITS, and each of r, g, b is on 8 bits */
- r += (threshold >> (GGL_DITHER_BITS-8 +5));
- g += (threshold >> (GGL_DITHER_BITS-8 +6));
- b += (threshold >> (GGL_DITHER_BITS-8 +5));
- if (r > 0xff)
- r = 0xff;
- if (g > 0xff)
- g = 0xff;
- if (b > 0xff)
- b = 0xff;
- return uint16_t(((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3));
- }
-protected:
- const uint8_t* m_line;
- int m_index;
-};
-
-/* This structure is used to blend (SRC_OVER) 32-bit source pixels
- * onto 16-bit destination ones. Usage is simply:
- *
- * blender.blend(<32-bit-src-pixel-value>,<ptr-to-16-bit-dest-pixel>)
- */
-struct blender_32to16 {
- explicit blender_32to16(context_t* /*c*/) { }
- void write(uint32_t s, uint16_t* dst) {
- if (s == 0)
- return;
- s = GGL_RGBA_TO_HOST(s);
- int sA = (s>>24);
- if (sA == 0xff) {
- *dst = convertAbgr8888ToRgb565(s);
- } else {
- int f = 0x100 - (sA + (sA>>7));
- int sR = (s >> ( 3))&0x1F;
- int sG = (s >> ( 8+2))&0x3F;
- int sB = (s >> (16+3))&0x1F;
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR += (f*dR)>>8;
- sG += (f*dG)>>8;
- sB += (f*dB)>>8;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
- }
- void write(uint32_t s, uint16_t* dst, ditherer& di) {
- if (s == 0) {
- di.step();
- return;
- }
- s = GGL_RGBA_TO_HOST(s);
- int sA = (s>>24);
- if (sA == 0xff) {
- *dst = di.abgr8888ToRgb565(s);
- } else {
- int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
- int f = 0x100 - (sA + (sA>>7));
- int sR = (s >> ( 3))&0x1F;
- int sG = (s >> ( 8+2))&0x3F;
- int sB = (s >> (16+3))&0x1F;
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR = ((sR << 8) + f*dR + threshold)>>8;
- sG = ((sG << 8) + f*dG + threshold)>>8;
- sB = ((sB << 8) + f*dB + threshold)>>8;
- if (sR > 0x1f) sR = 0x1f;
- if (sG > 0x3f) sG = 0x3f;
- if (sB > 0x1f) sB = 0x1f;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
- }
-};
-
-/* This blender does the same for the 'blend_srca' operation.
- * where dstFactor=srcA*(1-srcA) srcFactor=srcA
- */
-struct blender_32to16_srcA {
- explicit blender_32to16_srcA(const context_t* /*c*/) { }
- void write(uint32_t s, uint16_t* dst) {
- if (!s) {
- return;
- }
- uint16_t d = *dst;
- s = GGL_RGBA_TO_HOST(s);
- int sR = (s >> ( 3))&0x1F;
- int sG = (s >> ( 8+2))&0x3F;
- int sB = (s >> (16+3))&0x1F;
- int sA = (s>>24);
- int f1 = (sA + (sA>>7));
- int f2 = 0x100-f1;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR = (f1*sR + f2*dR)>>8;
- sG = (f1*sG + f2*dG)>>8;
- sB = (f1*sB + f2*dB)>>8;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
-};
-
-/* Common init code the modulating blenders */
-struct blender_modulate {
- void init(const context_t* c) {
- const int r = c->iterators.ydrdy >> (GGL_COLOR_BITS-8);
- const int g = c->iterators.ydgdy >> (GGL_COLOR_BITS-8);
- const int b = c->iterators.ydbdy >> (GGL_COLOR_BITS-8);
- const int a = c->iterators.ydady >> (GGL_COLOR_BITS-8);
- m_r = r + (r >> 7);
- m_g = g + (g >> 7);
- m_b = b + (b >> 7);
- m_a = a + (a >> 7);
- }
-protected:
- int m_r, m_g, m_b, m_a;
-};
-
-/* This blender does a normal blend after modulation.
- */
-struct blender_32to16_modulate : blender_modulate {
- explicit blender_32to16_modulate(const context_t* c) {
- init(c);
- }
- void write(uint32_t s, uint16_t* dst) {
- // blend source and destination
- if (!s) {
- return;
- }
- s = GGL_RGBA_TO_HOST(s);
-
- /* We need to modulate s */
- uint32_t sA = (s >> 24);
- uint32_t sB = (s >> 16) & 0xff;
- uint32_t sG = (s >> 8) & 0xff;
- uint32_t sR = s & 0xff;
-
- sA = (sA*m_a) >> 8;
- /* Keep R/G/B scaled to 5.8 or 6.8 fixed float format */
- sR = (sR*m_r) >> (8 - 5);
- sG = (sG*m_g) >> (8 - 6);
- sB = (sB*m_b) >> (8 - 5);
-
- /* Now do a normal blend */
- int f = 0x100 - (sA + (sA>>7));
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR = (sR + f*dR)>>8;
- sG = (sG + f*dG)>>8;
- sB = (sB + f*dB)>>8;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
- void write(uint32_t s, uint16_t* dst, ditherer& di) {
- // blend source and destination
- if (!s) {
- di.step();
- return;
- }
- s = GGL_RGBA_TO_HOST(s);
-
- /* We need to modulate s */
- uint32_t sA = (s >> 24);
- uint32_t sB = (s >> 16) & 0xff;
- uint32_t sG = (s >> 8) & 0xff;
- uint32_t sR = s & 0xff;
-
- sA = (sA*m_a) >> 8;
- /* keep R/G/B scaled to 5.8 or 6.8 fixed float format */
- sR = (sR*m_r) >> (8 - 5);
- sG = (sG*m_g) >> (8 - 6);
- sB = (sB*m_b) >> (8 - 5);
-
- /* Scale threshold to 0.8 fixed float format */
- int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
- int f = 0x100 - (sA + (sA>>7));
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR = (sR + f*dR + threshold)>>8;
- sG = (sG + f*dG + threshold)>>8;
- sB = (sB + f*dB + threshold)>>8;
- if (sR > 0x1f) sR = 0x1f;
- if (sG > 0x3f) sG = 0x3f;
- if (sB > 0x1f) sB = 0x1f;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
-};
-
-/* same as 32to16_modulate, except that the input is xRGB, instead of ARGB */
-struct blender_x32to16_modulate : blender_modulate {
- explicit blender_x32to16_modulate(const context_t* c) {
- init(c);
- }
- void write(uint32_t s, uint16_t* dst) {
- s = GGL_RGBA_TO_HOST(s);
-
- uint32_t sB = (s >> 16) & 0xff;
- uint32_t sG = (s >> 8) & 0xff;
- uint32_t sR = s & 0xff;
-
- /* Keep R/G/B in 5.8 or 6.8 format */
- sR = (sR*m_r) >> (8 - 5);
- sG = (sG*m_g) >> (8 - 6);
- sB = (sB*m_b) >> (8 - 5);
-
- int f = 0x100 - m_a;
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR = (sR + f*dR)>>8;
- sG = (sG + f*dG)>>8;
- sB = (sB + f*dB)>>8;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
- void write(uint32_t s, uint16_t* dst, ditherer& di) {
- s = GGL_RGBA_TO_HOST(s);
-
- uint32_t sB = (s >> 16) & 0xff;
- uint32_t sG = (s >> 8) & 0xff;
- uint32_t sR = s & 0xff;
-
- sR = (sR*m_r) >> (8 - 5);
- sG = (sG*m_g) >> (8 - 6);
- sB = (sB*m_b) >> (8 - 5);
-
- /* Now do a normal blend */
- int threshold = di.get_value() << (8 - GGL_DITHER_BITS);
- int f = 0x100 - m_a;
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR = (sR + f*dR + threshold)>>8;
- sG = (sG + f*dG + threshold)>>8;
- sB = (sB + f*dB + threshold)>>8;
- if (sR > 0x1f) sR = 0x1f;
- if (sG > 0x3f) sG = 0x3f;
- if (sB > 0x1f) sB = 0x1f;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
-};
-
-/* Same as above, but source is 16bit rgb565 */
-struct blender_16to16_modulate : blender_modulate {
- explicit blender_16to16_modulate(const context_t* c) {
- init(c);
- }
- void write(uint16_t s16, uint16_t* dst) {
- uint32_t s = s16;
-
- uint32_t sR = s >> 11;
- uint32_t sG = (s >> 5) & 0x3f;
- uint32_t sB = s & 0x1f;
-
- sR = (sR*m_r);
- sG = (sG*m_g);
- sB = (sB*m_b);
-
- int f = 0x100 - m_a;
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- sR = (sR + f*dR)>>8;
- sG = (sG + f*dG)>>8;
- sB = (sB + f*dB)>>8;
- *dst = uint16_t((sR<<11)|(sG<<5)|sB);
- }
-};
-
-/* This is used to iterate over a 16-bit destination color buffer.
- * Usage is:
- *
- * dst_iterator16 di(context);
- * while (di.count--) {
- * <do stuff with dest pixel at di.dst>
- * di.dst++;
- * }
- */
-struct dst_iterator16 {
- explicit dst_iterator16(const context_t* c) {
- const int x = c->iterators.xl;
- const int width = c->iterators.xr - x;
- const int32_t y = c->iterators.y;
- const surface_t* cb = &(c->state.buffers.color);
- count = width;
- dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
- }
- int count;
- uint16_t* dst;
-};
-
-
-static void scanline_t32cb16_clamp(context_t* c)
-{
- dst_iterator16 di(c);
-
- if (is_context_horizontal(c)) {
- /* Special case for simple horizontal scaling */
- horz_clamp_iterator32 ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- *di.dst++ = convertAbgr8888ToRgb565(s);
- }
- } else {
- /* General case */
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- *di.dst++ = convertAbgr8888ToRgb565(s);
- }
- }
-}
-
-static void scanline_t32cb16_dither(context_t* c)
-{
- horz_iterator32 si(c);
- dst_iterator16 di(c);
- ditherer dither(c);
-
- while (di.count--) {
- uint32_t s = si.get_pixel32();
- *di.dst++ = dither.abgr8888ToRgb565(s);
- }
-}
-
-static void scanline_t32cb16_clamp_dither(context_t* c)
-{
- dst_iterator16 di(c);
- ditherer dither(c);
-
- if (is_context_horizontal(c)) {
- /* Special case for simple horizontal scaling */
- horz_clamp_iterator32 ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- *di.dst++ = dither.abgr8888ToRgb565(s);
- }
- } else {
- /* General case */
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- *di.dst++ = dither.abgr8888ToRgb565(s);
- }
- }
-}
-
-static void scanline_t32cb16blend_dither(context_t* c)
-{
- dst_iterator16 di(c);
- ditherer dither(c);
- blender_32to16 bl(c);
- horz_iterator32 hi(c);
- while (di.count--) {
- uint32_t s = hi.get_pixel32();
- bl.write(s, di.dst, dither);
- di.dst++;
- }
-}
-
-static void scanline_t32cb16blend_clamp(context_t* c)
-{
- dst_iterator16 di(c);
- blender_32to16 bl(c);
-
- if (is_context_horizontal(c)) {
- horz_clamp_iterator32 ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- bl.write(s, di.dst);
- di.dst++;
- }
- } else {
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- bl.write(s, di.dst);
- di.dst++;
- }
- }
-}
-
-static void scanline_t32cb16blend_clamp_dither(context_t* c)
-{
- dst_iterator16 di(c);
- ditherer dither(c);
- blender_32to16 bl(c);
-
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- bl.write(s, di.dst, dither);
- di.dst++;
- }
-}
-
-void scanline_t32cb16blend_clamp_mod(context_t* c)
-{
- dst_iterator16 di(c);
- blender_32to16_modulate bl(c);
-
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- bl.write(s, di.dst);
- di.dst++;
- }
-}
-
-void scanline_t32cb16blend_clamp_mod_dither(context_t* c)
-{
- dst_iterator16 di(c);
- blender_32to16_modulate bl(c);
- ditherer dither(c);
-
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- bl.write(s, di.dst, dither);
- di.dst++;
- }
-}
-
-/* Variant of scanline_t32cb16blend_clamp_mod with a xRGB texture */
-void scanline_x32cb16blend_clamp_mod(context_t* c)
-{
- dst_iterator16 di(c);
- blender_x32to16_modulate bl(c);
-
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- bl.write(s, di.dst);
- di.dst++;
- }
-}
-
-void scanline_x32cb16blend_clamp_mod_dither(context_t* c)
-{
- dst_iterator16 di(c);
- blender_x32to16_modulate bl(c);
- ditherer dither(c);
-
- clamp_iterator ci(c);
- while (di.count--) {
- uint32_t s = ci.get_pixel32();
- bl.write(s, di.dst, dither);
- di.dst++;
- }
-}
-
-void scanline_t16cb16_clamp(context_t* c)
-{
- dst_iterator16 di(c);
-
- /* Special case for simple horizontal scaling */
- if (is_context_horizontal(c)) {
- horz_clamp_iterator16 ci(c);
- while (di.count--) {
- *di.dst++ = ci.get_pixel16();
- }
- } else {
- clamp_iterator ci(c);
- while (di.count--) {
- *di.dst++ = ci.get_pixel16();
- }
- }
-}
-
-
-
-template <typename T, typename U>
-static inline __attribute__((const))
-T interpolate(int y, T v0, U dvdx, U dvdy) {
- // interpolates in pixel's centers
- // v = v0 + (y + 0.5) * dvdy + (0.5 * dvdx)
- return (y * dvdy) + (v0 + ((dvdy + dvdx) >> 1));
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void init_y(context_t* c, int32_t ys)
-{
- const uint32_t enables = c->state.enables;
-
- // compute iterators...
- iterators_t& ci = c->iterators;
-
- // sample in the center
- ci.y = ys;
-
- if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_W|GGL_ENABLE_FOG)) {
- ci.ydzdy = interpolate(ys, c->shade.z0, c->shade.dzdx, c->shade.dzdy);
- ci.ydwdy = interpolate(ys, c->shade.w0, c->shade.dwdx, c->shade.dwdy);
- ci.ydfdy = interpolate(ys, c->shade.f0, c->shade.dfdx, c->shade.dfdy);
- }
-
- if (ggl_unlikely(enables & GGL_ENABLE_SMOOTH)) {
- ci.ydrdy = interpolate(ys, c->shade.r0, c->shade.drdx, c->shade.drdy);
- ci.ydgdy = interpolate(ys, c->shade.g0, c->shade.dgdx, c->shade.dgdy);
- ci.ydbdy = interpolate(ys, c->shade.b0, c->shade.dbdx, c->shade.dbdy);
- ci.ydady = interpolate(ys, c->shade.a0, c->shade.dadx, c->shade.dady);
- c->step_y = step_y__smooth;
- } else {
- ci.ydrdy = c->shade.r0;
- ci.ydgdy = c->shade.g0;
- ci.ydbdy = c->shade.b0;
- ci.ydady = c->shade.a0;
- // XXX: do only if needed, or make sure this is fast
- c->packed = ggl_pack_color(c, c->state.buffers.color.format,
- ci.ydrdy, ci.ydgdy, ci.ydbdy, ci.ydady);
- c->packed8888 = ggl_pack_color(c, GGL_PIXEL_FORMAT_RGBA_8888,
- ci.ydrdy, ci.ydgdy, ci.ydbdy, ci.ydady);
- }
-
- // initialize the variables we need in the shader
- generated_vars_t& gen = c->generated_vars;
- gen.argb[GGLFormat::ALPHA].c = ci.ydady;
- gen.argb[GGLFormat::ALPHA].dx = c->shade.dadx;
- gen.argb[GGLFormat::RED ].c = ci.ydrdy;
- gen.argb[GGLFormat::RED ].dx = c->shade.drdx;
- gen.argb[GGLFormat::GREEN].c = ci.ydgdy;
- gen.argb[GGLFormat::GREEN].dx = c->shade.dgdx;
- gen.argb[GGLFormat::BLUE ].c = ci.ydbdy;
- gen.argb[GGLFormat::BLUE ].dx = c->shade.dbdx;
- gen.dzdx = c->shade.dzdx;
- gen.f = ci.ydfdy;
- gen.dfdx = c->shade.dfdx;
-
- if (enables & GGL_ENABLE_TMUS) {
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- texture_t& t = c->state.texture[i];
- if (!t.enable) continue;
-
- texture_iterators_t& ti = t.iterators;
- if (t.s_coord == GGL_ONE_TO_ONE && t.t_coord == GGL_ONE_TO_ONE) {
- // we need to set all of these to 0 because in some cases
- // step_y__generic() or step_y__tmu() will be used and
- // therefore will update dtdy, however, in 1:1 mode
- // this is always done by the scanline rasterizer.
- ti.dsdx = ti.dsdy = ti.dtdx = ti.dtdy = 0;
- ti.ydsdy = t.shade.is0;
- ti.ydtdy = t.shade.it0;
- } else {
- const int adjustSWrap = ((t.s_wrap==GGL_CLAMP)?0:16);
- const int adjustTWrap = ((t.t_wrap==GGL_CLAMP)?0:16);
- ti.sscale = t.shade.sscale + adjustSWrap;
- ti.tscale = t.shade.tscale + adjustTWrap;
- if (!(enables & GGL_ENABLE_W)) {
- // S coordinate
- const int32_t sscale = ti.sscale;
- const int32_t sy = interpolate(ys,
- t.shade.is0, t.shade.idsdx, t.shade.idsdy);
- if (sscale>=0) {
- ti.ydsdy= sy << sscale;
- ti.dsdx = t.shade.idsdx << sscale;
- ti.dsdy = t.shade.idsdy << sscale;
- } else {
- ti.ydsdy= sy >> -sscale;
- ti.dsdx = t.shade.idsdx >> -sscale;
- ti.dsdy = t.shade.idsdy >> -sscale;
- }
- // T coordinate
- const int32_t tscale = ti.tscale;
- const int32_t ty = interpolate(ys,
- t.shade.it0, t.shade.idtdx, t.shade.idtdy);
- if (tscale>=0) {
- ti.ydtdy= ty << tscale;
- ti.dtdx = t.shade.idtdx << tscale;
- ti.dtdy = t.shade.idtdy << tscale;
- } else {
- ti.ydtdy= ty >> -tscale;
- ti.dtdx = t.shade.idtdx >> -tscale;
- ti.dtdy = t.shade.idtdy >> -tscale;
- }
- }
- }
- // mirror for generated code...
- generated_tex_vars_t& gen = c->generated_vars.texture[i];
- gen.width = t.surface.width;
- gen.height = t.surface.height;
- gen.stride = t.surface.stride;
- gen.data = uintptr_t(t.surface.data);
- gen.dsdx = ti.dsdx;
- gen.dtdx = ti.dtdx;
- }
- }
-
- // choose the y-stepper
- c->step_y = step_y__nop;
- if (enables & GGL_ENABLE_FOG) {
- c->step_y = step_y__generic;
- } else if (enables & GGL_ENABLE_TMUS) {
- if (enables & GGL_ENABLE_SMOOTH) {
- c->step_y = step_y__generic;
- } else if (enables & GGL_ENABLE_W) {
- c->step_y = step_y__w;
- } else {
- c->step_y = step_y__tmu;
- }
- } else {
- if (enables & GGL_ENABLE_SMOOTH) {
- c->step_y = step_y__smooth;
- }
- }
-
- // choose the rectangle blitter
- c->rect = rect_generic;
- if ((c->step_y == step_y__nop) &&
- (c->scanline == scanline_memcpy))
- {
- c->rect = rect_memcpy;
- }
-}
-
-void init_y_packed(context_t* c, int32_t y0)
-{
- uint8_t f = c->state.buffers.color.format;
- c->packed = ggl_pack_color(c, f,
- c->shade.r0, c->shade.g0, c->shade.b0, c->shade.a0);
- c->packed8888 = ggl_pack_color(c, GGL_PIXEL_FORMAT_RGBA_8888,
- c->shade.r0, c->shade.g0, c->shade.b0, c->shade.a0);
- c->iterators.y = y0;
- c->step_y = step_y__nop;
- // choose the rectangle blitter
- c->rect = rect_generic;
- if (c->scanline == scanline_memcpy) {
- c->rect = rect_memcpy;
- }
-}
-
-void init_y_noop(context_t* c, int32_t y0)
-{
- c->iterators.y = y0;
- c->step_y = step_y__nop;
- // choose the rectangle blitter
- c->rect = rect_generic;
- if (c->scanline == scanline_memcpy) {
- c->rect = rect_memcpy;
- }
-}
-
-void init_y_error(context_t* c, int32_t y0)
-{
- // woooops, shoud never happen,
- // fail gracefully (don't display anything)
- init_y_noop(c, y0);
- ALOGE("color-buffer has an invalid format!");
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void step_y__generic(context_t* c)
-{
- const uint32_t enables = c->state.enables;
-
- // iterate...
- iterators_t& ci = c->iterators;
- ci.y += 1;
-
- if (enables & GGL_ENABLE_SMOOTH) {
- ci.ydrdy += c->shade.drdy;
- ci.ydgdy += c->shade.dgdy;
- ci.ydbdy += c->shade.dbdy;
- ci.ydady += c->shade.dady;
- }
-
- const uint32_t mask =
- GGL_ENABLE_DEPTH_TEST |
- GGL_ENABLE_W |
- GGL_ENABLE_FOG;
- if (enables & mask) {
- ci.ydzdy += c->shade.dzdy;
- ci.ydwdy += c->shade.dwdy;
- ci.ydfdy += c->shade.dfdy;
- }
-
- if ((enables & GGL_ENABLE_TMUS) && (!(enables & GGL_ENABLE_W))) {
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- if (c->state.texture[i].enable) {
- texture_iterators_t& ti = c->state.texture[i].iterators;
- ti.ydsdy += ti.dsdy;
- ti.ydtdy += ti.dtdy;
- }
- }
- }
-}
-
-void step_y__nop(context_t* c)
-{
- c->iterators.y += 1;
- c->iterators.ydzdy += c->shade.dzdy;
-}
-
-void step_y__smooth(context_t* c)
-{
- iterators_t& ci = c->iterators;
- ci.y += 1;
- ci.ydrdy += c->shade.drdy;
- ci.ydgdy += c->shade.dgdy;
- ci.ydbdy += c->shade.dbdy;
- ci.ydady += c->shade.dady;
- ci.ydzdy += c->shade.dzdy;
-}
-
-void step_y__w(context_t* c)
-{
- iterators_t& ci = c->iterators;
- ci.y += 1;
- ci.ydzdy += c->shade.dzdy;
- ci.ydwdy += c->shade.dwdy;
-}
-
-void step_y__tmu(context_t* c)
-{
- iterators_t& ci = c->iterators;
- ci.y += 1;
- ci.ydzdy += c->shade.dzdy;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- if (c->state.texture[i].enable) {
- texture_iterators_t& ti = c->state.texture[i].iterators;
- ti.ydsdy += ti.dsdy;
- ti.ydtdy += ti.dtdy;
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void scanline_perspective(context_t* c)
-{
- struct {
- union {
- struct {
- int32_t s, sq;
- int32_t t, tq;
- } sqtq;
- struct {
- int32_t v, q;
- } st[2];
- };
- } tc[GGL_TEXTURE_UNIT_COUNT] __attribute__((aligned(16)));
-
- // XXX: we should have a special case when dwdx = 0
-
- // 32 pixels spans works okay. 16 is a lot better,
- // but hey, it's a software renderer...
- const uint32_t SPAN_BITS = 5;
- const uint32_t ys = c->iterators.y;
- const uint32_t xs = c->iterators.xl;
- const uint32_t x1 = c->iterators.xr;
- const uint32_t xc = x1 - xs;
- uint32_t remainder = xc & ((1<<SPAN_BITS)-1);
- uint32_t numSpans = xc >> SPAN_BITS;
-
- const iterators_t& ci = c->iterators;
- int32_t w0 = (xs * c->shade.dwdx) + ci.ydwdy;
- int32_t q0 = gglRecipQ(w0, 30);
- const int iwscale = 32 - gglClz(q0);
-
- const int32_t dwdx = c->shade.dwdx << SPAN_BITS;
- int32_t xl = c->iterators.xl;
-
- // We process s & t with a loop to reduce the code size
- // (and i-cache pressure).
-
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- const texture_t& tmu = c->state.texture[i];
- if (!tmu.enable) continue;
- int32_t s = tmu.shade.is0 +
- (tmu.shade.idsdy * ys) + (tmu.shade.idsdx * xs) +
- ((tmu.shade.idsdx + tmu.shade.idsdy)>>1);
- int32_t t = tmu.shade.it0 +
- (tmu.shade.idtdy * ys) + (tmu.shade.idtdx * xs) +
- ((tmu.shade.idtdx + tmu.shade.idtdy)>>1);
- tc[i].sqtq.s = s;
- tc[i].sqtq.t = t;
- tc[i].sqtq.sq = gglMulx(s, q0, iwscale);
- tc[i].sqtq.tq = gglMulx(t, q0, iwscale);
- }
-
- int32_t span = 0;
- do {
- int32_t w1;
- if (ggl_likely(numSpans)) {
- w1 = w0 + dwdx;
- } else {
- if (remainder) {
- // finish off the scanline...
- span = remainder;
- w1 = (c->shade.dwdx * span) + w0;
- } else {
- break;
- }
- }
- int32_t q1 = gglRecipQ(w1, 30);
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; ++i) {
- texture_t& tmu = c->state.texture[i];
- if (!tmu.enable) continue;
- texture_iterators_t& ti = tmu.iterators;
-
- for (int j=0 ; j<2 ; j++) {
- int32_t v = tc[i].st[j].v;
- if (span) v += (tmu.shade.st[j].dx)*span;
- else v += (tmu.shade.st[j].dx)<<SPAN_BITS;
- const int32_t v0 = tc[i].st[j].q;
- const int32_t v1 = gglMulx(v, q1, iwscale);
- int32_t dvdx = v1 - v0;
- if (span) dvdx /= span;
- else dvdx >>= SPAN_BITS;
- tc[i].st[j].v = v;
- tc[i].st[j].q = v1;
-
- const int scale = ti.st[j].scale + (iwscale - 30);
- if (scale >= 0) {
- ti.st[j].ydvdy = v0 << scale;
- ti.st[j].dvdx = dvdx << scale;
- } else {
- ti.st[j].ydvdy = v0 >> -scale;
- ti.st[j].dvdx = dvdx >> -scale;
- }
- }
- generated_tex_vars_t& gen = c->generated_vars.texture[i];
- gen.dsdx = ti.st[0].dvdx;
- gen.dtdx = ti.st[1].dvdx;
- }
- c->iterators.xl = xl;
- c->iterators.xr = xl = xl + (span ? span : (1<<SPAN_BITS));
- w0 = w1;
- q0 = q1;
- c->span(c);
- } while(numSpans--);
-}
-
-void scanline_perspective_single(context_t* c)
-{
- // 32 pixels spans works okay. 16 is a lot better,
- // but hey, it's a software renderer...
- const uint32_t SPAN_BITS = 5;
- const uint32_t ys = c->iterators.y;
- const uint32_t xs = c->iterators.xl;
- const uint32_t x1 = c->iterators.xr;
- const uint32_t xc = x1 - xs;
-
- const iterators_t& ci = c->iterators;
- int32_t w = (xs * c->shade.dwdx) + ci.ydwdy;
- int32_t iw = gglRecipQ(w, 30);
- const int iwscale = 32 - gglClz(iw);
-
- const int i = 31 - gglClz(c->state.enabled_tmu);
- generated_tex_vars_t& gen = c->generated_vars.texture[i];
- texture_t& tmu = c->state.texture[i];
- texture_iterators_t& ti = tmu.iterators;
- const int sscale = ti.sscale + (iwscale - 30);
- const int tscale = ti.tscale + (iwscale - 30);
- int32_t s = tmu.shade.is0 +
- (tmu.shade.idsdy * ys) + (tmu.shade.idsdx * xs) +
- ((tmu.shade.idsdx + tmu.shade.idsdy)>>1);
- int32_t t = tmu.shade.it0 +
- (tmu.shade.idtdy * ys) + (tmu.shade.idtdx * xs) +
- ((tmu.shade.idtdx + tmu.shade.idtdy)>>1);
- int32_t s0 = gglMulx(s, iw, iwscale);
- int32_t t0 = gglMulx(t, iw, iwscale);
- int32_t xl = c->iterators.xl;
-
- int32_t sq, tq, dsdx, dtdx;
- int32_t premainder = xc & ((1<<SPAN_BITS)-1);
- uint32_t numSpans = xc >> SPAN_BITS;
- if (c->shade.dwdx == 0) {
- // XXX: we could choose to do this if the error is small enough
- numSpans = 0;
- premainder = xc;
- goto no_perspective;
- }
-
- if (premainder) {
- w += c->shade.dwdx * premainder;
- iw = gglRecipQ(w, 30);
-no_perspective:
- s += tmu.shade.idsdx * premainder;
- t += tmu.shade.idtdx * premainder;
- sq = gglMulx(s, iw, iwscale);
- tq = gglMulx(t, iw, iwscale);
- dsdx = (sq - s0) / premainder;
- dtdx = (tq - t0) / premainder;
- c->iterators.xl = xl;
- c->iterators.xr = xl = xl + premainder;
- goto finish;
- }
-
- while (numSpans--) {
- w += c->shade.dwdx << SPAN_BITS;
- s += tmu.shade.idsdx << SPAN_BITS;
- t += tmu.shade.idtdx << SPAN_BITS;
- iw = gglRecipQ(w, 30);
- sq = gglMulx(s, iw, iwscale);
- tq = gglMulx(t, iw, iwscale);
- dsdx = (sq - s0) >> SPAN_BITS;
- dtdx = (tq - t0) >> SPAN_BITS;
- c->iterators.xl = xl;
- c->iterators.xr = xl = xl + (1<<SPAN_BITS);
-finish:
- if (sscale >= 0) {
- ti.ydsdy = s0 << sscale;
- ti.dsdx = dsdx << sscale;
- } else {
- ti.ydsdy = s0 >>-sscale;
- ti.dsdx = dsdx >>-sscale;
- }
- if (tscale >= 0) {
- ti.ydtdy = t0 << tscale;
- ti.dtdx = dtdx << tscale;
- } else {
- ti.ydtdy = t0 >>-tscale;
- ti.dtdx = dtdx >>-tscale;
- }
- s0 = sq;
- t0 = tq;
- gen.dsdx = ti.dsdx;
- gen.dtdx = ti.dtdx;
- c->span(c);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-void scanline_col32cb16blend(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- union {
- uint16_t* dst;
- uint32_t* dst32;
- };
- dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__arm__))
-#if defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN
- scanline_col32cb16blend_neon(dst, &(c->packed8888), ct);
-#else // defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN
- scanline_col32cb16blend_arm(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
-#endif // defined(__ARM_HAVE_NEON) && BYTE_ORDER == LITTLE_ENDIAN
-#elif ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && defined(__aarch64__))
- scanline_col32cb16blend_arm64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
-#elif ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__mips__) && defined(__LP64__)))
- scanline_col32cb16blend_mips64(dst, GGL_RGBA_TO_HOST(c->packed8888), ct);
-#else
- uint32_t s = GGL_RGBA_TO_HOST(c->packed8888);
- int sA = (s>>24);
- int f = 0x100 - (sA + (sA>>7));
- while (ct--) {
- uint16_t d = *dst;
- int dR = (d>>11)&0x1f;
- int dG = (d>>5)&0x3f;
- int dB = (d)&0x1f;
- int sR = (s >> ( 3))&0x1F;
- int sG = (s >> ( 8+2))&0x3F;
- int sB = (s >> (16+3))&0x1F;
- sR += (f*dR)>>8;
- sG += (f*dG)>>8;
- sB += (f*dB)>>8;
- *dst++ = uint16_t((sR<<11)|(sG<<5)|sB);
- }
-#endif
-
-}
-
-void scanline_t32cb16(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- union {
- uint16_t* dst;
- uint32_t* dst32;
- };
- dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-
- surface_t* tex = &(c->state.texture[0].surface);
- const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
- const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
- uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
- uint32_t s, d;
-
- if (ct==1 || uintptr_t(dst)&2) {
-last_one:
- s = GGL_RGBA_TO_HOST( *src++ );
- *dst++ = convertAbgr8888ToRgb565(s);
- ct--;
- }
-
- while (ct >= 2) {
-#if BYTE_ORDER == BIG_ENDIAN
- s = GGL_RGBA_TO_HOST( *src++ );
- d = convertAbgr8888ToRgb565_hi16(s);
-
- s = GGL_RGBA_TO_HOST( *src++ );
- d |= convertAbgr8888ToRgb565(s);
-#else
- s = GGL_RGBA_TO_HOST( *src++ );
- d = convertAbgr8888ToRgb565(s);
-
- s = GGL_RGBA_TO_HOST( *src++ );
- d |= convertAbgr8888ToRgb565(s) << 16;
-#endif
- *dst32++ = d;
- ct -= 2;
- }
-
- if (ct > 0) {
- goto last_one;
- }
-}
-
-void scanline_t32cb16blend(context_t* c)
-{
-#if ((ANDROID_CODEGEN >= ANDROID_CODEGEN_ASM) && (defined(__arm__) || defined(__aarch64__) || \
- (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || defined(__LP64__)))))
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- uint16_t* dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
-
- surface_t* tex = &(c->state.texture[0].surface);
- const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
- const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
- uint32_t *src = reinterpret_cast<uint32_t*>(tex->data)+(u+(tex->stride*v));
-
-#ifdef __arm__
- scanline_t32cb16blend_arm(dst, src, ct);
-#elif defined(__aarch64__)
- scanline_t32cb16blend_arm64(dst, src, ct);
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
- scanline_t32cb16blend_mips(dst, src, ct);
-#elif defined(__mips__) && defined(__LP64__)
- scanline_t32cb16blend_mips64(dst, src, ct);
-#endif
-#else
- dst_iterator16 di(c);
- horz_iterator32 hi(c);
- blender_32to16 bl(c);
- while (di.count--) {
- uint32_t s = hi.get_pixel32();
- bl.write(s, di.dst);
- di.dst++;
- }
-#endif
-}
-
-void scanline_t32cb16blend_srca(context_t* c)
-{
- dst_iterator16 di(c);
- horz_iterator32 hi(c);
- blender_32to16_srcA blender(c);
-
- while (di.count--) {
- uint32_t s = hi.get_pixel32();
- blender.write(s,di.dst);
- di.dst++;
- }
-}
-
-void scanline_t16cb16blend_clamp_mod(context_t* c)
-{
- const int a = c->iterators.ydady >> (GGL_COLOR_BITS-8);
- if (a == 0) {
- return;
- }
-
- if (a == 255) {
- scanline_t16cb16_clamp(c);
- return;
- }
-
- dst_iterator16 di(c);
- blender_16to16_modulate blender(c);
- clamp_iterator ci(c);
-
- while (di.count--) {
- uint16_t s = ci.get_pixel16();
- blender.write(s, di.dst);
- di.dst++;
- }
-}
-
-void scanline_memcpy(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- const GGLFormat* fp = &(c->formats[cb->format]);
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
- (x + (cb->stride * y)) * fp->size;
-
- surface_t* tex = &(c->state.texture[0].surface);
- const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
- const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
- uint8_t *src = reinterpret_cast<uint8_t*>(tex->data) +
- (u + (tex->stride * v)) * fp->size;
-
- const size_t size = ct * fp->size;
- memcpy(dst, src, size);
-}
-
-void scanline_memset8(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) + (x+(cb->stride*y));
- uint32_t packed = c->packed;
- memset(dst, packed, ct);
-}
-
-void scanline_memset16(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- uint16_t* dst = reinterpret_cast<uint16_t*>(cb->data) + (x+(cb->stride*y));
- uint32_t packed = c->packed;
- android_memset16(dst, packed, ct*2);
-}
-
-void scanline_memset32(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- uint32_t* dst = reinterpret_cast<uint32_t*>(cb->data) + (x+(cb->stride*y));
- uint32_t packed = GGL_HOST_TO_RGBA(c->packed);
- android_memset32(dst, packed, ct*4);
-}
-
-void scanline_clear(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- const GGLFormat* fp = &(c->formats[cb->format]);
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
- (x + (cb->stride * y)) * fp->size;
- const size_t size = ct * fp->size;
- memset(dst, 0, size);
-}
-
-void scanline_set(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- const GGLFormat* fp = &(c->formats[cb->format]);
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
- (x + (cb->stride * y)) * fp->size;
- const size_t size = ct * fp->size;
- memset(dst, 0xFF, size);
-}
-
-void scanline_noop(context_t* /*c*/)
-{
-}
-
-void rect_generic(context_t* c, size_t yc)
-{
- do {
- c->scanline(c);
- c->step_y(c);
- } while (--yc);
-}
-
-void rect_memcpy(context_t* c, size_t yc)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- const GGLFormat* fp = &(c->formats[cb->format]);
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
- (x + (cb->stride * y)) * fp->size;
-
- surface_t* tex = &(c->state.texture[0].surface);
- const int32_t u = (c->state.texture[0].shade.is0>>16) + x;
- const int32_t v = (c->state.texture[0].shade.it0>>16) + y;
- uint8_t *src = reinterpret_cast<uint8_t*>(tex->data) +
- (u + (tex->stride * v)) * fp->size;
-
- if (cb->stride == tex->stride && ct == size_t(cb->stride)) {
- memcpy(dst, src, ct * fp->size * yc);
- } else {
- const size_t size = ct * fp->size;
- const size_t dbpr = cb->stride * fp->size;
- const size_t sbpr = tex->stride * fp->size;
- do {
- memcpy(dst, src, size);
- dst += dbpr;
- src += sbpr;
- } while (--yc);
- }
-}
-// ----------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/libpixelflinger/scanline.h b/libpixelflinger/scanline.h
deleted file mode 100644
index b6f4d37..0000000
--- a/libpixelflinger/scanline.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* libs/pixelflinger/scanline.h
-**
-** Copyright 2006, 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 ANDROID_SCANLINE_H
-#define ANDROID_SCANLINE_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_scanline(context_t* c);
-void ggl_uninit_scanline(context_t* c);
-void ggl_pick_scanline(context_t* c);
-
-}; // namespace android
-
-#endif
diff --git a/libpixelflinger/t32cb16blend.S b/libpixelflinger/t32cb16blend.S
deleted file mode 100644
index 5e4995a..0000000
--- a/libpixelflinger/t32cb16blend.S
+++ /dev/null
@@ -1,203 +0,0 @@
-/* libs/pixelflinger/t32cb16blend.S
-**
-** Copyright 2006, 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.
-*/
-
-
- .text
- .syntax unified
- .balign 4
-
- .global scanline_t32cb16blend_arm
-
-
-/*
- * .macro pixel
- *
- * \DREG is a 32-bit register containing *two* original destination RGB565
- * pixels, with the even one in the low-16 bits, and the odd one in the
- * high 16 bits.
- *
- * \SRC is a 32-bit 0xAABBGGRR pixel value, with pre-multiplied colors.
- *
- * \FB is a target register that will contain the blended pixel values.
- *
- * \ODD is either 0 or 1 and indicates if we're blending the lower or
- * upper 16-bit pixels in DREG into FB
- *
- *
- * clobbered: r6, r7, lr
- *
- */
-
-.macro pixel, DREG, SRC, FB, ODD
-
- // SRC = 0xAABBGGRR
- mov r7, \SRC, lsr #24 // sA
- add r7, r7, r7, lsr #7 // sA + (sA >> 7)
- rsb r7, r7, #0x100 // sA = 0x100 - (sA+(sA>>7))
-
-1:
-
-.if \ODD
-
- // red
- mov lr, \DREG, lsr #(16 + 11)
- smulbb lr, r7, lr
- mov r6, \SRC, lsr #3
- and r6, r6, #0x1F
- add lr, r6, lr, lsr #8
- cmp lr, #0x1F
- orrhs \FB, \FB, #(0x1F<<(16 + 11))
- orrlo \FB, \FB, lr, lsl #(16 + 11)
-
- // green
- and r6, \DREG, #(0x3F<<(16 + 5))
- smulbt r6, r7, r6
- mov lr, \SRC, lsr #(8+2)
- and lr, lr, #0x3F
- add r6, lr, r6, lsr #(5+8)
- cmp r6, #0x3F
- orrhs \FB, \FB, #(0x3F<<(16 + 5))
- orrlo \FB, \FB, r6, lsl #(16 + 5)
-
- // blue
- and lr, \DREG, #(0x1F << 16)
- smulbt lr, r7, lr
- mov r6, \SRC, lsr #(8+8+3)
- and r6, r6, #0x1F
- add lr, r6, lr, lsr #8
- cmp lr, #0x1F
- orrhs \FB, \FB, #(0x1F << 16)
- orrlo \FB, \FB, lr, lsl #16
-
-.else
-
- // red
- mov lr, \DREG, lsr #11
- and lr, lr, #0x1F
- smulbb lr, r7, lr
- mov r6, \SRC, lsr #3
- and r6, r6, #0x1F
- add lr, r6, lr, lsr #8
- cmp lr, #0x1F
- movhs \FB, #(0x1F<<11)
- movlo \FB, lr, lsl #11
-
-
- // green
- and r6, \DREG, #(0x3F<<5)
- smulbb r6, r7, r6
- mov lr, \SRC, lsr #(8+2)
- and lr, lr, #0x3F
- add r6, lr, r6, lsr #(5+8)
- cmp r6, #0x3F
- orrhs \FB, \FB, #(0x3F<<5)
- orrlo \FB, \FB, r6, lsl #5
-
- // blue
- and lr, \DREG, #0x1F
- smulbb lr, r7, lr
- mov r6, \SRC, lsr #(8+8+3)
- and r6, r6, #0x1F
- add lr, r6, lr, lsr #8
- cmp lr, #0x1F
- orrhs \FB, \FB, #0x1F
- orrlo \FB, \FB, lr
-
-.endif
-
- .endm
-
-
-// r0: dst ptr
-// r1: src ptr
-// r2: count
-// r3: d
-// r4: s0
-// r5: s1
-// r6: pixel
-// r7: pixel
-// r8: free
-// r9: free
-// r10: free
-// r11: free
-// r12: scratch
-// r14: pixel
-
-scanline_t32cb16blend_arm:
- stmfd sp!, {r4-r7, lr}
-
- pld [r0]
- pld [r1]
-
- // align DST to 32 bits
- tst r0, #0x3
- beq aligned
- subs r2, r2, #1
- ldmfdlo sp!, {r4-r7, lr} // return
- bxlo lr
-
-last:
- ldr r4, [r1], #4
- ldrh r3, [r0]
- pixel r3, r4, r12, 0
- strh r12, [r0], #2
-
-aligned:
- subs r2, r2, #2
- blo 9f
-
- // The main loop is unrolled twice and processes 4 pixels
-8: ldmia r1!, {r4, r5}
- // stream the source
- pld [r1, #32]
- add r0, r0, #4
- // it's all zero, skip this pixel
- orrs r3, r4, r5
- beq 7f
-
- // load the destination
- ldr r3, [r0, #-4]
- // stream the destination
- pld [r0, #32]
- pixel r3, r4, r12, 0
- pixel r3, r5, r12, 1
- // effectively, we're getting write-combining by virtue of the
- // cpu's write-back cache.
- str r12, [r0, #-4]
-
- // 2nd iterration of the loop, don't stream anything
- subs r2, r2, #2
- movlt r4, r5
- blt 9f
- ldmia r1!, {r4, r5}
- add r0, r0, #4
- orrs r3, r4, r5
- beq 7f
- ldr r3, [r0, #-4]
- pixel r3, r4, r12, 0
- pixel r3, r5, r12, 16
- str r12, [r0, #-4]
-
-
-7: subs r2, r2, #2
- bhs 8b
- mov r4, r5
-
-9: adds r2, r2, #1
- ldmfdlo sp!, {r4-r7, lr} // return
- bxlo lr
- b last
diff --git a/libpixelflinger/tests/Android.bp b/libpixelflinger/tests/Android.bp
deleted file mode 100644
index e20dd93..0000000
--- a/libpixelflinger/tests/Android.bp
+++ /dev/null
@@ -1,17 +0,0 @@
-cc_defaults {
- name: "pixelflinger-tests",
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- header_libs: ["libpixelflinger_internal"],
- static_libs: [
- "libbase",
- "libcutils",
- "liblog",
- "libpixelflinger",
- "libutils",
- ],
-}
diff --git a/libpixelflinger/tests/arch-arm64/Android.bp b/libpixelflinger/tests/arch-arm64/Android.bp
deleted file mode 100644
index 2f5586a..0000000
--- a/libpixelflinger/tests/arch-arm64/Android.bp
+++ /dev/null
@@ -1,11 +0,0 @@
-cc_defaults {
- name: "pixelflinger-tests-arm64",
- defaults: ["pixelflinger-tests"],
-
- enabled: false,
- arch: {
- arm64: {
- enabled: true,
- },
- },
-}
diff --git a/libpixelflinger/tests/arch-arm64/assembler/Android.bp b/libpixelflinger/tests/arch-arm64/assembler/Android.bp
deleted file mode 100644
index 003f485..0000000
--- a/libpixelflinger/tests/arch-arm64/assembler/Android.bp
+++ /dev/null
@@ -1,9 +0,0 @@
-cc_test {
- name: "test-pixelflinger-arm64-assembler-test",
- defaults: ["pixelflinger-tests-arm64"],
-
- srcs: [
- "arm64_assembler_test.cpp",
- "asm_test_jacket.S",
- ],
-}
diff --git a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp b/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
deleted file mode 100644
index 63642c4..0000000
--- a/libpixelflinger/tests/arch-arm64/assembler/arm64_assembler_test.cpp
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <sys/mman.h>
-#include <cutils/ashmem.h>
-
-#define __STDC_FORMAT_MACROS
-#include <inttypes.h>
-
-#include "codeflinger/ARMAssemblerInterface.h"
-#include "codeflinger/Arm64Assembler.h"
-using namespace android;
-
-#define TESTS_DATAOP_ENABLE 1
-#define TESTS_DATATRANSFER_ENABLE 1
-#define TESTS_LDMSTM_ENABLE 1
-#define TESTS_REG_CORRUPTION_ENABLE 0
-
-void *instrMem;
-uint32_t instrMemSize = 128 * 1024;
-char dataMem[8192];
-
-typedef void (*asm_function_t)();
-extern "C" void asm_test_jacket(asm_function_t function,
- int64_t regs[], int32_t flags[]);
-
-#define MAX_32BIT (uint32_t)(((uint64_t)1 << 32) - 1)
-const uint32_t NA = 0;
-const uint32_t NUM_REGS = 32;
-const uint32_t NUM_FLAGS = 16;
-
-enum instr_t
-{
- INSTR_ADD,
- INSTR_SUB,
- INSTR_AND,
- INSTR_ORR,
- INSTR_RSB,
- INSTR_BIC,
- INSTR_CMP,
- INSTR_MOV,
- INSTR_MVN,
- INSTR_MUL,
- INSTR_MLA,
- INSTR_SMULBB,
- INSTR_SMULBT,
- INSTR_SMULTB,
- INSTR_SMULTT,
- INSTR_SMULWB,
- INSTR_SMULWT,
- INSTR_SMLABB,
- INSTR_UXTB16,
- INSTR_UBFX,
- INSTR_ADDR_ADD,
- INSTR_ADDR_SUB,
- INSTR_LDR,
- INSTR_LDRB,
- INSTR_LDRH,
- INSTR_ADDR_LDR,
- INSTR_LDM,
- INSTR_STR,
- INSTR_STRB,
- INSTR_STRH,
- INSTR_ADDR_STR,
- INSTR_STM
-};
-
-enum shift_t
-{
- SHIFT_LSL,
- SHIFT_LSR,
- SHIFT_ASR,
- SHIFT_ROR,
- SHIFT_NONE
-};
-
-enum offset_t
-{
- REG_SCALE_OFFSET,
- REG_OFFSET,
- IMM8_OFFSET,
- IMM12_OFFSET,
- NO_OFFSET
-};
-
-enum cond_t
-{
- EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV,
- HS = CS,
- LO = CC
-};
-
-const char * cc_code[] =
-{
- "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC",
- "HI", "LS","GE","LT", "GT", "LE", "AL", "NV"
-};
-
-
-struct dataOpTest_t
-{
- uint32_t id;
- instr_t op;
- uint32_t preFlag;
- cond_t cond;
- bool setFlags;
- uint64_t RnValue;
- uint64_t RsValue;
- bool immediate;
- uint32_t immValue;
- uint64_t RmValue;
- uint32_t shiftMode;
- uint32_t shiftAmount;
- uint64_t RdValue;
- bool checkRd;
- uint64_t postRdValue;
- bool checkFlag;
- uint32_t postFlag;
-};
-
-struct dataTransferTest_t
-{
- uint32_t id;
- instr_t op;
- uint32_t preFlag;
- cond_t cond;
- bool setMem;
- uint64_t memOffset;
- uint64_t memValue;
- uint64_t RnValue;
- offset_t offsetType;
- uint64_t RmValue;
- uint32_t immValue;
- bool writeBack;
- bool preIndex;
- bool postIndex;
- uint64_t RdValue;
- uint64_t postRdValue;
- uint64_t postRnValue;
- bool checkMem;
- uint64_t postMemOffset;
- uint32_t postMemLength;
- uint64_t postMemValue;
-};
-
-
-dataOpTest_t dataOpTests [] =
-{
- {0xA000,INSTR_ADD,AL,AL,0,1,NA,1,MAX_32BIT ,NA,NA,NA,NA,1,0,0,0},
- {0xA001,INSTR_ADD,AL,AL,0,1,NA,1,MAX_32BIT -1,NA,NA,NA,NA,1,MAX_32BIT,0,0},
- {0xA002,INSTR_ADD,AL,AL,0,1,NA,0,NA,MAX_32BIT ,NA,NA,NA,1,0,0,0},
- {0xA003,INSTR_ADD,AL,AL,0,1,NA,0,NA,MAX_32BIT -1,NA,NA,NA,1,MAX_32BIT,0,0},
- {0xA004,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,0,NA,1,0,0,0},
- {0xA005,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0x80000001,0,0},
- {0xA006,INSTR_ADD,AL,AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,2,0,0},
- {0xA007,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,2,0,0},
- {0xA008,INSTR_ADD,AL,AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1,0,0},
- {0xA009,INSTR_ADD,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,0,0,0},
- {0xA010,INSTR_AND,AL,AL,0,1,NA,1,MAX_32BIT ,0,0,0,NA,1,1,0,0},
- {0xA011,INSTR_AND,AL,AL,0,1,NA,1,MAX_32BIT -1,0,0,0,NA,1,0,0,0},
- {0xA012,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,0,0,NA,1,1,0,0},
- {0xA013,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT -1,0,0,NA,1,0,0,0},
- {0xA014,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,0,NA,1,1,0,0},
- {0xA015,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0,0,0},
- {0xA016,INSTR_AND,AL,AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1,0,0},
- {0xA017,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,1,0,0},
- {0xA018,INSTR_AND,AL,AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,0,0,0},
- {0xA019,INSTR_AND,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,1,0,0},
- {0xA020,INSTR_ORR,AL,AL,0,3,NA,1,MAX_32BIT ,0,0,0,NA,1,MAX_32BIT,0,0},
- {0xA021,INSTR_ORR,AL,AL,0,2,NA,1,MAX_32BIT -1,0,0,0,NA,1,MAX_32BIT-1,0,0},
- {0xA022,INSTR_ORR,AL,AL,0,3,NA,0,0,MAX_32BIT ,0,0,NA,1,MAX_32BIT,0,0},
- {0xA023,INSTR_ORR,AL,AL,0,2,NA,0,0,MAX_32BIT -1,0,0,NA,1,MAX_32BIT-1,0,0},
- {0xA024,INSTR_ORR,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,0,NA,1,MAX_32BIT,0,0},
- {0xA025,INSTR_ORR,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0x80000001,0,0},
- {0xA026,INSTR_ORR,AL,AL,0,1,NA,0,0,3,SHIFT_LSR,1,NA,1,1,0,0},
- {0xA027,INSTR_ORR,AL,AL,0,0,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,1,0,0},
- {0xA028,INSTR_ORR,AL,AL,0,0,NA,0,0,3,SHIFT_ASR,1,NA,1,1,0,0},
- {0xA029,INSTR_ORR,AL,AL,0,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,MAX_32BIT ,0,0},
- {0xA030,INSTR_CMP,AL,AL,1,0x10000,NA,1,0x10000,0,0,0,NA,0,0,1,HS},
- {0xA031,INSTR_CMP,AL,AL,1,0x00000,NA,1,0x10000,0,0,0,NA,0,0,1,CC},
- {0xA032,INSTR_CMP,AL,AL,1,0x00000,NA,0,0,0x10000,0,0,NA,0,0,1,LT},
- {0xA033,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,0,0,NA,0,0,1,EQ},
- {0xA034,INSTR_CMP,AL,AL,1,0x00000,NA,0,0,0x10000,0,0,NA,0,0,1,LS},
- {0xA035,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,0,0,NA,0,0,1,LS},
- {0xA036,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,0,0,NA,0,0,1,HI},
- {0xA037,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,0,0,NA,0,0,1,HS},
- {0xA038,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,0,0,NA,0,0,1,HS},
- {0xA039,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,0,0,NA,0,0,1,NE},
- {0xA040,INSTR_CMP,AL,AL,1,0,NA,0,0,MAX_32BIT ,SHIFT_LSR,1,NA,0,0,1,LT},
- {0xA041,INSTR_CMP,AL,AL,1,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,0,0,1,EQ},
- {0xA042,INSTR_CMP,AL,AL,1,0,NA,0,0,0x10000,SHIFT_LSR,31,NA,0,0,1,LS},
- {0xA043,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x30000,SHIFT_LSR,1,NA,0,0,1,LS},
- {0xA044,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x00000,SHIFT_LSR,31,NA,0,0,1,HI},
- {0xA045,INSTR_CMP,AL,AL,1,1,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,0,0,1,HS},
- {0xA046,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x2000,SHIFT_LSR,1,NA,0,0,1,HS},
- {0xA047,INSTR_CMP,AL,AL,1,0,NA,0,0,MAX_32BIT ,SHIFT_LSR,1,NA,0,0,1,NE},
- {0xA048,INSTR_CMP,AL,AL,1,0,NA,0,0,0x10000,SHIFT_ASR,2,NA,0,0,1,LT},
- {0xA049,INSTR_CMP,AL,AL,1,MAX_32BIT ,NA,0,0,MAX_32BIT ,SHIFT_ASR,1,NA,0,0,1,EQ},
- {0xA050,INSTR_CMP,AL,AL,1,MAX_32BIT ,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,0,0,1,LS},
- {0xA051,INSTR_CMP,AL,AL,1,0,NA,0,0,0x10000,SHIFT_ASR,1,NA,0,0,1,LS},
- {0xA052,INSTR_CMP,AL,AL,1,0x10000,NA,0,0,0x10000,SHIFT_ASR,1,NA,0,0,1,HI},
- {0xA053,INSTR_CMP,AL,AL,1,1,NA,0,0,0x10000,SHIFT_ASR,31,NA,0,0,1,HS},
- {0xA054,INSTR_CMP,AL,AL,1,1,NA,0,0,0x10000,SHIFT_ASR,16,NA,0,0,1,HS},
- {0xA055,INSTR_CMP,AL,AL,1,1,NA,0,0,MAX_32BIT ,SHIFT_ASR,1,NA,0,0,1,NE},
- {0xA056,INSTR_MUL,AL,AL,0,0,0x10000,0,0,0x10000,0,0,NA,1,0,0,0},
- {0xA057,INSTR_MUL,AL,AL,0,0,0x1000,0,0,0x10000,0,0,NA,1,0x10000000,0,0},
- {0xA058,INSTR_MUL,AL,AL,0,0,MAX_32BIT ,0,0,1,0,0,NA,1,MAX_32BIT ,0,0},
- {0xA059,INSTR_MLA,AL,AL,0,0x10000,0x10000,0,0,0x10000,0,0,NA,1,0x10000,0,0},
- {0xA060,INSTR_MLA,AL,AL,0,0x10000,0x1000,0,0,0x10000,0,0,NA,1,0x10010000,0,0},
- {0xA061,INSTR_MLA,AL,AL,1,1,MAX_32BIT ,0,0,1,0,0,NA,1,0,1,PL},
- {0xA062,INSTR_MLA,AL,AL,1,0,MAX_32BIT ,0,0,1,0,0,NA,1,MAX_32BIT ,1,MI},
- {0xA063,INSTR_SUB,AL,AL,1,1 << 16,NA,1,1 << 16,NA,NA,NA,NA,1,0,1,PL},
- {0xA064,INSTR_SUB,AL,AL,1,(1 << 16) + 1,NA,1,1 << 16,NA,NA,NA,NA,1,1,1,PL},
- {0xA065,INSTR_SUB,AL,AL,1,0,NA,1,1 << 16,NA,NA,NA,NA,1,(uint32_t)(0 - (1<<16)),1,MI},
- {0xA066,INSTR_SUB,MI,MI,0,2,NA,0,NA,1,NA,NA,2,1,1,0,NA},
- {0xA067,INSTR_SUB,EQ,MI,0,2,NA,0,NA,1,NA,NA,2,1,2,0,NA},
- {0xA068,INSTR_SUB,GT,GE,0,2,NA,1,1,NA,NA,NA,2,1,1,0,NA},
- {0xA069,INSTR_SUB,LT,GE,0,2,NA,1,1,NA,NA,NA,2,1,2,0,NA},
- {0xA070,INSTR_SUB,CS,HS,0,2,NA,1,1,NA,NA,NA,2,1,1,0,NA},
- {0xA071,INSTR_SUB,CC,HS,0,2,NA,1,1,NA,NA,NA,2,1,2,0,NA},
- {0xA072,INSTR_SUB,AL,AL,0,1,NA,1,1 << 16,0,0,0,NA,1,(uint32_t)(1 - (1 << 16)),0,NA},
- {0xA073,INSTR_SUB,AL,AL,0,MAX_32BIT,NA,1,1,0,0,0,NA,1,MAX_32BIT - 1,0,NA},
- {0xA074,INSTR_SUB,AL,AL,0,1,NA,1,1,0,0,0,NA,1,0,0,NA},
- {0xA075,INSTR_SUB,AL,AL,0,1,NA,0,NA,1 << 16,0,0,NA,1,(uint32_t)(1 - (1 << 16)),0,NA},
- {0xA076,INSTR_SUB,AL,AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,MAX_32BIT - 1,0,NA},
- {0xA077,INSTR_SUB,AL,AL,0,1,NA,0,NA,1,0,0,NA,1,0,0,NA},
- {0xA078,INSTR_SUB,AL,AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(uint32_t)(1 - (1 << 16)),0,NA},
- {0xA079,INSTR_SUB,AL,AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,1,0,NA},
- {0xA080,INSTR_SUB,AL,AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0,0,NA},
- {0xA081,INSTR_SUB,AL,AL,0,1,NA,0,NA,MAX_32BIT ,SHIFT_LSR,31,NA,1,0,0,NA},
- {0xA082,INSTR_RSB,GT,GE,0,2,NA,1,0,NA,NA,NA,2,1,(uint32_t)-2,0,NA},
- {0xA083,INSTR_RSB,LT,GE,0,2,NA,1,0,NA,NA,NA,2,1,2,0,NA},
- {0xA084,INSTR_RSB,AL,AL,0,1,NA,1,1 << 16,NA,NA,NA,NA,1,(1 << 16) - 1,0,NA},
- {0xA085,INSTR_RSB,AL,AL,0,MAX_32BIT,NA,1,1,NA,NA,NA,NA,1,(uint32_t) (1 - MAX_32BIT),0,NA},
- {0xA086,INSTR_RSB,AL,AL,0,1,NA,1,1,NA,NA,NA,NA,1,0,0,NA},
- {0xA087,INSTR_RSB,AL,AL,0,1,NA,0,NA,1 << 16,0,0,NA,1,(1 << 16) - 1,0,NA},
- {0xA088,INSTR_RSB,AL,AL,0,MAX_32BIT,NA,0,NA,1,0,0,NA,1,(uint32_t) (1 - MAX_32BIT),0,NA},
- {0xA089,INSTR_RSB,AL,AL,0,1,NA,0,NA,1,0,0,NA,1,0,0,NA},
- {0xA090,INSTR_RSB,AL,AL,0,1,NA,0,NA,1,SHIFT_LSL,16,NA,1,(1 << 16) - 1,0,NA},
- {0xA091,INSTR_RSB,AL,AL,0,0x80000001,NA,0,NA,MAX_32BIT ,SHIFT_LSL,31,NA,1,(uint32_t)-1,0,NA},
- {0xA092,INSTR_RSB,AL,AL,0,1,NA,0,NA,3,SHIFT_LSR,1,NA,1,0,0,NA},
- {0xA093,INSTR_RSB,AL,AL,0,1,NA,0,NA,MAX_32BIT ,SHIFT_LSR,31,NA,1,0,0,NA},
- {0xA094,INSTR_MOV,AL,AL,0,NA,NA,1,0x80000001,NA,NA,NA,NA,1,0x80000001,0,0},
- {0xA095,INSTR_MOV,AL,AL,0,NA,NA,0,0,0x80000001,0,0,NA,1,0x80000001,0,0},
- {0xA096,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,NA,1,MAX_32BIT -1,0,0},
- {0xA097,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,NA,1,0x80000000,0,0},
- {0xA098,INSTR_MOV,AL,AL,0,NA,NA,0,0,3,SHIFT_LSR,1,NA,1,1,0,0},
- {0xA099,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSR,31,NA,1,1,0,0},
- {0xA100,INSTR_MOV,AL,AL,0,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1,0,0},
- {0xA101,INSTR_MOV,AL,AL,0,NA,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,MAX_32BIT ,0,0},
- {0xA102,INSTR_MOV,AL,AL,0,NA,NA,0,0,3,SHIFT_ROR,1,NA,1,0x80000001,0,0},
- {0xA103,INSTR_MOV,AL,AL,0,NA,NA,0,0,0x80000001,SHIFT_ROR,31,NA,1,3,0,0},
- {0xA104,INSTR_MOV,AL,AL,1,NA,NA,0,0,MAX_32BIT -1,SHIFT_ASR,1,NA,1,MAX_32BIT,1,MI},
- {0xA105,INSTR_MOV,AL,AL,1,NA,NA,0,0,3,SHIFT_ASR,1,NA,1,1,1,PL},
- {0xA106,INSTR_MOV,PL,MI,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
- {0xA107,INSTR_MOV,MI,MI,0,NA,NA,0,0,0x80000001,0,0,2,1,0x80000001,0,0},
- {0xA108,INSTR_MOV,EQ,LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
- {0xA109,INSTR_MOV,LT,LT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
- {0xA110,INSTR_MOV,GT,GE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,MAX_32BIT -1,0,0},
- {0xA111,INSTR_MOV,EQ,GE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,2,1,0x80000000,0,0},
- {0xA112,INSTR_MOV,LT,GE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,2,1,2,0,0},
- {0xA113,INSTR_MOV,GT,LE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2,0,0},
- {0xA114,INSTR_MOV,EQ,LE,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
- {0xA115,INSTR_MOV,LT,LE,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,31,2,1,0x80000000,0,0},
- {0xA116,INSTR_MOV,EQ,GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
- {0xA117,INSTR_MOV,GT,GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
- {0xA118,INSTR_MOV,LE,GT,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
- {0xA119,INSTR_MOV,EQ,GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2,0,0},
- {0xA120,INSTR_MOV,GT,GT,0,NA,NA,0,0,0x80000001,0,0,2,1,0x80000001,0,0},
- {0xA121,INSTR_MOV,LE,GT,0,NA,NA,0,0,0x80000001,0,0,2,1,2,0,0},
- {0xA122,INSTR_MOV,EQ,GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2,0,0},
- {0xA123,INSTR_MOV,GT,GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,MAX_32BIT -1,0,0},
- {0xA124,INSTR_MOV,LE,GT,0,NA,NA,0,0,MAX_32BIT ,SHIFT_LSL,1,2,1,2,0,0},
- {0xA125,INSTR_MOV,LO,HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,2,0,0},
- {0xA126,INSTR_MOV,HS,HS,0,NA,NA,1,0x80000001,NA,NA,NA,2,1,0x80000001,0,0},
- {0xA127,INSTR_MVN,LO,HS,0,NA,NA,1,MAX_32BIT -1,NA,NA,NA,2,1,2,0,0},
- {0xA128,INSTR_MVN,HS,HS,0,NA,NA,1,MAX_32BIT -1,NA,NA,NA,2,1,1,0,0},
- {0xA129,INSTR_MVN,AL,AL,0,NA,NA,1,0,NA,NA,NA,2,1,MAX_32BIT,0,NA},
- {0xA130,INSTR_MVN,AL,AL,0,NA,NA,0,NA,MAX_32BIT -1,NA,0,2,1,1,0,NA},
- {0xA131,INSTR_MVN,AL,AL,0,NA,NA,0,NA,0x80000001,NA,0,2,1,0x7FFFFFFE,0,NA},
- {0xA132,INSTR_BIC,AL,AL,0,1,NA,1,MAX_32BIT ,NA,NA,NA,NA,1,0,0,0},
- {0xA133,INSTR_BIC,AL,AL,0,1,NA,1,MAX_32BIT -1,NA,NA,NA,NA,1,1,0,0},
- {0xA134,INSTR_BIC,AL,AL,0,1,NA,0,0,MAX_32BIT ,0,0,NA,1,0,0,0},
- {0xA135,INSTR_BIC,AL,AL,0,1,NA,0,0,MAX_32BIT -1,0,0,NA,1,1,0,0},
- {0xA136,INSTR_BIC,AL,AL,0,0xF0,NA,0,0,3,SHIFT_ASR,1,NA,1,0xF0,0,0},
- {0xA137,INSTR_BIC,AL,AL,0,0xF0,NA,0,0,MAX_32BIT ,SHIFT_ASR,31,NA,1,0,0,0},
- {0xA138,INSTR_SMULBB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xABCD0001,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA139,INSTR_SMULBB,AL,AL,0,NA,0xABCD0001,0,NA,0xABCD0FFF,NA,NA,NA,1,0x00000FFF,0,0},
- {0xA140,INSTR_SMULBB,AL,AL,0,NA,0xABCD0001,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA141,INSTR_SMULBB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xABCDFFFF,NA,NA,NA,1,1,0,0},
- {0xA142,INSTR_SMULBT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xABCD0001,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA143,INSTR_SMULBT,AL,AL,0,NA,0x0001ABCD,0,NA,0xABCD0FFF,NA,NA,NA,1,0x00000FFF,0,0},
- {0xA144,INSTR_SMULBT,AL,AL,0,NA,0x0001ABCD,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA145,INSTR_SMULBT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xABCDFFFF,NA,NA,NA,1,1,0,0},
- {0xA146,INSTR_SMULTB,AL,AL,0,NA,0xABCDFFFF,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA147,INSTR_SMULTB,AL,AL,0,NA,0xABCD0001,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
- {0xA148,INSTR_SMULTB,AL,AL,0,NA,0xABCD0001,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA149,INSTR_SMULTB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xFFFFABCD,NA,NA,NA,1,1,0,0},
- {0xA150,INSTR_SMULTT,AL,AL,0,NA,0xFFFFABCD,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA151,INSTR_SMULTT,AL,AL,0,NA,0x0001ABCD,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
- {0xA152,INSTR_SMULTT,AL,AL,0,NA,0x0001ABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA153,INSTR_SMULTT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,1,0,0},
- {0xA154,INSTR_SMULWB,AL,AL,0,NA,0xABCDFFFF,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFE,0,0},
- {0xA155,INSTR_SMULWB,AL,AL,0,NA,0xABCD0001,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
- {0xA156,INSTR_SMULWB,AL,AL,0,NA,0xABCD0001,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA157,INSTR_SMULWB,AL,AL,0,NA,0xABCDFFFF,0,NA,0xFFFFABCD,NA,NA,NA,1,0,0,0},
- {0xA158,INSTR_SMULWT,AL,AL,0,NA,0xFFFFABCD,0,NA,0x0001ABCD,NA,NA,NA,1,0xFFFFFFFE,0,0},
- {0xA159,INSTR_SMULWT,AL,AL,0,NA,0x0001ABCD,0,NA,0x0FFFABCD,NA,NA,NA,1,0x00000FFF,0,0},
- {0xA160,INSTR_SMULWT,AL,AL,0,NA,0x0001ABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,0xFFFFFFFF,0,0},
- {0xA161,INSTR_SMULWT,AL,AL,0,NA,0xFFFFABCD,0,NA,0xFFFFABCD,NA,NA,NA,1,0,0,0},
- {0xA162,INSTR_SMLABB,AL,AL,0,1,0xABCDFFFF,0,NA,0xABCD0001,NA,NA,NA,1,0,0,0},
- {0xA163,INSTR_SMLABB,AL,AL,0,1,0xABCD0001,0,NA,0xABCD0FFF,NA,NA,NA,1,0x00001000,0,0},
- {0xA164,INSTR_SMLABB,AL,AL,0,0xFFFFFFFF,0xABCD0001,0,NA,0xABCDFFFF,NA,NA,NA,1,0xFFFFFFFE,0,0},
- {0xA165,INSTR_SMLABB,AL,AL,0,0xFFFFFFFF,0xABCDFFFF,0,NA,0xABCDFFFF,NA,NA,NA,1,0,0,0},
- {0xA166,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,0,NA,1,0x00CD0001,0,0},
- {0xA167,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,1,NA,1,0x00AB00EF,0,0},
- {0xA168,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,2,NA,1,0x000100CD,0,0},
- {0xA169,INSTR_UXTB16,AL,AL,0,NA,NA,0,NA,0xABCDEF01,SHIFT_ROR,3,NA,1,0x00EF00AB,0,0},
- {0xA170,INSTR_UBFX,AL,AL,0,0xABCDEF01,4,0,NA,24,NA,NA,NA,1,0x00BCDEF0,0,0},
- {0xA171,INSTR_UBFX,AL,AL,0,0xABCDEF01,1,0,NA,2,NA,NA,NA,1,0,0,0},
- {0xA172,INSTR_UBFX,AL,AL,0,0xABCDEF01,16,0,NA,8,NA,NA,NA,1,0xCD,0,0},
- {0xA173,INSTR_UBFX,AL,AL,0,0xABCDEF01,31,0,NA,1,NA,NA,NA,1,1,0,0},
- {0xA174,INSTR_ADDR_ADD,AL,AL,0,0xCFFFFFFFF,NA,0,NA,0x1,SHIFT_LSL,1,NA,1,0xD00000001,0,0},
- {0xA175,INSTR_ADDR_ADD,AL,AL,0,0x01,NA,0,NA,0x1,SHIFT_LSL,2,NA,1,0x5,0,0},
- {0xA176,INSTR_ADDR_ADD,AL,AL,0,0xCFFFFFFFF,NA,0,NA,0x1,NA,0,NA,1,0xD00000000,0,0},
- {0xA177,INSTR_ADDR_SUB,AL,AL,0,0xD00000001,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,0xCFFFFFFFF,0,0},
- {0xA178,INSTR_ADDR_SUB,AL,AL,0,0xCFFFFFFFF,NA,0,NA,0x020000,SHIFT_LSR,15,NA,1,0xCFFFFFFFB,0,0},
- {0xA179,INSTR_ADDR_SUB,AL,AL,0,3,NA,0,NA,0x010000,SHIFT_LSR,15,NA,1,1,0,0},
-};
-
-dataTransferTest_t dataTransferTests [] =
-{
- {0xB000,INSTR_LDR,AL,AL,1,24,0xABCDEF0123456789,0,REG_SCALE_OFFSET,24,NA,NA,NA,NA,NA,0x23456789,0,0,NA,NA,NA},
- {0xB001,INSTR_LDR,AL,AL,1,4064,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4068,0,1,0,NA,0xABCDEF01,0,0,NA,NA,NA},
- {0xB002,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4,1,0,1,NA,0x23456789,4,0,NA,NA,NA},
- {0xB003,INSTR_LDR,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x23456789,0,0,NA,NA,NA},
- {0xB004,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,REG_SCALE_OFFSET,4064,NA,NA,NA,NA,NA,0x89,0,0,NA,NA,NA},
- {0xB005,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4065,0,1,0,NA,0x67,0,0,NA,NA,NA},
- {0xB006,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,0,0,1,0,NA,0x67,4065,0,NA,NA,NA},
- {0xB007,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,0,1,0,NA,0x45,4065,0,NA,NA,NA},
- {0xB008,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,2,0,1,0,NA,0x23,4065,0,NA,NA,NA},
- {0xB009,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,4065,IMM12_OFFSET,NA,1,1,0,1,NA,0x67,4066,0,NA,NA,NA},
- {0xB010,INSTR_LDRB,AL,AL,1,4064,0xABCDEF0123456789,0,NO_OFFSET,NA,NA,0,0,0,NA,0x89,0,0,NA,NA,NA},
- {0xB011,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,IMM8_OFFSET,NA,2,1,0,1,NA,0x6789,2,0,NA,NA,NA},
- {0xB012,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4064,0,0,1,0,NA,0x6789,0,0,NA,NA,NA},
- {0xB013,INSTR_LDRH,AL,AL,1,4064,0xABCDEF0123456789,0,REG_OFFSET,4066,0,0,1,0,NA,0x2345,0,0,NA,NA,NA},
- {0xB014,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,0,NO_OFFSET,NA,0,0,0,0,NA,0x6789,0,0,NA,NA,NA},
- {0xB015,INSTR_LDRH,AL,AL,1,0,0xABCDEF0123456789,2,NO_OFFSET,NA,0,0,0,0,NA,0x2345,2,0,NA,NA,NA},
- {0xB016,INSTR_ADDR_LDR,AL,AL,1,4064,0xABCDEF0123456789,0,IMM12_OFFSET,NA,4064,0,1,0,NA,0xABCDEF0123456789,0,0,NA,NA,NA},
- {0xB017,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,8,1,2,8,0xDEAD23456789BEEF},
- {0xB018,INSTR_STR,AL,AL,1,2,0xDEADBEEFDEADBEEF,4,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,2,8,0xDEAD23456789BEEF},
- {0xB019,INSTR_STR,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4064,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,4066,8,0xDEAD23456789BEEF},
- {0xB020,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,0,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF},
- {0xB021,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,1,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDE89BEEF},
- {0xB022,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,2,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEF89ADBEEF},
- {0xB023,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,IMM12_OFFSET,NA,4,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,5,1,0,8,0xDEADBEEFDEAD89EF},
- {0xB024,INSTR_STRB,AL,AL,1,0,0xDEADBEEFDEADBEEF,1,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,1,1,0,8,0xDEADBEEFDEAD89EF},
- {0xB025,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,IMM12_OFFSET,NA,2,1,0,1,0xABCDEF0123456789,0xABCDEF0123456789,4072,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB026,INSTR_STRH,AL,AL,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB027,INSTR_STRH,EQ,NE,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
- {0xB028,INSTR_STRH,NE,NE,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB029,INSTR_STRH,NE,EQ,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
- {0xB030,INSTR_STRH,EQ,EQ,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB031,INSTR_STRH,HI,LS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
- {0xB032,INSTR_STRH,LS,LS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB033,INSTR_STRH,LS,HI,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
- {0xB034,INSTR_STRH,HI,HI,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB035,INSTR_STRH,CC,HS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
- {0xB036,INSTR_STRH,CS,HS,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB037,INSTR_STRH,GE,LT,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEADBEEFDEADBEEF},
- {0xB038,INSTR_STRH,LT,LT,1,4066,0xDEADBEEFDEADBEEF,4070,NO_OFFSET,NA,NA,0,0,0,0xABCDEF0123456789,0xABCDEF0123456789,4070,1,4066,8,0xDEAD6789DEADBEEF},
- {0xB039,INSTR_ADDR_STR,AL,AL,1,4064,0xDEADBEEFDEADBEEF,4,IMM12_OFFSET,NA,4060,0,1,0,0xABCDEF0123456789,0xABCDEF0123456789,4,1,4064,8,0xABCDEF0123456789},
-};
-
-
-void flushcache()
-{
- const long base = long(instrMem);
- const long curr = base + long(instrMemSize);
- __builtin___clear_cache((char*)base, (char*)curr);
-}
-void dataOpTest(dataOpTest_t test, ARMAssemblerInterface *a64asm, uint32_t Rd = 0,
- uint32_t Rn = 1, uint32_t Rm = 2, uint32_t Rs = 3)
-{
- int64_t regs[NUM_REGS] = {0};
- int32_t flags[NUM_FLAGS] = {0};
- int64_t savedRegs[NUM_REGS] = {0};
- uint32_t i;
- uint32_t op2;
-
- for(i = 0; i < NUM_REGS; ++i)
- {
- regs[i] = i;
- }
-
- regs[Rd] = test.RdValue;
- regs[Rn] = test.RnValue;
- regs[Rs] = test.RsValue;
- flags[test.preFlag] = 1;
- a64asm->reset();
- a64asm->prolog();
- if(test.immediate == true)
- {
- op2 = a64asm->imm(test.immValue);
- }
- else if(test.immediate == false && test.shiftAmount == 0)
- {
- op2 = Rm;
- regs[Rm] = test.RmValue;
- }
- else
- {
- op2 = a64asm->reg_imm(Rm, test.shiftMode, test.shiftAmount);
- regs[Rm] = test.RmValue;
- }
- switch(test.op)
- {
- case INSTR_ADD: a64asm->ADD(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_SUB: a64asm->SUB(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_RSB: a64asm->RSB(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_AND: a64asm->AND(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_ORR: a64asm->ORR(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_BIC: a64asm->BIC(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_MUL: a64asm->MUL(test.cond, test.setFlags, Rd,Rm,Rs); break;
- case INSTR_MLA: a64asm->MLA(test.cond, test.setFlags, Rd,Rm,Rs,Rn); break;
- case INSTR_CMP: a64asm->CMP(test.cond, Rn,op2); break;
- case INSTR_MOV: a64asm->MOV(test.cond, test.setFlags,Rd,op2); break;
- case INSTR_MVN: a64asm->MVN(test.cond, test.setFlags,Rd,op2); break;
- case INSTR_SMULBB:a64asm->SMULBB(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULBT:a64asm->SMULBT(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULTB:a64asm->SMULTB(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULTT:a64asm->SMULTT(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULWB:a64asm->SMULWB(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMULWT:a64asm->SMULWT(test.cond, Rd,Rm,Rs); break;
- case INSTR_SMLABB:a64asm->SMLABB(test.cond, Rd,Rm,Rs,Rn); break;
- case INSTR_UXTB16:a64asm->UXTB16(test.cond, Rd,Rm,test.shiftAmount); break;
- case INSTR_UBFX:
- {
- int32_t lsb = test.RsValue;
- int32_t width = test.RmValue;
- a64asm->UBFX(test.cond, Rd,Rn,lsb, width);
- break;
- }
- case INSTR_ADDR_ADD: a64asm->ADDR_ADD(test.cond, test.setFlags, Rd,Rn,op2); break;
- case INSTR_ADDR_SUB: a64asm->ADDR_SUB(test.cond, test.setFlags, Rd,Rn,op2); break;
- default: printf("Error"); return;
- }
- a64asm->epilog(0);
- flushcache();
-
- asm_function_t asm_function = (asm_function_t)(instrMem);
-
- for(i = 0; i < NUM_REGS; ++i)
- savedRegs[i] = regs[i];
-
- asm_test_jacket(asm_function, regs, flags);
-
- /* Check if all regs except Rd is same */
- for(i = 0; i < NUM_REGS; ++i)
- {
- if(i == Rd) continue;
- if(regs[i] != savedRegs[i])
- {
- printf("Test %x failed Reg(%d) tampered Expected(0x%" PRIx64 "),"
- "Actual(0x%" PRIx64 ") t\n", test.id, i, savedRegs[i],
- regs[i]);
- return;
- }
- }
-
- if(test.checkRd == 1 && (uint64_t)regs[Rd] != test.postRdValue)
- {
- printf("Test %x failed, Expected(%" PRIx64 "), Actual(%" PRIx64 ")\n",
- test.id, test.postRdValue, regs[Rd]);
- }
- else if(test.checkFlag == 1 && flags[test.postFlag] == 0)
- {
- printf("Test %x failed Flag(%s) NOT set\n",
- test.id,cc_code[test.postFlag]);
- }
- else
- {
- printf("Test %x passed\n", test.id);
- }
-}
-
-
-void dataTransferTest(dataTransferTest_t test, ARMAssemblerInterface *a64asm,
- uint32_t Rd = 0, uint32_t Rn = 1,uint32_t Rm = 2)
-{
- int64_t regs[NUM_REGS] = {0};
- int64_t savedRegs[NUM_REGS] = {0};
- int32_t flags[NUM_FLAGS] = {0};
- uint32_t i;
- for(i = 0; i < NUM_REGS; ++i)
- {
- regs[i] = i;
- }
-
- uint32_t op2;
-
- regs[Rd] = test.RdValue;
- regs[Rn] = (uint64_t)(&dataMem[test.RnValue]);
- regs[Rm] = test.RmValue;
- flags[test.preFlag] = 1;
-
- if(test.setMem == true)
- {
- unsigned char *mem = (unsigned char *)&dataMem[test.memOffset];
- uint64_t value = test.memValue;
- for(int j = 0; j < 8; ++j)
- {
- mem[j] = value & 0x00FF;
- value >>= 8;
- }
- }
- a64asm->reset();
- a64asm->prolog();
- if(test.offsetType == REG_SCALE_OFFSET)
- {
- op2 = a64asm->reg_scale_pre(Rm);
- }
- else if(test.offsetType == REG_OFFSET)
- {
- op2 = a64asm->reg_pre(Rm);
- }
- else if(test.offsetType == IMM12_OFFSET && test.preIndex == true)
- {
- op2 = a64asm->immed12_pre(test.immValue, test.writeBack);
- }
- else if(test.offsetType == IMM12_OFFSET && test.postIndex == true)
- {
- op2 = a64asm->immed12_post(test.immValue);
- }
- else if(test.offsetType == IMM8_OFFSET && test.preIndex == true)
- {
- op2 = a64asm->immed8_pre(test.immValue, test.writeBack);
- }
- else if(test.offsetType == IMM8_OFFSET && test.postIndex == true)
- {
- op2 = a64asm->immed8_post(test.immValue);
- }
- else if(test.offsetType == NO_OFFSET)
- {
- op2 = a64asm->__immed12_pre(0);
- }
- else
- {
- printf("Error - Unknown offset\n"); return;
- }
-
- switch(test.op)
- {
- case INSTR_LDR: a64asm->LDR(test.cond, Rd,Rn,op2); break;
- case INSTR_LDRB: a64asm->LDRB(test.cond, Rd,Rn,op2); break;
- case INSTR_LDRH: a64asm->LDRH(test.cond, Rd,Rn,op2); break;
- case INSTR_ADDR_LDR: a64asm->ADDR_LDR(test.cond, Rd,Rn,op2); break;
- case INSTR_STR: a64asm->STR(test.cond, Rd,Rn,op2); break;
- case INSTR_STRB: a64asm->STRB(test.cond, Rd,Rn,op2); break;
- case INSTR_STRH: a64asm->STRH(test.cond, Rd,Rn,op2); break;
- case INSTR_ADDR_STR: a64asm->ADDR_STR(test.cond, Rd,Rn,op2); break;
- default: printf("Error"); return;
- }
- a64asm->epilog(0);
- flushcache();
-
- asm_function_t asm_function = (asm_function_t)(instrMem);
-
- for(i = 0; i < NUM_REGS; ++i)
- savedRegs[i] = regs[i];
-
-
- asm_test_jacket(asm_function, regs, flags);
-
- /* Check if all regs except Rd/Rn are same */
- for(i = 0; i < NUM_REGS; ++i)
- {
- if(i == Rd || i == Rn) continue;
- if(regs[i] != savedRegs[i])
- {
- printf("Test %x failed Reg(%d) tampered"
- " Expected(0x%" PRIx64 "), Actual(0x%" PRIx64 ") t\n",
- test.id, i, savedRegs[i], regs[i]);
- return;
- }
- }
-
- if((uint64_t)regs[Rd] != test.postRdValue)
- {
- printf("Test %x failed, "
- "Expected in Rd(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
- test.id, test.postRdValue, regs[Rd]);
- }
- else if((uint64_t)regs[Rn] != (uint64_t)(&dataMem[test.postRnValue]))
- {
- printf("Test %x failed, "
- "Expected in Rn(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
- test.id, test.postRnValue, regs[Rn] - (uint64_t)dataMem);
- }
- else if(test.checkMem == true)
- {
- unsigned char *addr = (unsigned char *)&dataMem[test.postMemOffset];
- uint64_t value;
- value = 0;
- for(uint32_t j = 0; j < test.postMemLength; ++j)
- value = (value << 8) | addr[test.postMemLength-j-1];
- if(value != test.postMemValue)
- {
- printf("Test %x failed, "
- "Expected in Mem(0x%" PRIx64 "), Actual(0x%" PRIx64 ")\n",
- test.id, test.postMemValue, value);
- }
- else
- {
- printf("Test %x passed\n", test.id);
- }
- }
- else
- {
- printf("Test %x passed\n", test.id);
- }
-}
-
-void dataTransferLDMSTM(ARMAssemblerInterface *a64asm)
-{
- int64_t regs[NUM_REGS] = {0};
- int32_t flags[NUM_FLAGS] = {0};
- const uint32_t numArmv7Regs = 16;
-
- uint32_t Rn = ARMAssemblerInterface::SP;
-
- uint32_t patterns[] =
- {
- 0x5A03,
- 0x4CF0,
- 0x1EA6,
- 0x0DBF,
- };
-
- uint32_t i, j;
- for(i = 0; i < sizeof(patterns)/sizeof(uint32_t); ++i)
- {
- for(j = 0; j < NUM_REGS; ++j)
- {
- regs[j] = j;
- }
- a64asm->reset();
- a64asm->prolog();
- a64asm->STM(AL,ARMAssemblerInterface::DB,Rn,1,patterns[i]);
- for(j = 0; j < numArmv7Regs; ++j)
- {
- uint32_t op2 = a64asm->imm(0x31);
- a64asm->MOV(AL, 0,j,op2);
- }
- a64asm->LDM(AL,ARMAssemblerInterface::IA,Rn,1,patterns[i]);
- a64asm->epilog(0);
- flushcache();
-
- asm_function_t asm_function = (asm_function_t)(instrMem);
- asm_test_jacket(asm_function, regs, flags);
-
- for(j = 0; j < numArmv7Regs; ++j)
- {
- if((1 << j) & patterns[i])
- {
- if(regs[j] != j)
- {
- printf("LDM/STM Test %x failed "
- "Reg%d expected(0x%x) Actual(0x%" PRIx64 ") \n",
- patterns[i], j, j, regs[j]);
- break;
- }
- }
- }
- if(j == numArmv7Regs)
- printf("LDM/STM Test %x passed\n", patterns[i]);
- }
-}
-
-int main(void)
-{
- uint32_t i;
-
- /* Allocate memory to store instructions generated by ArmToArm64Assembler */
- {
- int fd = ashmem_create_region("code cache", instrMemSize);
- if(fd < 0)
- printf("Creating code cache, ashmem_create_region "
- "failed with error '%s'", strerror(errno));
- instrMem = mmap(NULL, instrMemSize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE, fd, 0);
- }
-
- ArmToArm64Assembler a64asm(instrMem);
-
- if(TESTS_DATAOP_ENABLE)
- {
- printf("Running data processing tests\n");
- for(i = 0; i < sizeof(dataOpTests)/sizeof(dataOpTest_t); ++i)
- dataOpTest(dataOpTests[i], &a64asm);
- }
-
- if(TESTS_DATATRANSFER_ENABLE)
- {
- printf("Running data transfer tests\n");
- for(i = 0; i < sizeof(dataTransferTests)/sizeof(dataTransferTest_t); ++i)
- dataTransferTest(dataTransferTests[i], &a64asm);
- }
-
- if(TESTS_LDMSTM_ENABLE)
- {
- printf("Running LDM/STM tests\n");
- dataTransferLDMSTM(&a64asm);
- }
-
-
- if(TESTS_REG_CORRUPTION_ENABLE)
- {
- uint32_t reg_list[] = {0,1,12,14};
- uint32_t Rd, Rm, Rs, Rn;
- uint32_t i;
- uint32_t numRegs = sizeof(reg_list)/sizeof(uint32_t);
-
- printf("Running Register corruption tests\n");
- for(i = 0; i < sizeof(dataOpTests)/sizeof(dataOpTest_t); ++i)
- {
- for(Rd = 0; Rd < numRegs; ++Rd)
- {
- for(Rn = 0; Rn < numRegs; ++Rn)
- {
- for(Rm = 0; Rm < numRegs; ++Rm)
- {
- for(Rs = 0; Rs < numRegs;++Rs)
- {
- if(Rd == Rn || Rd == Rm || Rd == Rs) continue;
- if(Rn == Rm || Rn == Rs) continue;
- if(Rm == Rs) continue;
- printf("Testing combination Rd(%d), Rn(%d),"
- " Rm(%d), Rs(%d): ",
- reg_list[Rd], reg_list[Rn], reg_list[Rm], reg_list[Rs]);
- dataOpTest(dataOpTests[i], &a64asm, reg_list[Rd],
- reg_list[Rn], reg_list[Rm], reg_list[Rs]);
- }
- }
- }
- }
- }
- }
- return 0;
-}
diff --git a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S b/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
deleted file mode 100644
index 3f900f8..0000000
--- a/libpixelflinger/tests/arch-arm64/assembler/asm_test_jacket.S
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- .text
- .balign 0
-
- .global asm_test_jacket
-
- // Set the register and flag values
- // Calls the asm function
- // Reads the register/flag values to output register
-
- // Parameters
- // X0 - Function to jump
- // X1 - register values array
- // X2 - flag values array
-asm_test_jacket:
- // Save registers to stack
- stp x29, x30, [sp,#-16]!
- stp x27, x28, [sp,#-16]!
-
- mov x30, x0
- mov x28, x1
- mov x27, x2
-
- //Set the flags based on flag array
- //EQ
- ldr w0, [x27,#0]
- cmp w0, #1
- b.ne bt_aeq
- cmp w0,#1
- b bt_end
-bt_aeq:
-
- //NE
- ldr w0, [x27,#4]
- cmp w0, #1
- b.ne bt_ane
- cmp w0,#2
- b bt_end
-bt_ane:
-
- //CS
- ldr w0, [x27,#8]
- cmp w0, #1
- b.ne bt_acs
- cmp w0,#0
- b bt_end
-bt_acs:
-
- //CC
- ldr w0, [x27,#12]
- cmp w0, #1
- b.ne bt_acc
- cmp w0,#2
- b bt_end
-bt_acc:
-
- //MI
- ldr w0, [x27,#16]
- cmp w0, #1
- b.ne bt_ami
- subs w0,w0,#2
- b bt_end
-bt_ami:
-
- //PL
- ldr w0, [x27,#20]
- cmp w0, #1
- b.ne bt_apl
- subs w0,w0,#0
- b bt_end
-bt_apl:
- //HI - (C==1) && (Z==0)
- ldr w0, [x27,#32]
- cmp w0, #1
- b.ne bt_ahi
- cmp w0,#0
- b bt_end
-bt_ahi:
-
- //LS - (C==0) || (Z==1)
- ldr w0, [x27,#36]
- cmp w0, #1
- b.ne bt_als
- cmp w0,#1
- b bt_end
-bt_als:
-
- //GE
- ldr w0, [x27,#40]
- cmp w0, #1
- b.ne bt_age
- cmp w0,#0
- b bt_end
-bt_age:
-
- //LT
- ldr w0, [x27,#44]
- cmp w0, #1
- b.ne bt_alt
- cmp w0,#2
- b bt_end
-bt_alt:
-
- //GT
- ldr w0, [x27,#48]
- cmp w0, #1
- b.ne bt_agt
- cmp w0,#0
- b bt_end
-bt_agt:
-
- //LE
- ldr w0, [x27,#52]
- cmp w0, #1
- b.ne bt_ale
- cmp w0,#2
- b bt_end
-bt_ale:
-
-
-bt_end:
-
- // Load the registers from reg array
- ldr x0, [x28,#0]
- ldr x1, [x28,#8]
- ldr x2, [x28,#16]
- ldr x3, [x28,#24]
- ldr x4, [x28,#32]
- ldr x5, [x28,#40]
- ldr x6, [x28,#48]
- ldr x7, [x28,#56]
- ldr x8, [x28,#64]
- ldr x9, [x28,#72]
- ldr x10, [x28,#80]
- ldr x11, [x28,#88]
- ldr x12, [x28,#96]
- ldr x14, [x28,#112]
-
- // Call the function
- blr X30
-
- // Save the registers to reg array
- str x0, [x28,#0]
- str x1, [x28,#8]
- str x2, [x28,#16]
- str x3, [x28,#24]
- str x4, [x28,#32]
- str x5, [x28,#40]
- str x6, [x28,#48]
- str x7, [x28,#56]
- str x8, [x28,#64]
- str x9, [x28,#72]
- str x10, [x28,#80]
- str x11, [x28,#88]
- str x12, [x28,#96]
- str x14, [x28,#112]
-
- //Set the flags array based on result flags
- movz w0, #0
- movz w1, #1
- csel w2, w1, w0, EQ
- str w2, [x27,#0]
- csel w2, w1, w0, NE
- str w2, [x27,#4]
- csel w2, w1, w0, CS
- str w2, [x27,#8]
- csel w2, w1, w0, CC
- str w2, [x27,#12]
- csel w2, w1, w0, MI
- str w2, [x27,#16]
- csel w2, w1, w0, PL
- str w2, [x27,#20]
- csel w2, w1, w0, VS
- str w2, [x27,#24]
- csel w2, w1, w0, VC
- str w2, [x27,#28]
- csel w2, w1, w0, HI
- str w2, [x27,#32]
- csel w2, w1, w0, LS
- str w2, [x27,#36]
- csel w2, w1, w0, GE
- str w2, [x27,#40]
- csel w2, w1, w0, LT
- str w2, [x27,#44]
- csel w2, w1, w0, GT
- str w2, [x27,#48]
- csel w2, w1, w0, LE
- str w2, [x27,#52]
-
- // Restore registers from stack
- ldp x27, x28, [sp],#16
- ldp x29, x30, [sp],#16
- ret
-
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp b/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp
deleted file mode 100644
index e640aeb..0000000
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
- name: "test-pixelflinger-arm64-col32cb16blend",
- defaults: ["pixelflinger-tests-arm64"],
-
- srcs: ["col32cb16blend_test.c"],
-}
diff --git a/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c b/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c
deleted file mode 100644
index c6a3017..0000000
--- a/libpixelflinger/tests/arch-arm64/col32cb16blend/col32cb16blend_test.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-
-#define ARGB_8888_MAX 0xFFFFFFFF
-#define ARGB_8888_MIN 0x00000000
-#define RGB_565_MAX 0xFFFF
-#define RGB_565_MIN 0x0000
-
-struct test_t
-{
- char name[256];
- uint32_t dst_color;
- uint32_t src_color;
- size_t count;
-};
-
-struct test_t tests[] =
-{
- {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1},
- {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2},
- {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3},
- {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4},
- {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1},
- {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2},
- {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3},
- {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4},
- {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5},
- {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
-};
-
-void scanline_col32cb16blend_arm64(uint16_t *dst, int32_t src, size_t count);
-void scanline_col32cb16blend_c(uint16_t * dst, int32_t src, size_t count)
-{
- int srcAlpha = (src>>24);
- int f = 0x100 - (srcAlpha + (srcAlpha>>7));
- while (count--)
- {
- uint16_t d = *dst;
- int dstR = (d>>11)&0x1f;
- int dstG = (d>>5)&0x3f;
- int dstB = (d)&0x1f;
- int srcR = (src >> ( 3))&0x1F;
- int srcG = (src >> ( 8+2))&0x3F;
- int srcB = (src >> (16+3))&0x1F;
- srcR += (f*dstR)>>8;
- srcG += (f*dstG)>>8;
- srcB += (f*dstB)>>8;
- *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB);
- }
-}
-
-void scanline_col32cb16blend_test()
-{
- uint16_t dst_c[16], dst_asm[16];
- uint32_t i, j;
-
- for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i)
- {
- struct test_t test = tests[i];
-
- printf("Testing - %s:",test.name);
-
- memset(dst_c, 0, sizeof(dst_c));
- memset(dst_asm, 0, sizeof(dst_asm));
-
- for(j = 0; j < test.count; ++j)
- {
- dst_c[j] = test.dst_color;
- dst_asm[j] = test.dst_color;
- }
-
-
- scanline_col32cb16blend_c(dst_c, test.src_color, test.count);
- scanline_col32cb16blend_arm64(dst_asm, test.src_color, test.count);
-
-
- if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
- printf("Passed\n");
- else
- printf("Failed\n");
-
- for(j = 0; j < test.count; ++j)
- {
- printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]);
- }
- }
-}
-
-int main()
-{
- scanline_col32cb16blend_test();
- return 0;
-}
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/Android.bp b/libpixelflinger/tests/arch-arm64/disassembler/Android.bp
deleted file mode 100644
index 38dc99a..0000000
--- a/libpixelflinger/tests/arch-arm64/disassembler/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
- name: "test-pixelflinger-arm64-disassembler-test",
- defaults: ["pixelflinger-tests-arm64"],
-
- srcs: ["arm64_diassembler_test.cpp"],
-}
diff --git a/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp b/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp
deleted file mode 100644
index af3183b..0000000
--- a/libpixelflinger/tests/arch-arm64/disassembler/arm64_diassembler_test.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include <stdio.h>
-#include <inttypes.h>
-#include <string.h>
-
-int arm64_disassemble(uint32_t code, char* instr);
-
-struct test_table_entry_t
-{
- uint32_t code;
- const char *instr;
-};
-static test_table_entry_t test_table [] =
-{
- { 0x91000240, "add x0, x18, #0x0, lsl #0" },
- { 0x9140041f, "add sp, x0, #0x1, lsl #12" },
- { 0x917ffff2, "add x18, sp, #0xfff, lsl #12" },
-
- { 0xd13ffe40, "sub x0, x18, #0xfff, lsl #0" },
- { 0xd140001f, "sub sp, x0, #0x0, lsl #12" },
- { 0xd14007f2, "sub x18, sp, #0x1, lsl #12" },
-
- { 0x8b1e0200, "add x0, x16, x30, lsl #0" },
- { 0x8b507fdf, "add xzr, x30, x16, lsr #31" },
- { 0x8b8043f0, "add x16, xzr, x0, asr #16" },
- { 0x8b5f401e, "add x30, x0, xzr, lsr #16" },
-
-
- { 0x4b1e0200, "sub w0, w16, w30, lsl #0" },
- { 0x4b507fdf, "sub wzr, w30, w16, lsr #31" },
- { 0x4b8043f0, "sub w16, wzr, w0, asr #16" },
- { 0x4b5f401e, "sub w30, w0, wzr, lsr #16" },
-
- { 0x6b1e0200, "subs w0, w16, w30, lsl #0" },
- { 0x6b507fdf, "subs wzr, w30, w16, lsr #31" },
- { 0x6b8043f0, "subs w16, wzr, w0, asr #16" },
- { 0x6b5f401e, "subs w30, w0, wzr, lsr #16" },
-
- { 0x0a1e0200, "and w0, w16, w30, lsl #0" },
- { 0x0a507fdf, "and wzr, w30, w16, lsr #31" },
- { 0x0a8043f0, "and w16, wzr, w0, asr #16" },
- { 0x0adf401e, "and w30, w0, wzr, ror #16" },
-
- { 0x2a1e0200, "orr w0, w16, w30, lsl #0" },
- { 0x2a507fdf, "orr wzr, w30, w16, lsr #31" },
- { 0x2a8043f0, "orr w16, wzr, w0, asr #16" },
- { 0x2adf401e, "orr w30, w0, wzr, ror #16" },
-
- { 0x2a3e0200, "orn w0, w16, w30, lsl #0" },
- { 0x2a707fdf, "orn wzr, w30, w16, lsr #31" },
- { 0x2aa043f0, "orn w16, wzr, w0, asr #16" },
- { 0x2aff401e, "orn w30, w0, wzr, ror #16" },
-
- { 0x729fffe0, "movk w0, #0xffff, lsl #0" },
- { 0x72a0000f, "movk w15, #0x0, lsl #16" },
- { 0x7281fffe, "movk w30, #0xfff, lsl #0" },
- { 0x72a0003f, "movk wzr, #0x1, lsl #16" },
-
- { 0x529fffe0, "movz w0, #0xffff, lsl #0" },
- { 0x52a0000f, "movz w15, #0x0, lsl #16" },
- { 0x5281fffe, "movz w30, #0xfff, lsl #0" },
- { 0x52a0003f, "movz wzr, #0x1, lsl #16" },
-
- { 0xd29fffe0, "movz x0, #0xffff, lsl #0" },
- { 0xd2a0000f, "movz x15, #0x0, lsl #16" },
- { 0xd2c1fffe, "movz x30, #0xfff, lsl #32" },
- { 0xd2e0003f, "movz xzr, #0x1, lsl #48" },
-
- { 0x1a8003e0, "csel w0, wzr, w0, eq" },
- { 0x1a831001, "csel w1, w0, w3, ne" },
- { 0x1a9e2022, "csel w2, w1, w30, cs" },
- { 0x1a8a3083, "csel w3, w4, w10, cc" },
- { 0x1a8b40e4, "csel w4, w7, w11, mi" },
- { 0x1a9b5105, "csel w5, w8, w27, pl" },
- { 0x1a846167, "csel w7, w11, w4, vs" },
- { 0x1a8671c8, "csel w8, w14, w6, vc" },
- { 0x1a878289, "csel w9, w20, w7, hi" },
- { 0x1a8c92aa, "csel w10, w21, w12, ls" },
- { 0x1a8ea2ce, "csel w14, w22, w14, ge" },
- { 0x1a9fb3b2, "csel w18, w29, wzr, lt" },
- { 0x1a9fc3d8, "csel w24, w30, wzr, gt" },
- { 0x1a82d17e, "csel w30, w11, w2, le" },
- { 0x1a81e19f, "csel wzr, w12, w1, al" },
-
- { 0x9a8003e0, "csel x0, xzr, x0, eq" },
- { 0x9a831001, "csel x1, x0, x3, ne" },
- { 0x9a9e2022, "csel x2, x1, x30, cs" },
- { 0x9a8a3083, "csel x3, x4, x10, cc" },
- { 0x9a8b40e4, "csel x4, x7, x11, mi" },
- { 0x9a9b5105, "csel x5, x8, x27, pl" },
- { 0x9a846167, "csel x7, x11, x4, vs" },
- { 0x9a8671c8, "csel x8, x14, x6, vc" },
- { 0x9a878289, "csel x9, x20, x7, hi" },
- { 0x9a8c92aa, "csel x10, x21, x12, ls" },
- { 0x9a8ea2ce, "csel x14, x22, x14, ge" },
- { 0x9a9fb3b2, "csel x18, x29, xzr, lt" },
- { 0x9a9fc3d8, "csel x24, x30, xzr, gt" },
- { 0x9a82d17e, "csel x30, x11, x2, le" },
- { 0x9a81e19f, "csel xzr, x12, x1, al" },
-
- { 0x5a8003e0, "csinv w0, wzr, w0, eq" },
- { 0x5a831001, "csinv w1, w0, w3, ne" },
- { 0x5a9e2022, "csinv w2, w1, w30, cs" },
- { 0x5a8a3083, "csinv w3, w4, w10, cc" },
- { 0x5a8b40e4, "csinv w4, w7, w11, mi" },
- { 0x5a9b5105, "csinv w5, w8, w27, pl" },
- { 0x5a846167, "csinv w7, w11, w4, vs" },
- { 0x5a8671c8, "csinv w8, w14, w6, vc" },
- { 0x5a878289, "csinv w9, w20, w7, hi" },
- { 0x5a8c92aa, "csinv w10, w21, w12, ls" },
- { 0x5a8ea2ce, "csinv w14, w22, w14, ge" },
- { 0x5a9fb3b2, "csinv w18, w29, wzr, lt" },
- { 0x5a9fc3d8, "csinv w24, w30, wzr, gt" },
- { 0x5a82d17e, "csinv w30, w11, w2, le" },
- { 0x5a81e19f, "csinv wzr, w12, w1, al" },
-
- { 0x1b1f3fc0, "madd w0, w30, wzr, w15" },
- { 0x1b0079ef, "madd w15, w15, w0, w30" },
- { 0x1b0f7ffe, "madd w30, wzr, w15, wzr" },
- { 0x1b1e001f, "madd wzr, w0, w30, w0" },
-
- { 0x9b3f3fc0, "smaddl x0, w30, wzr, x15" },
- { 0x9b2079ef, "smaddl x15, w15, w0, x30" },
- { 0x9b2f7ffe, "smaddl x30, wzr, w15, xzr" },
- { 0x9b3e001f, "smaddl xzr, w0, w30, x0" },
-
- { 0xd65f0000, "ret x0" },
- { 0xd65f01e0, "ret x15" },
- { 0xd65f03c0, "ret x30" },
- { 0xd65f03e0, "ret xzr" },
-
- { 0xb87f4be0, "ldr w0, [sp, wzr, uxtw #0]" },
- { 0xb87ed80f, "ldr w15, [x0, w30, sxtw #2]" },
- { 0xb86fc9fe, "ldr w30, [x15, w15, sxtw #0]" },
- { 0xb8605bdf, "ldr wzr, [x30, w0, uxtw #2]" },
- { 0xb87febe0, "ldr w0, [sp, xzr, sxtx #0]" },
- { 0xb87e780f, "ldr w15, [x0, x30, lsl #2]" },
- { 0xb86f69fe, "ldr w30, [x15, x15, lsl #0]" },
- { 0xb860fbdf, "ldr wzr, [x30, x0, sxtx #2]" },
-
- { 0xb83f4be0, "str w0, [sp, wzr, uxtw #0]" },
- { 0xb83ed80f, "str w15, [x0, w30, sxtw #2]" },
- { 0xb82fc9fe, "str w30, [x15, w15, sxtw #0]" },
- { 0xb8205bdf, "str wzr, [x30, w0, uxtw #2]" },
- { 0xb83febe0, "str w0, [sp, xzr, sxtx #0]" },
- { 0xb83e780f, "str w15, [x0, x30, lsl #2]" },
- { 0xb82f69fe, "str w30, [x15, x15, lsl #0]" },
- { 0xb820fbdf, "str wzr, [x30, x0, sxtx #2]" },
-
- { 0x787f4be0, "ldrh w0, [sp, wzr, uxtw #0]" },
- { 0x787ed80f, "ldrh w15, [x0, w30, sxtw #1]" },
- { 0x786fc9fe, "ldrh w30, [x15, w15, sxtw #0]" },
- { 0x78605bdf, "ldrh wzr, [x30, w0, uxtw #1]" },
- { 0x787febe0, "ldrh w0, [sp, xzr, sxtx #0]" },
- { 0x787e780f, "ldrh w15, [x0, x30, lsl #1]" },
- { 0x786f69fe, "ldrh w30, [x15, x15, lsl #0]" },
- { 0x7860fbdf, "ldrh wzr, [x30, x0, sxtx #1]" },
-
- { 0x783f4be0, "strh w0, [sp, wzr, uxtw #0]" },
- { 0x783ed80f, "strh w15, [x0, w30, sxtw #1]" },
- { 0x782fc9fe, "strh w30, [x15, w15, sxtw #0]" },
- { 0x78205bdf, "strh wzr, [x30, w0, uxtw #1]" },
- { 0x783febe0, "strh w0, [sp, xzr, sxtx #0]" },
- { 0x783e780f, "strh w15, [x0, x30, lsl #1]" },
- { 0x782f69fe, "strh w30, [x15, x15, lsl #0]" },
- { 0x7820fbdf, "strh wzr, [x30, x0, sxtx #1]" },
-
- { 0x387f5be0, "ldrb w0, [sp, wzr, uxtw #0]" },
- { 0x387ec80f, "ldrb w15, [x0, w30, sxtw ]" },
- { 0x386fd9fe, "ldrb w30, [x15, w15, sxtw #0]" },
- { 0x38604bdf, "ldrb wzr, [x30, w0, uxtw ]" },
- { 0x387ffbe0, "ldrb w0, [sp, xzr, sxtx #0]" },
- { 0x387e780f, "ldrb w15, [x0, x30, lsl #0]" },
- { 0x386f79fe, "ldrb w30, [x15, x15, lsl #0]" },
- { 0x3860ebdf, "ldrb wzr, [x30, x0, sxtx ]" },
-
- { 0x383f5be0, "strb w0, [sp, wzr, uxtw #0]" },
- { 0x383ec80f, "strb w15, [x0, w30, sxtw ]" },
- { 0x382fd9fe, "strb w30, [x15, w15, sxtw #0]" },
- { 0x38204bdf, "strb wzr, [x30, w0, uxtw ]" },
- { 0x383ffbe0, "strb w0, [sp, xzr, sxtx #0]" },
- { 0x383e780f, "strb w15, [x0, x30, lsl #0]" },
- { 0x382f79fe, "strb w30, [x15, x15, lsl #0]" },
- { 0x3820ebdf, "strb wzr, [x30, x0, sxtx ]" },
-
- { 0xf87f4be0, "ldr x0, [sp, wzr, uxtw #0]" },
- { 0xf87ed80f, "ldr x15, [x0, w30, sxtw #3]" },
- { 0xf86fc9fe, "ldr x30, [x15, w15, sxtw #0]" },
- { 0xf8605bdf, "ldr xzr, [x30, w0, uxtw #3]" },
- { 0xf87febe0, "ldr x0, [sp, xzr, sxtx #0]" },
- { 0xf87e780f, "ldr x15, [x0, x30, lsl #3]" },
- { 0xf86f69fe, "ldr x30, [x15, x15, lsl #0]" },
- { 0xf860fbdf, "ldr xzr, [x30, x0, sxtx #3]" },
-
- { 0xf83f4be0, "str x0, [sp, wzr, uxtw #0]" },
- { 0xf83ed80f, "str x15, [x0, w30, sxtw #3]" },
- { 0xf82fc9fe, "str x30, [x15, w15, sxtw #0]" },
- { 0xf8205bdf, "str xzr, [x30, w0, uxtw #3]" },
- { 0xf83febe0, "str x0, [sp, xzr, sxtx #0]" },
- { 0xf83e780f, "str x15, [x0, x30, lsl #3]" },
- { 0xf82f69fe, "str x30, [x15, x15, lsl #0]" },
- { 0xf820fbdf, "str xzr, [x30, x0, sxtx #3]" },
-
- { 0xb85007e0, "ldr w0, [sp], #-256" },
- { 0xb840040f, "ldr w15, [x0], #0" },
- { 0xb84015fe, "ldr w30, [x15], #1" },
- { 0xb84ff7df, "ldr wzr, [x30], #255" },
- { 0xb8100fe0, "str w0, [sp, #-256]!" },
- { 0xb8000c0f, "str w15, [x0, #0]!" },
- { 0xb8001dfe, "str w30, [x15, #1]!" },
- { 0xb80fffdf, "str wzr, [x30, #255]!" },
-
- { 0x13017be0, "sbfm w0, wzr, #1, #30" },
- { 0x131e7fcf, "sbfm w15, w30, #30, #31" },
- { 0x131f01fe, "sbfm w30, w15, #31, #0" },
- { 0x1300041f, "sbfm wzr, w0, #0, #1" },
-
- { 0x53017be0, "ubfm w0, wzr, #1, #30" },
- { 0x531e7fcf, "ubfm w15, w30, #30, #31" },
- { 0x531f01fe, "ubfm w30, w15, #31, #0" },
- { 0x5300041f, "ubfm wzr, w0, #0, #1" },
- { 0xd3417fe0, "ubfm x0, xzr, #1, #31" },
- { 0xd35fffcf, "ubfm x15, x30, #31, #63" },
- { 0xd35f01fe, "ubfm x30, x15, #31, #0" },
- { 0xd340041f, "ubfm xzr, x0, #0, #1" },
-
- { 0x139e7be0, "extr w0, wzr, w30, #30" },
- { 0x138f7fcf, "extr w15, w30, w15, #31" },
- { 0x138001fe, "extr w30, w15, w0, #0" },
- { 0x139f041f, "extr wzr, w0, wzr, #1" },
-
- { 0x54000020, "b.eq #.+4" },
- { 0x54000201, "b.ne #.+64" },
- { 0x54000802, "b.cs #.+256" },
- { 0x54002003, "b.cc #.+1024" },
- { 0x54008004, "b.mi #.+4096" },
- { 0x54ffffe5, "b.pl #.-4" },
- { 0x54ffff06, "b.vs #.-32" },
- { 0x54fffc07, "b.vc #.-128" },
- { 0x54fff008, "b.hi #.-512" },
- { 0x54000049, "b.ls #.+8" },
- { 0x5400006a, "b.ge #.+12" },
- { 0x5400008b, "b.lt #.+16" },
- { 0x54ffffcc, "b.gt #.-8" },
- { 0x54ffffad, "b.le #.-12" },
- { 0x54ffff8e, "b.al #.-16" },
-
- { 0x8b2001e0, "add x0, x15, w0, uxtb #0" },
- { 0x8b2f27cf, "add x15, x30, w15, uxth #1" },
- { 0x8b3e4bfe, "add x30, sp, w30, uxtw #2" },
- { 0x8b3f6c1f, "add sp, x0, xzr, uxtx #3" },
- { 0x8b2091e0, "add x0, x15, w0, sxtb #4" },
- { 0x8b2fa3cf, "add x15, x30, w15, sxth #0" },
- { 0x8b3ec7fe, "add x30, sp, w30, sxtw #1" },
- { 0x8b3fe81f, "add sp, x0, xzr, sxtx #2" },
-
- { 0xcb2001e0, "sub x0, x15, w0, uxtb #0" },
- { 0xcb2f27cf, "sub x15, x30, w15, uxth #1" },
- { 0xcb3e4bfe, "sub x30, sp, w30, uxtw #2" },
- { 0xcb3f6c1f, "sub sp, x0, xzr, uxtx #3" },
- { 0xcb2091e0, "sub x0, x15, w0, sxtb #4" },
- { 0xcb2fa3cf, "sub x15, x30, w15, sxth #0" },
- { 0xcb3ec7fe, "sub x30, sp, w30, sxtw #1" },
- { 0xcb3fe81f, "sub sp, x0, xzr, sxtx #2" }
-};
-
-int main()
-{
- char instr[256];
- uint32_t failed = 0;
- for(uint32_t i = 0; i < sizeof(test_table)/sizeof(test_table_entry_t); ++i)
- {
- test_table_entry_t *test;
- test = &test_table[i];
- arm64_disassemble(test->code, instr);
- if(strcmp(instr, test->instr) != 0)
- {
- printf("Test Failed \n"
- "Code : 0x%0x\n"
- "Expected : %s\n"
- "Actual : %s\n", test->code, test->instr, instr);
- failed++;
- }
- }
- if(failed == 0)
- {
- printf("All tests PASSED\n");
- return 0;
- }
- else
- {
- printf("%d tests FAILED\n", failed);
- return -1;
- }
-}
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp b/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp
deleted file mode 100644
index 9d060d1..0000000
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-cc_test {
- name: "test-pixelflinger-arm64-t32cb16blend",
- defaults: ["pixelflinger-tests-arm64"],
-
- srcs: ["t32cb16blend_test.c"],
-}
diff --git a/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c b/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c
deleted file mode 100644
index afb36fb..0000000
--- a/libpixelflinger/tests/arch-arm64/t32cb16blend/t32cb16blend_test.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#define ARGB_8888_MAX 0xFFFFFFFF
-#define ARGB_8888_MIN 0x00000000
-#define RGB_565_MAX 0xFFFF
-#define RGB_565_MIN 0x0000
-
-struct test_t
-{
- char name[256];
- uint32_t src_color;
- uint16_t dst_color;
- size_t count;
-};
-
-struct test_t tests[] =
-{
- {"Count 0", 0, 0, 0},
- {"Count 1, Src=Max, Dst=Min", ARGB_8888_MAX, RGB_565_MIN, 1},
- {"Count 2, Src=Min, Dst=Max", ARGB_8888_MIN, RGB_565_MAX, 2},
- {"Count 3, Src=Max, Dst=Max", ARGB_8888_MAX, RGB_565_MAX, 3},
- {"Count 4, Src=Min, Dst=Min", ARGB_8888_MAX, RGB_565_MAX, 4},
- {"Count 1, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 1},
- {"Count 2, Src=Rand, Dst=Rand", 0xABCDEF12, 0x2345, 2},
- {"Count 3, Src=Rand, Dst=Rand", 0x11111111, 0xEDFE, 3},
- {"Count 4, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 4},
- {"Count 5, Src=Rand, Dst=Rand", 0xEFEFFEFE, 0xFACC, 5},
- {"Count 10, Src=Rand, Dst=Rand", 0x12345678, 0x9ABC, 10}
-
-};
-
-void scanline_t32cb16blend_arm64(uint16_t*, uint32_t*, size_t);
-void scanline_t32cb16blend_c(uint16_t * dst, uint32_t* src, size_t count)
-{
- while (count--)
- {
- uint16_t d = *dst;
- uint32_t s = *src++;
- int dstR = (d>>11)&0x1f;
- int dstG = (d>>5)&0x3f;
- int dstB = (d)&0x1f;
- int srcR = (s >> ( 3))&0x1F;
- int srcG = (s >> ( 8+2))&0x3F;
- int srcB = (s >> (16+3))&0x1F;
- int srcAlpha = (s>>24) & 0xFF;
-
-
- int f = 0x100 - (srcAlpha + ((srcAlpha>>7) & 0x1));
- srcR += (f*dstR)>>8;
- srcG += (f*dstG)>>8;
- srcB += (f*dstB)>>8;
- srcR = srcR > 0x1F? 0x1F: srcR;
- srcG = srcG > 0x3F? 0x3F: srcG;
- srcB = srcB > 0x1F? 0x1F: srcB;
- *dst++ = (uint16_t)((srcR<<11)|(srcG<<5)|srcB);
- }
-}
-
-void scanline_t32cb16blend_test()
-{
- uint16_t dst_c[16], dst_asm[16];
- uint32_t src[16];
- uint32_t i;
- uint32_t j;
-
- for(i = 0; i < sizeof(tests)/sizeof(struct test_t); ++i)
- {
- struct test_t test = tests[i];
-
- printf("Testing - %s:",test.name);
-
- memset(dst_c, 0, sizeof(dst_c));
- memset(dst_asm, 0, sizeof(dst_asm));
-
- for(j = 0; j < test.count; ++j)
- {
- dst_c[j] = test.dst_color;
- dst_asm[j] = test.dst_color;
- src[j] = test.src_color;
- }
-
- scanline_t32cb16blend_c(dst_c,src,test.count);
- scanline_t32cb16blend_arm64(dst_asm,src,test.count);
-
-
- if(memcmp(dst_c, dst_asm, sizeof(dst_c)) == 0)
- printf("Passed\n");
- else
- printf("Failed\n");
-
- for(j = 0; j < test.count; ++j)
- {
- printf("dst_c[%d] = %x, dst_asm[%d] = %x \n", j, dst_c[j], j, dst_asm[j]);
- }
- }
-}
-
-int main()
-{
- scanline_t32cb16blend_test();
- return 0;
-}
diff --git a/libpixelflinger/tests/codegen/Android.bp b/libpixelflinger/tests/codegen/Android.bp
deleted file mode 100644
index 7e4bcfb3..0000000
--- a/libpixelflinger/tests/codegen/Android.bp
+++ /dev/null
@@ -1,12 +0,0 @@
-cc_test {
- name: "test-opengl-codegen",
- defaults: ["pixelflinger-tests"],
-
- srcs: ["codegen.cpp"],
-
- arch: {
- arm: {
- instruction_set: "arm",
- },
- },
-}
diff --git a/libpixelflinger/tests/codegen/codegen.cpp b/libpixelflinger/tests/codegen/codegen.cpp
deleted file mode 100644
index dce4ed7..0000000
--- a/libpixelflinger/tests/codegen/codegen.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-#include <stdio.h>
-#include <stdint.h>
-
-#include "private/pixelflinger/ggl_context.h"
-
-#include "buffer.h"
-#include "scanline.h"
-
-#include "codeflinger/CodeCache.h"
-#include "codeflinger/GGLAssembler.h"
-#include "codeflinger/ARMAssembler.h"
-#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-#include "codeflinger/MIPSAssembler.h"
-#elif defined(__mips__) && defined(__LP64__) && __mips_isa_rev == 6
-#include "codeflinger/MIPS64Assembler.h"
-#endif
-#include "codeflinger/Arm64Assembler.h"
-
-#if defined(__arm__) || (defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || (defined(__LP64__) && __mips_isa_rev == 6))) || defined(__aarch64__)
-# define ANDROID_ARM_CODEGEN 1
-#else
-# define ANDROID_ARM_CODEGEN 0
-#endif
-
-#if defined(__mips__) && ((!defined(__LP64__) && __mips_isa_rev < 6) || (defined(__LP64__) && __mips_isa_rev == 6))
-#define ASSEMBLY_SCRATCH_SIZE 4096
-#elif defined(__aarch64__)
-#define ASSEMBLY_SCRATCH_SIZE 8192
-#else
-#define ASSEMBLY_SCRATCH_SIZE 2048
-#endif
-
-using namespace android;
-
-class ScanlineAssembly : public Assembly {
- AssemblyKey<needs_t> mKey;
-public:
- ScanlineAssembly(needs_t needs, size_t size)
- : Assembly(size), mKey(needs) { }
- const AssemblyKey<needs_t>& key() const { return mKey; }
-};
-
-#if ANDROID_ARM_CODEGEN
-static void ggl_test_codegen(uint32_t n, uint32_t p, uint32_t t0, uint32_t t1)
-{
- GGLContext* c;
- gglInit(&c);
- needs_t needs;
- needs.n = n;
- needs.p = p;
- needs.t[0] = t0;
- needs.t[1] = t1;
- sp<ScanlineAssembly> a(new ScanlineAssembly(needs, ASSEMBLY_SCRATCH_SIZE));
-
-#if defined(__arm__)
- GGLAssembler assembler( new ARMAssembler(a) );
-#endif
-
-#if defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
- GGLAssembler assembler( new ArmToMipsAssembler(a) );
-#endif
-
-#if defined(__mips__) && defined(__LP64__) && __mips_isa_rev == 6
- GGLAssembler assembler( new ArmToMips64Assembler(a) );
-#endif
-
-#if defined(__aarch64__)
- GGLAssembler assembler( new ArmToArm64Assembler(a) );
-#endif
-
- int err = assembler.scanline(needs, (context_t*)c);
- if (err != 0) {
- printf("error %08x (%s)\n", err, strerror(-err));
- }
- gglUninit(c);
-}
-#else
-static void ggl_test_codegen(uint32_t, uint32_t, uint32_t, uint32_t) {
- printf("This test runs only on ARM, Arm64 or MIPS\n");
-}
-#endif
-
-int main(int argc, char** argv)
-{
- if (argc != 2) {
- printf("usage: %s 00000117:03454504_00001501_00000000\n", argv[0]);
- return 0;
- }
- uint32_t n;
- uint32_t p;
- uint32_t t0;
- uint32_t t1;
- sscanf(argv[1], "%08x:%08x_%08x_%08x", &p, &n, &t0, &t1);
- ggl_test_codegen(n, p, t0, t1);
- return 0;
-}
diff --git a/libpixelflinger/tests/gglmul/Android.bp b/libpixelflinger/tests/gglmul/Android.bp
deleted file mode 100644
index 288337b..0000000
--- a/libpixelflinger/tests/gglmul/Android.bp
+++ /dev/null
@@ -1,12 +0,0 @@
-cc_test {
- name: "test-pixelflinger-gglmul",
-
- srcs: ["gglmul_test.cpp"],
-
- header_libs: ["libpixelflinger_internal"],
-
- cflags: [
- "-Wall",
- "-Werror",
- ],
-}
diff --git a/libpixelflinger/tests/gglmul/gglmul_test.cpp b/libpixelflinger/tests/gglmul/gglmul_test.cpp
deleted file mode 100644
index 5d460d6..0000000
--- a/libpixelflinger/tests/gglmul/gglmul_test.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdint.h>
-#include <inttypes.h>
-
-#include "private/pixelflinger/ggl_fixed.h"
-
-// gglClampx() tests
-struct gglClampx_test_t
-{
- GGLfixed input;
- GGLfixed output;
-};
-
-gglClampx_test_t gglClampx_tests[] =
-{
- {FIXED_ONE + 1, FIXED_ONE},
- {FIXED_ONE, FIXED_ONE},
- {FIXED_ONE - 1, FIXED_ONE - 1},
- {1, 1},
- {0, 0},
- {FIXED_MIN,0}
-};
-
-void gglClampx_test()
-{
- uint32_t i;
-
- printf("Testing gglClampx\n");
- for(i = 0; i < sizeof(gglClampx_tests)/sizeof(gglClampx_test_t); ++i)
- {
- gglClampx_test_t *test = &gglClampx_tests[i];
- printf("Test input=0x%08x output=0x%08x :",
- test->input, test->output);
- if(gglClampx(test->input) == test->output)
- printf("Passed\n");
- else
- printf("Failed\n");
- }
-}
-
-// gglClz() tests
-struct gglClz_test_t
-{
- GGLfixed input;
- GGLfixed output;
-};
-
-gglClz_test_t gglClz_tests[] =
-{
- {0, 32},
- {1, 31},
- {-1,0}
-};
-
-void gglClz_test()
-{
- uint32_t i;
-
- printf("Testing gglClz\n");
- for(i = 0; i < sizeof(gglClz_tests)/sizeof(gglClz_test_t); ++i)
- {
- gglClz_test_t *test = &gglClz_tests[i];
- printf("Test input=0x%08x output=%2d :", test->input, test->output);
- if(gglClz(test->input) == test->output)
- printf("Passed\n");
- else
- printf("Failed\n");
- }
-}
-
-// gglMulx() tests
-struct gglMulx_test_t
-{
- GGLfixed x;
- GGLfixed y;
- int shift;
-};
-
-gglMulx_test_t gglMulx_tests[] =
-{
- {1,1,1},
- {0,1,1},
- {FIXED_ONE,FIXED_ONE,16},
- {FIXED_MIN,FIXED_MAX,16},
- {FIXED_MAX,FIXED_MAX,16},
- {FIXED_MIN,FIXED_MIN,16},
- {FIXED_HALF,FIXED_ONE,16},
- {FIXED_MAX,FIXED_MAX,31},
- {FIXED_ONE,FIXED_MAX,31}
-};
-
-void gglMulx_test()
-{
- uint32_t i;
- GGLfixed actual, expected;
-
- printf("Testing gglMulx\n");
- for(i = 0; i < sizeof(gglMulx_tests)/sizeof(gglMulx_test_t); ++i)
- {
- gglMulx_test_t *test = &gglMulx_tests[i];
- printf("Test x=0x%08x y=0x%08x shift=%2d :",
- test->x, test->y, test->shift);
- actual = gglMulx(test->x, test->y, test->shift);
- expected =
- ((int64_t)test->x * test->y + (1 << (test->shift-1))) >> test->shift;
- if(actual == expected)
- printf(" Passed\n");
- else
- printf(" Failed Actual(0x%08x) Expected(0x%08x)\n",
- actual, expected);
- }
-}
-// gglMulAddx() tests
-struct gglMulAddx_test_t
-{
- GGLfixed x;
- GGLfixed y;
- int shift;
- GGLfixed a;
-};
-
-gglMulAddx_test_t gglMulAddx_tests[] =
-{
- {1,2,1,1},
- {0,1,1,1},
- {FIXED_ONE,FIXED_ONE,16, 0},
- {FIXED_MIN,FIXED_MAX,16, FIXED_HALF},
- {FIXED_MAX,FIXED_MAX,16, FIXED_MIN},
- {FIXED_MIN,FIXED_MIN,16, FIXED_MAX},
- {FIXED_HALF,FIXED_ONE,16,FIXED_ONE},
- {FIXED_MAX,FIXED_MAX,31, FIXED_HALF},
- {FIXED_ONE,FIXED_MAX,31, FIXED_HALF}
-};
-
-void gglMulAddx_test()
-{
- uint32_t i;
- GGLfixed actual, expected;
-
- printf("Testing gglMulAddx\n");
- for(i = 0; i < sizeof(gglMulAddx_tests)/sizeof(gglMulAddx_test_t); ++i)
- {
- gglMulAddx_test_t *test = &gglMulAddx_tests[i];
- printf("Test x=0x%08x y=0x%08x shift=%2d a=0x%08x :",
- test->x, test->y, test->shift, test->a);
- actual = gglMulAddx(test->x, test->y,test->a, test->shift);
- expected = (((int64_t)test->x * test->y) >> test->shift) + test->a;
-
- if(actual == expected)
- printf(" Passed\n");
- else
- printf(" Failed Actual(0x%08x) Expected(0x%08x)\n",
- actual, expected);
- }
-}
-// gglMulSubx() tests
-struct gglMulSubx_test_t
-{
- GGLfixed x;
- GGLfixed y;
- int shift;
- GGLfixed a;
-};
-
-gglMulSubx_test_t gglMulSubx_tests[] =
-{
- {1,2,1,1},
- {0,1,1,1},
- {FIXED_ONE,FIXED_ONE,16, 0},
- {FIXED_MIN,FIXED_MAX,16, FIXED_HALF},
- {FIXED_MAX,FIXED_MAX,16, FIXED_MIN},
- {FIXED_MIN,FIXED_MIN,16, FIXED_MAX},
- {FIXED_HALF,FIXED_ONE,16,FIXED_ONE},
- {FIXED_MAX,FIXED_MAX,31, FIXED_HALF},
- {FIXED_ONE,FIXED_MAX,31, FIXED_HALF}
-};
-
-void gglMulSubx_test()
-{
- uint32_t i;
- GGLfixed actual, expected;
-
- printf("Testing gglMulSubx\n");
- for(i = 0; i < sizeof(gglMulSubx_tests)/sizeof(gglMulSubx_test_t); ++i)
- {
- gglMulSubx_test_t *test = &gglMulSubx_tests[i];
- printf("Test x=0x%08x y=0x%08x shift=%2d a=0x%08x :",
- test->x, test->y, test->shift, test->a);
- actual = gglMulSubx(test->x, test->y, test->a, test->shift);
- expected = (((int64_t)test->x * test->y) >> test->shift) - test->a;
-
- if(actual == expected)
- printf(" Passed\n");
- else
- printf(" Failed Actual(0x%08x) Expected(0x%08x)\n",
- actual, expected);
- }
-}
-
-// gglMulii() tests
-
-struct gglMulii_test_t
-{
- int32_t x;
- int32_t y;
-};
-
-gglMulii_test_t gglMulii_tests[] =
-{
- {1,INT32_MIN},
- {1,INT32_MAX},
- {0,INT32_MIN},
- {0,INT32_MAX},
- {INT32_MIN, INT32_MAX},
- {INT32_MAX, INT32_MIN},
- {INT32_MIN, INT32_MIN},
- {INT32_MAX, INT32_MAX}
-};
-
-void gglMulii_test()
-{
- uint32_t i;
- int64_t actual, expected;
-
- printf("Testing gglMulii\n");
- for(i = 0; i < sizeof(gglMulii_tests)/sizeof(gglMulii_test_t); ++i)
- {
- gglMulii_test_t *test = &gglMulii_tests[i];
- printf("Test x=0x%08x y=0x%08x :", test->x, test->y);
- actual = gglMulii(test->x, test->y);
- expected = ((int64_t)test->x * test->y);
-
- if(actual == expected)
- printf(" Passed\n");
- else
- printf(" Failed Actual(%" PRId64 ") Expected(%" PRId64 ")\n",
- actual, expected);
- }
-}
-
-int main(int /*argc*/, char** /*argv*/)
-{
- gglClampx_test();
- gglClz_test();
- gglMulx_test();
- gglMulAddx_test();
- gglMulSubx_test();
- gglMulii_test();
- return 0;
-}
diff --git a/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
deleted file mode 100644
index 06ad237..0000000
--- a/libpixelflinger/trap.cpp
+++ /dev/null
@@ -1,1173 +0,0 @@
-/* libs/pixelflinger/trap.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define LOG_TAG "pixelflinger-trap"
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/memory.h>
-#include <log/log.h>
-
-#include "trap.h"
-#include "picker.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// enable to see triangles edges
-#define DEBUG_TRANGLES 0
-
-// ----------------------------------------------------------------------------
-
-static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r);
-static void pointx(void *con, const GGLcoord* c, GGLcoord r);
-static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r);
-static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r);
-
-static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-
-static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
-static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
-
-static void trianglex_validate(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_small(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_big(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void aa_trianglex(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_debug(void* con,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-
-static void aapolyx(void* con,
- const GGLcoord* pts, int count);
-
-static inline int min(int a, int b) CONST;
-static inline int max(int a, int b) CONST;
-static inline int min(int a, int b, int c) CONST;
-static inline int max(int a, int b, int c) CONST;
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Tools
-#endif
-
-inline int min(int a, int b) {
- return a<b ? a : b;
-}
-inline int max(int a, int b) {
- return a<b ? b : a;
-}
-inline int min(int a, int b, int c) {
- return min(a,min(b,c));
-}
-inline int max(int a, int b, int c) {
- return max(a,max(b,c));
-}
-
-template <typename T>
-static inline void swap(T& a, T& b) {
- T t(a);
- a = b;
- b = t;
-}
-
-static void
-triangle_dump_points( const GGLcoord* v0,
- const GGLcoord* v1,
- const GGLcoord* v2 )
-{
- float tri = 1.0f / TRI_ONE;
- ALOGD(" P0=(%.3f, %.3f) [%08x, %08x]\n"
- " P1=(%.3f, %.3f) [%08x, %08x]\n"
- " P2=(%.3f, %.3f) [%08x, %08x]\n",
- v0[0]*tri, v0[1]*tri, v0[0], v0[1],
- v1[0]*tri, v1[1]*tri, v1[0], v1[1],
- v2[0]*tri, v2[1]*tri, v2[0], v2[1] );
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Misc
-#endif
-
-void ggl_init_trap(context_t* c)
-{
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE);
-}
-
-void ggl_state_changed(context_t* c, int flags)
-{
- if (ggl_likely(!c->dirty)) {
- c->procs.pointx = pointx_validate;
- c->procs.linex = linex_validate;
- c->procs.recti = recti_validate;
- c->procs.trianglex = trianglex_validate;
- }
- c->dirty |= uint32_t(flags);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Point
-#endif
-
-void pointx_validate(void *con, const GGLcoord* v, GGLcoord rad)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- if (c->state.enables & GGL_ENABLE_POINT_AA_NICE) {
- c->procs.pointx = aa_nice_pointx;
- } else {
- c->procs.pointx = aa_pointx;
- }
- } else {
- c->procs.pointx = pointx;
- }
- c->procs.pointx(con, v, rad);
-}
-
-void pointx(void *con, const GGLcoord* v, GGLcoord rad)
-{
- GGL_CONTEXT(c, con);
- GGLcoord halfSize = TRI_ROUND(rad) >> 1;
- if (halfSize == 0)
- halfSize = TRI_HALF;
- GGLcoord xc = v[0];
- GGLcoord yc = v[1];
- if (halfSize & TRI_HALF) { // size odd
- xc = TRI_FLOOR(xc) + TRI_HALF;
- yc = TRI_FLOOR(yc) + TRI_HALF;
- } else { // size even
- xc = TRI_ROUND(xc);
- yc = TRI_ROUND(yc);
- }
- GGLint l = (xc - halfSize) >> TRI_FRACTION_BITS;
- GGLint t = (yc - halfSize) >> TRI_FRACTION_BITS;
- GGLint r = (xc + halfSize) >> TRI_FRACTION_BITS;
- GGLint b = (yc + halfSize) >> TRI_FRACTION_BITS;
- recti(c, l, t, r, b);
-}
-
-// This way of computing the coverage factor, is more accurate and gives
-// better results for small circles, but it is also a lot slower.
-// Here we use super-sampling.
-static int32_t coverageNice(GGLcoord x, GGLcoord y,
- GGLcoord rmin, GGLcoord rmax, GGLcoord rr)
-{
- const GGLcoord d2 = x*x + y*y;
- if (d2 >= rmax) return 0;
- if (d2 < rmin) return 0x7FFF;
-
- const int kSamples = 4;
- const int kInc = 4; // 1/4 = 0.25
- const int kCoverageUnit = 1; // 1/(4^2) = 0.0625
- const GGLcoord kCoordOffset = -6; // -0.375
-
- int hits = 0;
- int x_sample = x + kCoordOffset;
- for (int i=0 ; i<kSamples ; i++, x_sample += kInc) {
- const int xval = rr - (x_sample * x_sample);
- int y_sample = y + kCoordOffset;
- for (int j=0 ; j<kSamples ; j++, y_sample += kInc) {
- if (xval - (y_sample * y_sample) > 0)
- hits += kCoverageUnit;
- }
- }
- return min(0x7FFF, hits << (15 - kSamples));
-}
-
-
-void aa_nice_pointx(void *con, const GGLcoord* v, GGLcoord size)
-{
- GGL_CONTEXT(c, con);
-
- GGLcoord rad = ((size + 1)>>1);
- GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
- GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
- GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
- GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
-
- // scissor...
- if (l < GGLint(c->state.scissor.left)) {
- xstart += TRI_FROM_INT(c->state.scissor.left-l);
- l = GGLint(c->state.scissor.left);
- }
- if (t < GGLint(c->state.scissor.top)) {
- ystart += TRI_FROM_INT(c->state.scissor.top-t);
- t = GGLint(c->state.scissor.top);
- }
- if (r > GGLint(c->state.scissor.right)) {
- r = GGLint(c->state.scissor.right);
- }
- if (b > GGLint(c->state.scissor.bottom)) {
- b = GGLint(c->state.scissor.bottom);
- }
-
- int xc = r - l;
- int yc = b - t;
- if (xc>0 && yc>0) {
- int16_t* covPtr = c->state.buffers.coverage;
- const int32_t sqr2Over2 = 0xC; // rounded up
- GGLcoord rr = rad*rad;
- GGLcoord rmin = (rad - sqr2Over2)*(rad - sqr2Over2);
- GGLcoord rmax = (rad + sqr2Over2)*(rad + sqr2Over2);
- GGLcoord y = ystart;
- c->iterators.xl = l;
- c->iterators.xr = r;
- c->init_y(c, t);
- do {
- // compute coverage factors for each pixel
- GGLcoord x = xstart;
- for (int i=l ; i<r ; i++) {
- covPtr[i] = coverageNice(x, y, rmin, rmax, rr);
- x += TRI_ONE;
- }
- y += TRI_ONE;
- c->scanline(c);
- c->step_y(c);
- } while (--yc);
- }
-}
-
-// This is a cheap way of computing the coverage factor for a circle.
-// We just lerp between the circles of radii r-sqrt(2)/2 and r+sqrt(2)/2
-static inline int32_t coverageFast(GGLcoord x, GGLcoord y,
- GGLcoord rmin, GGLcoord rmax, GGLcoord scale)
-{
- const GGLcoord d2 = x*x + y*y;
- if (d2 >= rmax) return 0;
- if (d2 < rmin) return 0x7FFF;
- return 0x7FFF - (d2-rmin)*scale;
-}
-
-void aa_pointx(void *con, const GGLcoord* v, GGLcoord size)
-{
- GGL_CONTEXT(c, con);
-
- GGLcoord rad = ((size + 1)>>1);
- GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
- GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
- GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
- GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
-
- // scissor...
- if (l < GGLint(c->state.scissor.left)) {
- xstart += TRI_FROM_INT(c->state.scissor.left-l);
- l = GGLint(c->state.scissor.left);
- }
- if (t < GGLint(c->state.scissor.top)) {
- ystart += TRI_FROM_INT(c->state.scissor.top-t);
- t = GGLint(c->state.scissor.top);
- }
- if (r > GGLint(c->state.scissor.right)) {
- r = GGLint(c->state.scissor.right);
- }
- if (b > GGLint(c->state.scissor.bottom)) {
- b = GGLint(c->state.scissor.bottom);
- }
-
- int xc = r - l;
- int yc = b - t;
- if (xc>0 && yc>0) {
- int16_t* covPtr = c->state.buffers.coverage;
- rad <<= 4;
- const int32_t sqr2Over2 = 0xB5; // fixed-point 24.8
- GGLcoord rmin = rad - sqr2Over2;
- GGLcoord rmax = rad + sqr2Over2;
- GGLcoord scale;
- rmin *= rmin;
- rmax *= rmax;
- scale = 0x800000 / (rmax - rmin);
- rmin >>= 8;
- rmax >>= 8;
-
- GGLcoord y = ystart;
- c->iterators.xl = l;
- c->iterators.xr = r;
- c->init_y(c, t);
-
- do {
- // compute coverage factors for each pixel
- GGLcoord x = xstart;
- for (int i=l ; i<r ; i++) {
- covPtr[i] = coverageFast(x, y, rmin, rmax, scale);
- x += TRI_ONE;
- }
- y += TRI_ONE;
- c->scanline(c);
- c->step_y(c);
- } while (--yc);
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Line
-#endif
-
-void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- c->procs.linex = aa_linex;
- } else {
- c->procs.linex = linex;
- }
- c->procs.linex(con, v0, v1, w);
-}
-
-static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
-{
- GGLcoord v[4][2];
- v[0][0] = v0[0]; v[0][1] = v0[1];
- v[1][0] = v1[0]; v[1][1] = v1[1];
- v0 = v[0];
- v1 = v[1];
- const GGLcoord dx = abs(v0[0] - v1[0]);
- const GGLcoord dy = abs(v0[1] - v1[1]);
- GGLcoord nx, ny;
- nx = ny = 0;
-
- GGLcoord halfWidth = TRI_ROUND(width) >> 1;
- if (halfWidth == 0)
- halfWidth = TRI_HALF;
-
- ((dx > dy) ? ny : nx) = halfWidth;
- v[2][0] = v1[0]; v[2][1] = v1[1];
- v[3][0] = v0[0]; v[3][1] = v0[1];
- v[0][0] += nx; v[0][1] += ny;
- v[1][0] += nx; v[1][1] += ny;
- v[2][0] -= nx; v[2][1] -= ny;
- v[3][0] -= nx; v[3][1] -= ny;
- trianglex_big(con, v[0], v[1], v[2]);
- trianglex_big(con, v[0], v[2], v[3]);
-}
-
-static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
-{
- GGLcoord v[4][2];
- v[0][0] = v0[0]; v[0][1] = v0[1];
- v[1][0] = v1[0]; v[1][1] = v1[1];
- v0 = v[0];
- v1 = v[1];
-
- const GGLcoord dx = v0[0] - v1[0];
- const GGLcoord dy = v0[1] - v1[1];
- GGLcoord nx = -dy;
- GGLcoord ny = dx;
-
- // generally, this will be well below 1.0
- const GGLfixed norm = gglMulx(width, gglSqrtRecipx(nx*nx+ny*ny), 4);
- nx = gglMulx(nx, norm, 21);
- ny = gglMulx(ny, norm, 21);
-
- v[2][0] = v1[0]; v[2][1] = v1[1];
- v[3][0] = v0[0]; v[3][1] = v0[1];
- v[0][0] += nx; v[0][1] += ny;
- v[1][0] += nx; v[1][1] += ny;
- v[2][0] -= nx; v[2][1] -= ny;
- v[3][0] -= nx; v[3][1] -= ny;
- aapolyx(con, v[0], 4);
-}
-
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Rect
-#endif
-
-void recti_validate(void *con, GGLint l, GGLint t, GGLint r, GGLint b)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- c->procs.recti = recti;
- c->procs.recti(con, l, t, r, b);
-}
-
-void recti(void* con, GGLint l, GGLint t, GGLint r, GGLint b)
-{
- GGL_CONTEXT(c, con);
-
- // scissor...
- if (l < GGLint(c->state.scissor.left))
- l = GGLint(c->state.scissor.left);
- if (t < GGLint(c->state.scissor.top))
- t = GGLint(c->state.scissor.top);
- if (r > GGLint(c->state.scissor.right))
- r = GGLint(c->state.scissor.right);
- if (b > GGLint(c->state.scissor.bottom))
- b = GGLint(c->state.scissor.bottom);
-
- int xc = r - l;
- int yc = b - t;
- if (xc>0 && yc>0) {
- c->iterators.xl = l;
- c->iterators.xr = r;
- c->init_y(c, t);
- c->rect(c, yc);
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Triangle / Debugging
-#endif
-
-static void scanline_set(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- const GGLFormat* fp = &(c->formats[cb->format]);
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
- (x + (cb->stride * y)) * fp->size;
- const size_t size = ct * fp->size;
- memset(dst, 0xFF, size);
-}
-
-static void trianglex_debug(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- aa_trianglex(con,v0,v1,v2);
- } else {
- trianglex_big(con,v0,v1,v2);
- }
- void (*save_scanline)(context_t*) = c->scanline;
- c->scanline = scanline_set;
- linex(con, v0, v1, TRI_ONE);
- linex(con, v1, v2, TRI_ONE);
- linex(con, v2, v0, TRI_ONE);
- c->scanline = save_scanline;
-}
-
-static void trianglex_xor(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- trianglex_big(con,v0,v1,v2);
- trianglex_small(con,v0,v1,v2);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Triangle
-#endif
-
-void trianglex_validate(void *con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : aa_trianglex;
- } else {
- c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : trianglex_big;
- }
- c->procs.trianglex(con, v0, v1, v2);
-}
-
-// ----------------------------------------------------------------------------
-
-void trianglex_small(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
-
- // vertices are in 28.4 fixed point, which allows
- // us to use 32 bits multiplies below.
- int32_t x0 = v0[0];
- int32_t y0 = v0[1];
- int32_t x1 = v1[0];
- int32_t y1 = v1[1];
- int32_t x2 = v2[0];
- int32_t y2 = v2[1];
-
- int32_t dx01 = x0 - x1;
- int32_t dy20 = y2 - y0;
- int32_t dy01 = y0 - y1;
- int32_t dx20 = x2 - x0;
-
- // The code below works only with CCW triangles
- // so if we get a CW triangle, we need to swap two of its vertices
- if (dx01*dy20 < dy01*dx20) {
- swap(x0, x1);
- swap(y0, y1);
- dx01 = x0 - x1;
- dy01 = y0 - y1;
- dx20 = x2 - x0;
- dy20 = y2 - y0;
- }
- int32_t dx12 = x1 - x2;
- int32_t dy12 = y1 - y2;
-
- // bounding box & scissor
- const int32_t bminx = TRI_FLOOR(min(x0, x1, x2)) >> TRI_FRACTION_BITS;
- const int32_t bminy = TRI_FLOOR(min(y0, y1, y2)) >> TRI_FRACTION_BITS;
- const int32_t bmaxx = TRI_CEIL( max(x0, x1, x2)) >> TRI_FRACTION_BITS;
- const int32_t bmaxy = TRI_CEIL( max(y0, y1, y2)) >> TRI_FRACTION_BITS;
- const int32_t minx = max(bminx, c->state.scissor.left);
- const int32_t miny = max(bminy, c->state.scissor.top);
- const int32_t maxx = min(bmaxx, c->state.scissor.right);
- const int32_t maxy = min(bmaxy, c->state.scissor.bottom);
- if ((minx >= maxx) || (miny >= maxy))
- return; // too small or clipped out...
-
- // step equations to the bounding box and snap to pixel center
- const int32_t my = (miny << TRI_FRACTION_BITS) + TRI_HALF;
- const int32_t mx = (minx << TRI_FRACTION_BITS) + TRI_HALF;
- int32_t ey0 = dy01 * (x0 - mx) - dx01 * (y0 - my);
- int32_t ey1 = dy12 * (x1 - mx) - dx12 * (y1 - my);
- int32_t ey2 = dy20 * (x2 - mx) - dx20 * (y2 - my);
-
- // right-exclusive fill rule, to avoid rare cases
- // of over drawing
- if (dy01<0 || (dy01 == 0 && dx01>0)) ey0++;
- if (dy12<0 || (dy12 == 0 && dx12>0)) ey1++;
- if (dy20<0 || (dy20 == 0 && dx20>0)) ey2++;
-
- c->init_y(c, miny);
- for (int32_t y = miny; y < maxy; y++) {
- int32_t ex0 = ey0;
- int32_t ex1 = ey1;
- int32_t ex2 = ey2;
- int32_t xl, xr;
- for (xl=minx ; xl<maxx ; xl++) {
- if (ex0>0 && ex1>0 && ex2>0)
- break; // all strictly positive
- ex0 -= dy01 << TRI_FRACTION_BITS;
- ex1 -= dy12 << TRI_FRACTION_BITS;
- ex2 -= dy20 << TRI_FRACTION_BITS;
- }
- xr = xl;
- for ( ; xr<maxx ; xr++) {
- if (!(ex0>0 && ex1>0 && ex2>0))
- break; // not all strictly positive
- ex0 -= dy01 << TRI_FRACTION_BITS;
- ex1 -= dy12 << TRI_FRACTION_BITS;
- ex2 -= dy20 << TRI_FRACTION_BITS;
- }
-
- if (xl < xr) {
- c->iterators.xl = xl;
- c->iterators.xr = xr;
- c->scanline(c);
- }
- c->step_y(c);
-
- ey0 += dx01 << TRI_FRACTION_BITS;
- ey1 += dx12 << TRI_FRACTION_BITS;
- ey2 += dx20 << TRI_FRACTION_BITS;
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-// the following routine fills a triangle via edge stepping, which
-// unfortunately requires divisions in the setup phase to get right,
-// it should probably only be used for relatively large trianges
-
-
-// x = y*DX/DY (ou DX and DY are constants, DY > 0, et y >= 0)
-//
-// for an equation of the type:
-// x' = y*K/2^p (with K and p constants "carefully chosen")
-//
-// We can now do a DDA without precision loss. We define 'e' by:
-// x' - x = y*(DX/DY - K/2^p) = y*e
-//
-// If we choose K = round(DX*2^p/DY) then,
-// abs(e) <= 1/2^(p+1) by construction
-//
-// therefore abs(x'-x) = y*abs(e) <= y/2^(p+1) <= DY/2^(p+1) <= DMAX/2^(p+1)
-//
-// which means that if DMAX <= 2^p, therefore abs(x-x') <= 1/2, including
-// at the last line. In fact, it's even a strict inequality except in one
-// extrem case (DY == DMAX et e = +/- 1/2)
-//
-// Applying that to our coordinates, we need 2^p >= 4096*16 = 65536
-// so p = 16 is enough, we're so lucky!
-
-const int TRI_ITERATORS_BITS = 16;
-
-struct Edge
-{
- int32_t x; // edge position in 16.16 coordinates
- int32_t x_incr; // on each step, increment x by that amount
- int32_t y_top; // starting scanline, 16.4 format
- int32_t y_bot;
-};
-
-static void
-edge_dump( Edge* edge )
-{
- ALOGI( " top=%d (%.3f) bot=%d (%.3f) x=%d (%.3f) ix=%d (%.3f)",
- edge->y_top, edge->y_top/float(TRI_ONE),
- edge->y_bot, edge->y_bot/float(TRI_ONE),
- edge->x, edge->x/float(FIXED_ONE),
- edge->x_incr, edge->x_incr/float(FIXED_ONE) );
-}
-
-static void
-triangle_dump_edges( Edge* edges,
- int count )
-{
- ALOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" );
- for ( ; count > 0; count--, edges++ )
- edge_dump( edges );
-}
-
-// the following function sets up an edge, it assumes
-// that ymin and ymax are in already in the 'reduced'
-// format
-static __attribute__((noinline))
-void edge_setup(
- Edge* edges,
- int* pcount,
- const GGLcoord* p1,
- const GGLcoord* p2,
- int32_t ymin,
- int32_t ymax )
-{
- const GGLfixed* top = p1;
- const GGLfixed* bot = p2;
- Edge* edge = edges + *pcount;
-
- if (top[1] > bot[1]) {
- swap(top, bot);
- }
-
- int y1 = top[1] | 1;
- int y2 = bot[1] | 1;
- int dy = y2 - y1;
-
- if ( dy == 0 || y1 > ymax || y2 < ymin )
- return;
-
- if ( y1 > ymin )
- ymin = TRI_SNAP_NEXT_HALF(y1);
-
- if ( y2 < ymax )
- ymax = TRI_SNAP_PREV_HALF(y2);
-
- if ( ymin > ymax ) // when the edge doesn't cross any scanline
- return;
-
- const int x1 = top[0];
- const int dx = bot[0] - x1;
- const int shift = TRI_ITERATORS_BITS - TRI_FRACTION_BITS;
-
- // setup edge fields
- // We add 0.5 to edge->x here because it simplifies the rounding
- // in triangle_sweep_edges() -- this doesn't change the ordering of 'x'
- edge->x = (x1 << shift) + (1LU << (TRI_ITERATORS_BITS-1));
- edge->x_incr = 0;
- edge->y_top = ymin;
- edge->y_bot = ymax;
-
- if (ggl_likely(ymin <= ymax && dx)) {
- edge->x_incr = gglDivQ16(dx, dy);
- }
- if (ggl_likely(y1 < ymin)) {
- int32_t xadjust = (edge->x_incr * (ymin-y1)) >> TRI_FRACTION_BITS;
- edge->x += xadjust;
- }
-
- ++*pcount;
-}
-
-
-static void
-triangle_sweep_edges( Edge* left,
- Edge* right,
- int ytop,
- int ybot,
- context_t* c )
-{
- int count = ((ybot - ytop)>>TRI_FRACTION_BITS) + 1;
- if (count<=0) return;
-
- // sort the edges horizontally
- if ((left->x > right->x) ||
- ((left->x == right->x) && (left->x_incr > right->x_incr))) {
- swap(left, right);
- }
-
- int left_x = left->x;
- int right_x = right->x;
- const int left_xi = left->x_incr;
- const int right_xi = right->x_incr;
- left->x += left_xi * count;
- right->x += right_xi * count;
-
- const int xmin = c->state.scissor.left;
- const int xmax = c->state.scissor.right;
- do {
- // horizontal scissoring
- const int32_t xl = max(left_x >> TRI_ITERATORS_BITS, xmin);
- const int32_t xr = min(right_x >> TRI_ITERATORS_BITS, xmax);
- left_x += left_xi;
- right_x += right_xi;
- // invoke the scanline rasterizer
- if (ggl_likely(xl < xr)) {
- c->iterators.xl = xl;
- c->iterators.xr = xr;
- c->scanline(c);
- }
- c->step_y(c);
- } while (--count);
-}
-
-
-void trianglex_big(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
-
- Edge edges[3];
- int num_edges = 0;
- int32_t ymin = TRI_FROM_INT(c->state.scissor.top) + TRI_HALF;
- int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom) - TRI_HALF;
-
- edge_setup( edges, &num_edges, v0, v1, ymin, ymax );
- edge_setup( edges, &num_edges, v0, v2, ymin, ymax );
- edge_setup( edges, &num_edges, v1, v2, ymin, ymax );
-
- if (ggl_unlikely(num_edges<2)) // for really tiny triangles that don't
- return; // cross any scanline centers
-
- Edge* left = &edges[0];
- Edge* right = &edges[1];
- Edge* other = &edges[2];
- int32_t y_top = min(left->y_top, right->y_top);
- int32_t y_bot = max(left->y_bot, right->y_bot);
-
- if (ggl_likely(num_edges==3)) {
- y_top = min(y_top, edges[2].y_top);
- y_bot = max(y_bot, edges[2].y_bot);
- if (edges[0].y_top > y_top) {
- other = &edges[0];
- left = &edges[2];
- } else if (edges[1].y_top > y_top) {
- other = &edges[1];
- right = &edges[2];
- }
- }
-
- c->init_y(c, y_top >> TRI_FRACTION_BITS);
-
- int32_t y_mid = min(left->y_bot, right->y_bot);
- triangle_sweep_edges( left, right, y_top, y_mid, c );
-
- // second scanline sweep loop, if necessary
- y_mid += TRI_ONE;
- if (y_mid <= y_bot) {
- ((left->y_bot == y_bot) ? right : left) = other;
- if (other->y_top < y_mid) {
- other->x += other->x_incr;
- }
- triangle_sweep_edges( left, right, y_mid, y_bot, c );
- }
-}
-
-void aa_trianglex(void* con,
- const GGLcoord* a, const GGLcoord* b, const GGLcoord* c)
-{
- GGLcoord pts[6] = { a[0], a[1], b[0], b[1], c[0], c[1] };
- aapolyx(con, pts, 3);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-struct AAEdge
-{
- GGLfixed x; // edge position in 12.16 coordinates
- GGLfixed x_incr; // on each y step, increment x by that amount
- GGLfixed y_incr; // on each x step, increment y by that amount
- int16_t y_top; // starting scanline, 12.4 format
- int16_t y_bot; // starting scanline, 12.4 format
- void dump();
-};
-
-void AAEdge::dump()
-{
- float tri = 1.0f / TRI_ONE;
- float iter = 1.0f / (1<<TRI_ITERATORS_BITS);
- float fix = 1.0f / FIXED_ONE;
- ALOGD( "x=%08x (%.3f), "
- "x_incr=%08x (%.3f), y_incr=%08x (%.3f), "
- "y_top=%08x (%.3f), y_bot=%08x (%.3f) ",
- x, x*fix,
- x_incr, x_incr*iter,
- y_incr, y_incr*iter,
- y_top, y_top*tri,
- y_bot, y_bot*tri );
-}
-
-// the following function sets up an edge, it assumes
-// that ymin and ymax are in already in the 'reduced'
-// format
-static __attribute__((noinline))
-void aa_edge_setup(
- AAEdge* edges,
- int* pcount,
- const GGLcoord* p1,
- const GGLcoord* p2,
- int32_t ymin,
- int32_t ymax )
-{
- const GGLfixed* top = p1;
- const GGLfixed* bot = p2;
- AAEdge* edge = edges + *pcount;
-
- if (top[1] > bot[1])
- swap(top, bot);
-
- int y1 = top[1];
- int y2 = bot[1];
- int dy = y2 - y1;
-
- if (dy==0 || y1>ymax || y2<ymin)
- return;
-
- if (y1 > ymin)
- ymin = y1;
-
- if (y2 < ymax)
- ymax = y2;
-
- const int x1 = top[0];
- const int dx = bot[0] - x1;
- const int shift = FIXED_BITS - TRI_FRACTION_BITS;
-
- // setup edge fields
- edge->x = x1 << shift;
- edge->x_incr = 0;
- edge->y_top = ymin;
- edge->y_bot = ymax;
- edge->y_incr = 0x7FFFFFFF;
-
- if (ggl_likely(ymin <= ymax && dx)) {
- edge->x_incr = gglDivQ16(dx, dy);
- if (dx != 0) {
- edge->y_incr = abs(gglDivQ16(dy, dx));
- }
- }
- if (ggl_likely(y1 < ymin)) {
- int32_t xadjust = (edge->x_incr * (ymin-y1))
- >> (TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS);
- edge->x += xadjust;
- }
-
- ++*pcount;
-}
-
-
-typedef int (*compar_t)(const void*, const void*);
-static int compare_edges(const AAEdge *e0, const AAEdge *e1) {
- if (e0->y_top > e1->y_top) return 1;
- if (e0->y_top < e1->y_top) return -1;
- if (e0->x > e1->x) return 1;
- if (e0->x < e1->x) return -1;
- if (e0->x_incr > e1->x_incr) return 1;
- if (e0->x_incr < e1->x_incr) return -1;
- return 0; // same edges, should never happen
-}
-
-static inline
-void SET_COVERAGE(int16_t*& p, int32_t value, ssize_t n)
-{
- android_memset16((uint16_t*)p, value, n*2);
- p += n;
-}
-
-static inline
-void ADD_COVERAGE(int16_t*& p, int32_t value)
-{
- value = *p + value;
- if (value >= 0x8000)
- value = 0x7FFF;
- *p++ = value;
-}
-
-static inline
-void SUB_COVERAGE(int16_t*& p, int32_t value)
-{
- value = *p - value;
- value &= ~(value>>31);
- *p++ = value;
-}
-
-void aapolyx(void* con,
- const GGLcoord* pts, int count)
-{
- /*
- * NOTE: This routine assumes that the polygon has been clipped to the
- * viewport already, that is, no vertex lies outside of the framebuffer.
- * If this happens, the code below won't corrupt memory but the
- * coverage values may not be correct.
- */
-
- GGL_CONTEXT(c, con);
-
- // we do only quads for now (it's used for thick lines)
- if ((count>4) || (count<2)) return;
-
- // take scissor into account
- const int xmin = c->state.scissor.left;
- const int xmax = c->state.scissor.right;
- if (xmin >= xmax) return;
-
- // generate edges from the vertices
- int32_t ymin = TRI_FROM_INT(c->state.scissor.top);
- int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom);
- if (ymin >= ymax) return;
-
- AAEdge edges[4];
- int num_edges = 0;
- GGLcoord const * p = pts;
- for (int i=0 ; i<count-1 ; i++, p+=2) {
- aa_edge_setup(edges, &num_edges, p, p+2, ymin, ymax);
- }
- aa_edge_setup(edges, &num_edges, p, pts, ymin, ymax );
- if (ggl_unlikely(num_edges<2))
- return;
-
- // sort the edge list top to bottom, left to right.
- qsort(edges, num_edges, sizeof(AAEdge), (compar_t)compare_edges);
-
- int16_t* const covPtr = c->state.buffers.coverage;
- memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
-
- // now, sweep all edges in order
- // start with the 2 first edges. We know that they share their top
- // vertex, by construction.
- int i = 2;
- AAEdge* left = &edges[0];
- AAEdge* right = &edges[1];
- int32_t yt = left->y_top;
- GGLfixed l = left->x;
- GGLfixed r = right->x;
- int retire = 0;
- int16_t* coverage;
-
- // at this point we can initialize the rasterizer
- c->init_y(c, yt>>TRI_FRACTION_BITS);
- c->iterators.xl = xmax;
- c->iterators.xr = xmin;
-
- do {
- int32_t y = min(min(left->y_bot, right->y_bot), TRI_FLOOR(yt + TRI_ONE));
- const int32_t shift = TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS;
- const int cf_shift = (1 + TRI_FRACTION_BITS*2 + TRI_ITERATORS_BITS - 15);
-
- // compute xmin and xmax for the left edge
- GGLfixed l_min = gglMulAddx(left->x_incr, y - left->y_top, left->x, shift);
- GGLfixed l_max = l;
- l = l_min;
- if (l_min > l_max)
- swap(l_min, l_max);
-
- // compute xmin and xmax for the right edge
- GGLfixed r_min = gglMulAddx(right->x_incr, y - right->y_top, right->x, shift);
- GGLfixed r_max = r;
- r = r_min;
- if (r_min > r_max)
- swap(r_min, r_max);
-
- // make sure we're not touching coverage values outside of the
- // framebuffer
- l_min &= ~(l_min>>31);
- r_min &= ~(r_min>>31);
- l_max &= ~(l_max>>31);
- r_max &= ~(r_max>>31);
- if (gglFixedToIntFloor(l_min) >= xmax) l_min = gglIntToFixed(xmax)-1;
- if (gglFixedToIntFloor(r_min) >= xmax) r_min = gglIntToFixed(xmax)-1;
- if (gglFixedToIntCeil(l_max) >= xmax) l_max = gglIntToFixed(xmax)-1;
- if (gglFixedToIntCeil(r_max) >= xmax) r_max = gglIntToFixed(xmax)-1;
-
- // compute the integer versions of the above
- const GGLfixed l_min_i = gglFloorx(l_min);
- const GGLfixed l_max_i = gglCeilx (l_max);
- const GGLfixed r_min_i = gglFloorx(r_min);
- const GGLfixed r_max_i = gglCeilx (r_max);
-
- // clip horizontally using the scissor
- const int xml = max(xmin, gglFixedToIntFloor(l_min_i));
- const int xmr = min(xmax, gglFixedToIntFloor(r_max_i));
-
- // if we just stepped to a new scanline, render the previous one.
- // and clear the coverage buffer
- if (retire) {
- if (c->iterators.xl < c->iterators.xr)
- c->scanline(c);
- c->step_y(c);
- memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
- c->iterators.xl = xml;
- c->iterators.xr = xmr;
- } else {
- // update the horizontal range of this scanline
- c->iterators.xl = min(c->iterators.xl, xml);
- c->iterators.xr = max(c->iterators.xr, xmr);
- }
-
- coverage = covPtr + gglFixedToIntFloor(l_min_i);
- if (l_min_i == gglFloorx(l_max)) {
-
- /*
- * fully traverse this pixel vertically
- * l_max
- * +-----/--+ yt
- * | / |
- * | / |
- * | / |
- * +-/------+ y
- * l_min (l_min_i + TRI_ONE)
- */
-
- GGLfixed dx = l_max - l_min;
- int32_t dy = y - yt;
- int cf = gglMulx((dx >> 1) + (l_min_i + FIXED_ONE - l_max), dy,
- FIXED_BITS + TRI_FRACTION_BITS - 15);
- ADD_COVERAGE(coverage, cf);
- // all pixels on the right have cf = 1.0
- } else {
- /*
- * spans several pixels in one scanline
- * l_max
- * +--------+--/-----+ yt
- * | |/ |
- * | /| |
- * | / | |
- * +---/----+--------+ y
- * l_min (l_min_i + TRI_ONE)
- */
-
- // handle the first pixel separately...
- const int32_t y_incr = left->y_incr;
- int32_t dx = TRI_FROM_FIXED(l_min_i - l_min) + TRI_ONE;
- int32_t cf = (dx * dx * y_incr) >> cf_shift;
- ADD_COVERAGE(coverage, cf);
-
- // following pixels get covered by y_incr, but we need
- // to fix-up the cf to account for previous partial pixel
- dx = TRI_FROM_FIXED(l_min - l_min_i);
- cf -= (dx * dx * y_incr) >> cf_shift;
- for (int x = l_min_i+FIXED_ONE ; x < l_max_i-FIXED_ONE ; x += FIXED_ONE) {
- cf += y_incr >> (TRI_ITERATORS_BITS-15);
- ADD_COVERAGE(coverage, cf);
- }
-
- // and the last pixel
- dx = TRI_FROM_FIXED(l_max - l_max_i) - TRI_ONE;
- cf += (dx * dx * y_incr) >> cf_shift;
- ADD_COVERAGE(coverage, cf);
- }
-
- // now, fill up all fully covered pixels
- coverage = covPtr + gglFixedToIntFloor(l_max_i);
- int cf = ((y - yt) << (15 - TRI_FRACTION_BITS));
- if (ggl_likely(cf >= 0x8000)) {
- SET_COVERAGE(coverage, 0x7FFF, ((r_max - l_max_i)>>FIXED_BITS)+1);
- } else {
- for (int x=l_max_i ; x<r_max ; x+=FIXED_ONE) {
- ADD_COVERAGE(coverage, cf);
- }
- }
-
- // subtract the coverage of the right edge
- coverage = covPtr + gglFixedToIntFloor(r_min_i);
- if (r_min_i == gglFloorx(r_max)) {
- GGLfixed dx = r_max - r_min;
- int32_t dy = y - yt;
- int cf = gglMulx((dx >> 1) + (r_min_i + FIXED_ONE - r_max), dy,
- FIXED_BITS + TRI_FRACTION_BITS - 15);
- SUB_COVERAGE(coverage, cf);
- // all pixels on the right have cf = 1.0
- } else {
- // handle the first pixel separately...
- const int32_t y_incr = right->y_incr;
- int32_t dx = TRI_FROM_FIXED(r_min_i - r_min) + TRI_ONE;
- int32_t cf = (dx * dx * y_incr) >> cf_shift;
- SUB_COVERAGE(coverage, cf);
-
- // following pixels get covered by y_incr, but we need
- // to fix-up the cf to account for previous partial pixel
- dx = TRI_FROM_FIXED(r_min - r_min_i);
- cf -= (dx * dx * y_incr) >> cf_shift;
- for (int x = r_min_i+FIXED_ONE ; x < r_max_i-FIXED_ONE ; x += FIXED_ONE) {
- cf += y_incr >> (TRI_ITERATORS_BITS-15);
- SUB_COVERAGE(coverage, cf);
- }
-
- // and the last pixel
- dx = TRI_FROM_FIXED(r_max - r_max_i) - TRI_ONE;
- cf += (dx * dx * y_incr) >> cf_shift;
- SUB_COVERAGE(coverage, cf);
- }
-
- // did we reach the end of an edge? if so, get a new one.
- if (y == left->y_bot || y == right->y_bot) {
- // bail out if we're done
- if (i>=num_edges)
- break;
- if (y == left->y_bot)
- left = &edges[i++];
- if (y == right->y_bot)
- right = &edges[i++];
- }
-
- // next scanline
- yt = y;
-
- // did we just finish a scanline?
- retire = (y << (32-TRI_FRACTION_BITS)) == 0;
- } while (true);
-
- // render the last scanline
- if (c->iterators.xl < c->iterators.xr)
- c->scanline(c);
-}
-
-}; // namespace android
diff --git a/libpixelflinger/trap.h b/libpixelflinger/trap.h
deleted file mode 100644
index 7cce7b3..0000000
--- a/libpixelflinger/trap.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* libs/pixelflinger/trap.h
-**
-** Copyright 2006, 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 ANDROID_TRAP_H
-#define ANDROID_TRAP_H
-
-#include <private/pixelflinger/ggl_context.h>
-
-namespace android {
-
-void ggl_init_trap(context_t* c);
-void ggl_state_changed(context_t* c, int flags);
-
-}; // namespace android
-
-#endif
diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp
index ccc6f62..c371ef7 100644
--- a/libprocessgroup/profiles/Android.bp
+++ b/libprocessgroup/profiles/Android.bp
@@ -104,8 +104,3 @@
"vts",
],
}
-
-vts_config {
- name: "VtsProcessgroupValidateTest",
- test_config: "vts_processgroup_validate_test.xml",
-}
diff --git a/libprocessgroup/profiles/vts_processgroup_validate_test.xml b/libprocessgroup/profiles/vts_processgroup_validate_test.xml
deleted file mode 100644
index 21d29cd..0000000
--- a/libprocessgroup/profiles/vts_processgroup_validate_test.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?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 VtsProcessgroupValidateTest">
- <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
- <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="VtsProcessgroupValidateTest"/>
- <option name="binary-test-working-directory" value="_32bit::/data/nativetest/" />
- <option name="binary-test-working-directory" value="_64bit::/data/nativetest64/" />
- <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_processgroup_validate_test/vts_processgroup_validate_test" />
- <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_processgroup_validate_test/vts_processgroup_validate_test" />
- <option name="binary-test-type" value="gtest"/>
- <option name="binary-test-disable-framework" value="false"/>
- <option name="test-timeout" value="30s"/>
- </test>
-</configuration>
diff --git a/libprocinfo b/libprocinfo
new file mode 120000
index 0000000..dec8cf8
--- /dev/null
+++ b/libprocinfo
@@ -0,0 +1 @@
+../libprocinfo
\ No newline at end of file
diff --git a/libprocinfo/.clang-format b/libprocinfo/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/libprocinfo/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/libprocinfo/Android.bp b/libprocinfo/Android.bp
deleted file mode 100644
index ae45742..0000000
--- a/libprocinfo/Android.bp
+++ /dev/null
@@ -1,131 +0,0 @@
-//
-// Copyright (C) 2015 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.
-//
-
-cc_defaults {
- name: "libprocinfo_defaults",
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- ],
-}
-
-cc_library {
- name: "libprocinfo",
- defaults: ["libprocinfo_defaults"],
- vendor_available: true,
- // TODO(b/153609531): remove when no longer needed.
- native_bridge_supported: true,
- recovery_available: true,
- vndk: {
- enabled: true,
- },
- host_supported: true,
- srcs: [
- "process.cpp",
- "process_map.cpp",
- ],
-
- local_include_dirs: ["include"],
- export_include_dirs: ["include"],
- shared_libs: ["libbase"],
- target: {
- darwin: {
- enabled: false,
- },
- linux_bionic: {
- enabled: true,
- },
- windows: {
- enabled: false,
- },
- },
-
- apex_available: [
- "//apex_available:platform",
- "com.android.art.debug",
- "com.android.art.release",
- ],
-}
-
-// Tests
-// ------------------------------------------------------------------------------
-cc_test {
- name: "libprocinfo_test",
- defaults: ["libprocinfo_defaults"],
- host_supported: true,
- isolated: true,
- srcs: [
- "process_test.cpp",
- "process_map_test.cpp",
- ],
- target: {
- darwin: {
- enabled: false,
- },
- windows: {
- enabled: false,
- },
- },
-
- shared_libs: [
- "libbase",
- "libprocinfo",
- ],
-
- compile_multilib: "both",
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
-
- data: [
- "testdata/*",
- ],
-
- test_suites: ["device-tests"],
-}
-
-cc_benchmark {
- name: "libprocinfo_benchmark",
- defaults: ["libprocinfo_defaults"],
- srcs: [
- "process_map_benchmark.cpp",
- ],
- shared_libs: [
- "libbacktrace",
- "libbase",
- "libprocinfo",
- "libunwindstack",
- ],
- compile_multilib: "both",
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
-
- data: [
- "testdata/*",
- ],
-}
diff --git a/libprocinfo/OWNERS b/libprocinfo/OWNERS
deleted file mode 100644
index a70cc57..0000000
--- a/libprocinfo/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-jmgao@google.com
diff --git a/libprocinfo/include/procinfo/process.h b/libprocinfo/include/procinfo/process.h
deleted file mode 100644
index 9278e18..0000000
--- a/libprocinfo/include/procinfo/process.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-#include <type_traits>
-
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/unique_fd.h>
-
-namespace android {
-namespace procinfo {
-
-#if defined(__linux__)
-
-enum ProcessState {
- kProcessStateUnknown,
- kProcessStateRunning,
- kProcessStateSleeping,
- kProcessStateUninterruptibleWait,
- kProcessStateStopped,
- kProcessStateZombie,
-};
-
-struct ProcessInfo {
- std::string name;
- ProcessState state;
- pid_t tid;
- pid_t pid;
- pid_t ppid;
- pid_t tracer;
- uid_t uid;
- uid_t gid;
-};
-
-// Parse the contents of /proc/<tid>/status into |process_info|.
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error = nullptr);
-
-// Parse the contents of <fd>/status into |process_info|.
-// |fd| should be an fd pointing at a /proc/<pid> directory.
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error = nullptr);
-
-// Fetch the list of threads from a given process's /proc/<pid> directory.
-// |fd| should be an fd pointing at a /proc/<pid> directory.
-template <typename Collection>
-auto GetProcessTidsFromProcPidFd(int fd, Collection* out, std::string* error = nullptr) ->
- typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
- out->clear();
-
- int task_fd = openat(fd, "task", O_DIRECTORY | O_RDONLY | O_CLOEXEC);
- std::unique_ptr<DIR, int (*)(DIR*)> dir(fdopendir(task_fd), closedir);
- if (!dir) {
- if (error != nullptr) {
- *error = "failed to open task directory";
- }
- return false;
- }
-
- struct dirent* dent;
- while ((dent = readdir(dir.get()))) {
- if (strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0) {
- pid_t tid;
- if (!android::base::ParseInt(dent->d_name, &tid, 1, std::numeric_limits<pid_t>::max())) {
- if (error != nullptr) {
- *error = std::string("failed to parse task id: ") + dent->d_name;
- }
- return false;
- }
-
- out->insert(out->end(), tid);
- }
- }
-
- return true;
-}
-
-template <typename Collection>
-auto GetProcessTids(pid_t pid, Collection* out, std::string* error = nullptr) ->
- typename std::enable_if<sizeof(typename Collection::value_type) >= sizeof(pid_t), bool>::type {
- char task_path[PATH_MAX];
- if (snprintf(task_path, PATH_MAX, "/proc/%d", pid) >= PATH_MAX) {
- if (error != nullptr) {
- *error = "task path overflow (pid = " + std::to_string(pid) + ")";
- }
- return false;
- }
-
- android::base::unique_fd fd(open(task_path, O_DIRECTORY | O_RDONLY | O_CLOEXEC));
- if (fd == -1) {
- if (error != nullptr) {
- *error = std::string("failed to open ") + task_path;
- }
- return false;
- }
-
- return GetProcessTidsFromProcPidFd(fd.get(), out, error);
-}
-
-#endif
-
-} /* namespace procinfo */
-} /* namespace android */
diff --git a/libprocinfo/include/procinfo/process_map.h b/libprocinfo/include/procinfo/process_map.h
deleted file mode 100644
index 569a022..0000000
--- a/libprocinfo/include/procinfo/process_map.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-
-#include <functional>
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-
-namespace android {
-namespace procinfo {
-
-template <class CallbackType>
-bool ReadMapFileContent(char* content, const CallbackType& callback) {
- uint64_t start_addr;
- uint64_t end_addr;
- uint16_t flags;
- uint64_t pgoff;
- ino_t inode;
- char* next_line = content;
- char* p;
-
- auto pass_space = [&]() {
- if (*p != ' ') {
- return false;
- }
- while (*p == ' ') {
- p++;
- }
- return true;
- };
-
- auto pass_xdigit = [&]() {
- if (!isxdigit(*p)) {
- return false;
- }
- do {
- p++;
- } while (isxdigit(*p));
- return true;
- };
-
- while (next_line != nullptr && *next_line != '\0') {
- p = next_line;
- next_line = strchr(next_line, '\n');
- if (next_line != nullptr) {
- *next_line = '\0';
- next_line++;
- }
- // Parse line like: 00400000-00409000 r-xp 00000000 fc:00 426998 /usr/lib/gvfs/gvfsd-http
- char* end;
- // start_addr
- start_addr = strtoull(p, &end, 16);
- if (end == p || *end != '-') {
- return false;
- }
- p = end + 1;
- // end_addr
- end_addr = strtoull(p, &end, 16);
- if (end == p) {
- return false;
- }
- p = end;
- if (!pass_space()) {
- return false;
- }
- // flags
- flags = 0;
- if (*p == 'r') {
- flags |= PROT_READ;
- } else if (*p != '-') {
- return false;
- }
- p++;
- if (*p == 'w') {
- flags |= PROT_WRITE;
- } else if (*p != '-') {
- return false;
- }
- p++;
- if (*p == 'x') {
- flags |= PROT_EXEC;
- } else if (*p != '-') {
- return false;
- }
- p++;
- if (*p != 'p' && *p != 's') {
- return false;
- }
- p++;
- if (!pass_space()) {
- return false;
- }
- // pgoff
- pgoff = strtoull(p, &end, 16);
- if (end == p) {
- return false;
- }
- p = end;
- if (!pass_space()) {
- return false;
- }
- // major:minor
- if (!pass_xdigit() || *p++ != ':' || !pass_xdigit() || !pass_space()) {
- return false;
- }
- // inode
- inode = strtoull(p, &end, 10);
- if (end == p) {
- return false;
- }
- p = end;
-
- if (*p != '\0' && !pass_space()) {
- return false;
- }
-
- // filename
- callback(start_addr, end_addr, flags, pgoff, inode, p);
- }
- return true;
-}
-
-inline bool ReadMapFile(const std::string& map_file,
- const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
- const char*)>& callback) {
- std::string content;
- if (!android::base::ReadFileToString(map_file, &content)) {
- return false;
- }
- return ReadMapFileContent(&content[0], callback);
-}
-
-inline bool ReadProcessMaps(pid_t pid,
- const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
- const char*)>& callback) {
- return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
-}
-
-struct MapInfo {
- uint64_t start;
- uint64_t end;
- uint16_t flags;
- uint64_t pgoff;
- ino_t inode;
- std::string name;
-
- MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
- const char* name)
- : start(start), end(end), flags(flags), pgoff(pgoff), inode(inode), name(name) {}
-};
-
-inline bool ReadProcessMaps(pid_t pid, std::vector<MapInfo>* maps) {
- return ReadProcessMaps(
- pid, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
- const char* name) { maps->emplace_back(start, end, flags, pgoff, inode, name); });
-}
-
-bool ReadMapFileAsyncSafe(const char* map_file, void* buffer, size_t buffer_size,
- const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
- const char*)>& callback);
-
-} /* namespace procinfo */
-} /* namespace android */
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
deleted file mode 100644
index 2efd49c..0000000
--- a/libprocinfo/process.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <procinfo/process.h>
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/unique_fd.h>
-
-using android::base::unique_fd;
-
-namespace android {
-namespace procinfo {
-
-bool GetProcessInfo(pid_t tid, ProcessInfo* process_info, std::string* error) {
- char path[PATH_MAX];
- snprintf(path, sizeof(path), "/proc/%d", tid);
-
- unique_fd dirfd(open(path, O_DIRECTORY | O_RDONLY));
- if (dirfd == -1) {
- if (error != nullptr) {
- *error = std::string("failed to open ") + path;
- }
- return false;
- }
-
- return GetProcessInfoFromProcPidFd(dirfd.get(), process_info, error);
-}
-
-static ProcessState parse_state(const char* state) {
- switch (*state) {
- case 'R':
- return kProcessStateRunning;
- case 'S':
- return kProcessStateSleeping;
- case 'D':
- return kProcessStateUninterruptibleWait;
- case 'T':
- return kProcessStateStopped;
- case 'Z':
- return kProcessStateZombie;
- default:
- return kProcessStateUnknown;
- }
-}
-
-bool GetProcessInfoFromProcPidFd(int fd, ProcessInfo* process_info, std::string* error) {
- int status_fd = openat(fd, "status", O_RDONLY | O_CLOEXEC);
-
- if (status_fd == -1) {
- if (error != nullptr) {
- *error = "failed to open status fd in GetProcessInfoFromProcPidFd";
- }
- return false;
- }
-
- std::unique_ptr<FILE, decltype(&fclose)> fp(fdopen(status_fd, "r"), fclose);
- if (!fp) {
- if (error != nullptr) {
- *error = "failed to open status file in GetProcessInfoFromProcPidFd";
- }
- close(status_fd);
- return false;
- }
-
- int field_bitmap = 0;
- static constexpr int finished_bitmap = 255;
- char* line = nullptr;
- size_t len = 0;
-
- while (getline(&line, &len, fp.get()) != -1 && field_bitmap != finished_bitmap) {
- char* tab = strchr(line, '\t');
- if (tab == nullptr) {
- continue;
- }
-
- size_t header_len = tab - line;
- std::string header = std::string(line, header_len);
- if (header == "Name:") {
- std::string name = line + header_len + 1;
-
- // line includes the trailing newline.
- name.pop_back();
- process_info->name = std::move(name);
-
- field_bitmap |= 1;
- } else if (header == "Pid:") {
- process_info->tid = atoi(tab + 1);
- field_bitmap |= 2;
- } else if (header == "Tgid:") {
- process_info->pid = atoi(tab + 1);
- field_bitmap |= 4;
- } else if (header == "PPid:") {
- process_info->ppid = atoi(tab + 1);
- field_bitmap |= 8;
- } else if (header == "TracerPid:") {
- process_info->tracer = atoi(tab + 1);
- field_bitmap |= 16;
- } else if (header == "Uid:") {
- process_info->uid = atoi(tab + 1);
- field_bitmap |= 32;
- } else if (header == "Gid:") {
- process_info->gid = atoi(tab + 1);
- field_bitmap |= 64;
- } else if (header == "State:") {
- process_info->state = parse_state(tab + 1);
- field_bitmap |= 128;
- }
- }
-
- free(line);
- return field_bitmap == finished_bitmap;
-}
-
-} /* namespace procinfo */
-} /* namespace android */
diff --git a/libprocinfo/process_map.cpp b/libprocinfo/process_map.cpp
deleted file mode 100644
index 5e240b9..0000000
--- a/libprocinfo/process_map.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * 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 <procinfo/process_map.h>
-
-#include <fcntl.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <procinfo/process.h>
-
-namespace android {
-namespace procinfo {
-
-bool ReadMapFileAsyncSafe(const char* map_file, void* buffer, size_t buffer_size,
- const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
- const char*)>& callback) {
- if (buffer == nullptr || buffer_size == 0) {
- return false;
- }
-
- int fd = open(map_file, O_RDONLY | O_CLOEXEC);
- if (fd == -1) {
- return false;
- }
-
- char* char_buffer = reinterpret_cast<char*>(buffer);
- size_t start = 0;
- size_t read_bytes = 0;
- char* line = nullptr;
- bool read_complete = false;
- while (true) {
- ssize_t bytes =
- TEMP_FAILURE_RETRY(read(fd, char_buffer + read_bytes, buffer_size - read_bytes - 1));
- if (bytes <= 0) {
- if (read_bytes == 0) {
- close(fd);
- return bytes == 0;
- }
- // Treat the last piece of data as the last line.
- char_buffer[start + read_bytes] = '\n';
- bytes = 1;
- read_complete = true;
- }
- read_bytes += bytes;
-
- while (read_bytes > 0) {
- char* newline = reinterpret_cast<char*>(memchr(&char_buffer[start], '\n', read_bytes));
- if (newline == nullptr) {
- break;
- }
- *newline = '\0';
- line = &char_buffer[start];
- start = newline - char_buffer + 1;
- read_bytes -= newline - line + 1;
-
- // Ignore the return code, errors are okay.
- ReadMapFileContent(line, callback);
- }
-
- if (read_complete) {
- close(fd);
- return true;
- }
-
- if (start == 0 && read_bytes == buffer_size - 1) {
- // The buffer provided is too small to contain this line, give up
- // and indicate failure.
- close(fd);
- return false;
- }
-
- // Copy any leftover data to the front of the buffer.
- if (start > 0) {
- if (read_bytes > 0) {
- memmove(char_buffer, &char_buffer[start], read_bytes);
- }
- start = 0;
- }
- }
-}
-
-} /* namespace procinfo */
-} /* namespace android */
diff --git a/libprocinfo/process_map_benchmark.cpp b/libprocinfo/process_map_benchmark.cpp
deleted file mode 100644
index eba4fd0..0000000
--- a/libprocinfo/process_map_benchmark.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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 <procinfo/process_map.h>
-
-#include <string.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <backtrace/BacktraceMap.h>
-#include <unwindstack/Maps.h>
-
-#include <benchmark/benchmark.h>
-
-static void BM_ReadMapFile(benchmark::State& state) {
- std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
- for (auto _ : state) {
- std::vector<android::procinfo::MapInfo> maps;
- android::procinfo::ReadMapFile(map_file, [&](uint64_t start, uint64_t end, uint16_t flags,
- uint64_t pgoff, ino_t inode, const char* name) {
- maps.emplace_back(start, end, flags, pgoff, inode, name);
- });
- CHECK_EQ(maps.size(), 2043u);
- }
-}
-BENCHMARK(BM_ReadMapFile);
-
-static void BM_unwindstack_FileMaps(benchmark::State& state) {
- std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
- for (auto _ : state) {
- unwindstack::FileMaps maps(map_file);
- maps.Parse();
- CHECK_EQ(maps.Total(), 2043u);
- }
-}
-BENCHMARK(BM_unwindstack_FileMaps);
-
-static void BM_unwindstack_BufferMaps(benchmark::State& state) {
- std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
- std::string content;
- CHECK(android::base::ReadFileToString(map_file, &content));
- for (auto _ : state) {
- unwindstack::BufferMaps maps(content.c_str());
- maps.Parse();
- CHECK_EQ(maps.Total(), 2043u);
- }
-}
-BENCHMARK(BM_unwindstack_BufferMaps);
-
-static void BM_backtrace_BacktraceMap(benchmark::State& state) {
- pid_t pid = getpid();
- for (auto _ : state) {
- BacktraceMap* map = BacktraceMap::Create(pid, true);
- CHECK(map != nullptr);
- delete map;
- }
-}
-BENCHMARK(BM_backtrace_BacktraceMap);
-
-BENCHMARK_MAIN();
diff --git a/libprocinfo/process_map_test.cpp b/libprocinfo/process_map_test.cpp
deleted file mode 100644
index b1bdc08..0000000
--- a/libprocinfo/process_map_test.cpp
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * 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 <procinfo/process_map.h>
-
-#include <inttypes.h>
-#include <sys/mman.h>
-
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-
-#include <gtest/gtest.h>
-
-TEST(process_map, ReadMapFile) {
- std::string map_file = android::base::GetExecutableDirectory() + "/testdata/maps";
- std::vector<android::procinfo::MapInfo> maps;
- ASSERT_TRUE(android::procinfo::ReadMapFile(
- map_file,
- [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
- const char* name) { maps.emplace_back(start, end, flags, pgoff, inode, name); }));
- ASSERT_EQ(2043u, maps.size());
- ASSERT_EQ(maps[0].start, 0x12c00000ULL);
- ASSERT_EQ(maps[0].end, 0x2ac00000ULL);
- ASSERT_EQ(maps[0].flags, PROT_READ | PROT_WRITE);
- ASSERT_EQ(maps[0].pgoff, 0ULL);
- ASSERT_EQ(maps[0].inode, 10267643UL);
- ASSERT_EQ(maps[0].name, "[anon:dalvik-main space (region space)]");
- ASSERT_EQ(maps[876].start, 0x70e6c4f000ULL);
- ASSERT_EQ(maps[876].end, 0x70e6c6b000ULL);
- ASSERT_EQ(maps[876].flags, PROT_READ | PROT_EXEC);
- ASSERT_EQ(maps[876].pgoff, 0ULL);
- ASSERT_EQ(maps[876].inode, 2407UL);
- ASSERT_EQ(maps[876].name, "/system/lib64/libutils.so");
- ASSERT_EQ(maps[1260].start, 0x70e96fa000ULL);
- ASSERT_EQ(maps[1260].end, 0x70e96fb000ULL);
- ASSERT_EQ(maps[1260].flags, PROT_READ);
- ASSERT_EQ(maps[1260].pgoff, 0ULL);
- ASSERT_EQ(maps[1260].inode, 10266154UL);
- ASSERT_EQ(maps[1260].name,
- "[anon:dalvik-classes.dex extracted in memory from "
- "/data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk]");
-}
-
-TEST(process_map, ReadProcessMaps) {
- std::vector<android::procinfo::MapInfo> maps;
- ASSERT_TRUE(android::procinfo::ReadProcessMaps(
- getpid(),
- [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
- const char* name) { maps.emplace_back(start, end, flags, pgoff, inode, name); }));
- ASSERT_GT(maps.size(), 0u);
- maps.clear();
- ASSERT_TRUE(android::procinfo::ReadProcessMaps(getpid(), &maps));
- ASSERT_GT(maps.size(), 0u);
-}
-
-extern "C" void malloc_disable();
-extern "C" void malloc_enable();
-
-struct TestMapInfo {
- TestMapInfo() = default;
- TestMapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
- const char* new_name)
- : start(start), end(end), flags(flags), pgoff(pgoff), inode(inode) {
- strcpy(name, new_name);
- }
- uint64_t start = 0;
- uint64_t end = 0;
- uint16_t flags = 0;
- uint64_t pgoff = 0;
- ino_t inode = 0;
- char name[100] = {};
-};
-
-void VerifyReadMapFileAsyncSafe(const char* maps_data,
- const std::vector<TestMapInfo>& expected_info) {
- TemporaryFile tf;
- ASSERT_TRUE(android::base::WriteStringToFd(maps_data, tf.fd));
-
- std::vector<TestMapInfo> saved_info(expected_info.size());
- size_t num_maps = 0;
-
- auto callback = [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
- const char* name) {
- if (num_maps != saved_info.size()) {
- TestMapInfo& saved = saved_info[num_maps];
- saved.start = start;
- saved.end = end;
- saved.flags = flags;
- saved.pgoff = pgoff;
- saved.inode = inode;
- strcpy(saved.name, name);
- }
- num_maps++;
- };
-
- std::vector<char> buffer(64 * 1024);
-
-#if defined(__BIONIC__)
- // Any allocations will block after this call.
- malloc_disable();
-#endif
-
- bool parsed =
- android::procinfo::ReadMapFileAsyncSafe(tf.path, buffer.data(), buffer.size(), callback);
-
-#if defined(__BIONIC__)
- malloc_enable();
-#endif
-
- ASSERT_TRUE(parsed) << "Parsing of data failed:\n" << maps_data;
- ASSERT_EQ(expected_info.size(), num_maps);
- for (size_t i = 0; i < expected_info.size(); i++) {
- const TestMapInfo& expected = expected_info[i];
- const TestMapInfo& saved = saved_info[i];
- EXPECT_EQ(expected.start, saved.start);
- EXPECT_EQ(expected.end, saved.end);
- EXPECT_EQ(expected.flags, saved.flags);
- EXPECT_EQ(expected.pgoff, saved.pgoff);
- EXPECT_EQ(expected.inode, saved.inode);
- EXPECT_STREQ(expected.name, saved.name);
- }
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_invalid) {
- std::vector<TestMapInfo> expected_info;
-
- VerifyReadMapFileAsyncSafe("12c00000-2ac00000", expected_info);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_single) {
- std::vector<TestMapInfo> expected_info;
- expected_info.emplace_back(0x12c00000, 0x2ac00000, PROT_READ | PROT_WRITE, 0x100, 10267643,
- "/lib/fake.so");
-
- VerifyReadMapFileAsyncSafe("12c00000-2ac00000 rw-p 00000100 00:05 10267643 /lib/fake.so",
- expected_info);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_single_with_newline) {
- std::vector<TestMapInfo> expected_info;
- expected_info.emplace_back(0x12c00000, 0x2ac00000, PROT_READ | PROT_WRITE, 0x100, 10267643,
- "/lib/fake.so");
-
- VerifyReadMapFileAsyncSafe("12c00000-2ac00000 rw-p 00000100 00:05 10267643 /lib/fake.so\n",
- expected_info);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_single_no_library) {
- std::vector<TestMapInfo> expected_info;
- expected_info.emplace_back(0xa0000, 0xc0000, PROT_READ | PROT_WRITE | PROT_EXEC, 0xb00, 101, "");
-
- VerifyReadMapFileAsyncSafe("a0000-c0000 rwxp 00000b00 00:05 101", expected_info);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_multiple) {
- std::vector<TestMapInfo> expected_info;
- expected_info.emplace_back(0xa0000, 0xc0000, PROT_READ | PROT_WRITE | PROT_EXEC, 1, 100, "");
- expected_info.emplace_back(0xd0000, 0xe0000, PROT_READ, 2, 101, "/lib/libsomething1.so");
- expected_info.emplace_back(0xf0000, 0x100000, PROT_WRITE, 3, 102, "/lib/libsomething2.so");
- expected_info.emplace_back(0x110000, 0x120000, PROT_EXEC, 4, 103, "[anon:something or another]");
-
- std::string map_data =
- "0a0000-0c0000 rwxp 00000001 00:05 100\n"
- "0d0000-0e0000 r--p 00000002 00:05 101 /lib/libsomething1.so\n"
- "0f0000-100000 -w-p 00000003 00:05 102 /lib/libsomething2.so\n"
- "110000-120000 --xp 00000004 00:05 103 [anon:something or another]\n";
-
- VerifyReadMapFileAsyncSafe(map_data.c_str(), expected_info);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_multiple_reads) {
- std::vector<TestMapInfo> expected_info;
- std::string map_data;
- uint64_t start = 0xa0000;
- for (size_t i = 0; i < 10000; i++) {
- map_data += android::base::StringPrintf("%" PRIx64 "-%" PRIx64 " r--p %zx 01:20 %zu fake.so\n",
- start, start + 0x1000, i, 1000 + i);
- expected_info.emplace_back(start, start + 0x1000, PROT_READ, i, 1000 + i, "fake.so");
- }
-
- VerifyReadMapFileAsyncSafe(map_data.c_str(), expected_info);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_buffer_nullptr) {
- size_t num_calls = 0;
- auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
-
-#if defined(__BIONIC__)
- // Any allocations will block after this call.
- malloc_disable();
-#endif
-
- bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", nullptr, 10, callback);
-
-#if defined(__BIONIC__)
- malloc_enable();
-#endif
-
- ASSERT_FALSE(parsed);
- EXPECT_EQ(0UL, num_calls);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_buffer_size_zero) {
- size_t num_calls = 0;
- auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
-
-#if defined(__BIONIC__)
- // Any allocations will block after this call.
- malloc_disable();
-#endif
-
- char buffer[10];
- bool parsed = android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer, 0, callback);
-
-#if defined(__BIONIC__)
- malloc_enable();
-#endif
-
- ASSERT_FALSE(parsed);
- EXPECT_EQ(0UL, num_calls);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_buffer_too_small_no_calls) {
- size_t num_calls = 0;
- auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
-
-#if defined(__BIONIC__)
- // Any allocations will block after this call.
- malloc_disable();
-#endif
-
- char buffer[10];
- bool parsed =
- android::procinfo::ReadMapFileAsyncSafe("/proc/self/maps", buffer, sizeof(buffer), callback);
-
-#if defined(__BIONIC__)
- malloc_enable();
-#endif
-
- ASSERT_FALSE(parsed);
- EXPECT_EQ(0UL, num_calls);
-}
-
-TEST(process_map, ReadMapFileAsyncSafe_buffer_too_small_could_parse) {
- TemporaryFile tf;
- ASSERT_TRUE(android::base::WriteStringToFd(
- "0a0000-0c0000 rwxp 00000001 00:05 100 /fake/lib.so\n", tf.fd));
-
- size_t num_calls = 0;
- auto callback = [&](uint64_t, uint64_t, uint16_t, uint64_t, ino_t, const char*) { num_calls++; };
-
-#if defined(__BIONIC__)
- // Any allocations will block after this call.
- malloc_disable();
-#endif
-
- char buffer[39];
- bool parsed = android::procinfo::ReadMapFileAsyncSafe(tf.path, buffer, sizeof(buffer), callback);
-
-#if defined(__BIONIC__)
- malloc_enable();
-#endif
-
- ASSERT_FALSE(parsed);
- EXPECT_EQ(0UL, num_calls);
-}
diff --git a/libprocinfo/process_test.cpp b/libprocinfo/process_test.cpp
deleted file mode 100644
index 9da9278..0000000
--- a/libprocinfo/process_test.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <procinfo/process.h>
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <set>
-#include <thread>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <android-base/stringprintf.h>
-
-using namespace std::chrono_literals;
-
-#if !defined(__BIONIC__)
-#include <syscall.h>
-static pid_t gettid() {
- return syscall(__NR_gettid);
-}
-#endif
-
-TEST(process_info, process_info_smoke) {
- android::procinfo::ProcessInfo self;
- ASSERT_TRUE(android::procinfo::GetProcessInfo(gettid(), &self));
- ASSERT_EQ(gettid(), self.tid);
- ASSERT_EQ(getpid(), self.pid);
- ASSERT_EQ(getppid(), self.ppid);
- ASSERT_EQ(getuid(), self.uid);
- ASSERT_EQ(getgid(), self.gid);
-}
-
-TEST(process_info, process_info_proc_pid_fd_smoke) {
- android::procinfo::ProcessInfo self;
- int fd = open(android::base::StringPrintf("/proc/%d", gettid()).c_str(), O_DIRECTORY | O_RDONLY);
- ASSERT_NE(-1, fd);
- ASSERT_TRUE(android::procinfo::GetProcessInfoFromProcPidFd(fd, &self));
-
- // Process name is capped at 15 bytes.
- ASSERT_EQ("libprocinfo_tes", self.name);
- ASSERT_EQ(gettid(), self.tid);
- ASSERT_EQ(getpid(), self.pid);
- ASSERT_EQ(getppid(), self.ppid);
- ASSERT_EQ(getuid(), self.uid);
- ASSERT_EQ(getgid(), self.gid);
- close(fd);
-}
-
-TEST(process_info, process_tids_smoke) {
- pid_t main_tid = gettid();
- std::thread([main_tid]() {
- pid_t thread_tid = gettid();
-
- {
- std::vector<pid_t> vec;
- ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &vec));
- ASSERT_EQ(1, std::count(vec.begin(), vec.end(), main_tid));
- ASSERT_EQ(1, std::count(vec.begin(), vec.end(), thread_tid));
- }
-
- {
- std::set<pid_t> set;
- ASSERT_TRUE(android::procinfo::GetProcessTids(getpid(), &set));
- ASSERT_EQ(1, std::count(set.begin(), set.end(), main_tid));
- ASSERT_EQ(1, std::count(set.begin(), set.end(), thread_tid));
- }
- }).join();
-}
-
-TEST(process_info, process_state) {
- int pipefd[2];
- ASSERT_EQ(0, pipe2(pipefd, O_CLOEXEC));
- pid_t forkpid = fork();
-
- ASSERT_NE(-1, forkpid);
- if (forkpid == 0) {
- close(pipefd[1]);
- char buf;
- TEMP_FAILURE_RETRY(read(pipefd[0], &buf, 1));
- _exit(0);
- }
-
- // Give the child some time to get to the read.
- std::this_thread::sleep_for(100ms);
-
- android::procinfo::ProcessInfo procinfo;
- ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
- ASSERT_EQ(android::procinfo::kProcessStateSleeping, procinfo.state);
-
- ASSERT_EQ(0, kill(forkpid, SIGKILL));
-
- // Give the kernel some time to kill the child.
- std::this_thread::sleep_for(100ms);
-
- ASSERT_TRUE(android::procinfo::GetProcessInfo(forkpid, &procinfo));
- ASSERT_EQ(android::procinfo::kProcessStateZombie, procinfo.state);
-
- ASSERT_EQ(forkpid, waitpid(forkpid, nullptr, 0));
-}
diff --git a/libprocinfo/testdata/maps b/libprocinfo/testdata/maps
deleted file mode 100644
index 098cf25..0000000
--- a/libprocinfo/testdata/maps
+++ /dev/null
@@ -1,2043 +0,0 @@
-12c00000-2ac00000 rw-p 00000000 00:05 10267643 [anon:dalvik-main space (region space)]
-6fb5d000-6fd6e000 rw-p 00000000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
-6fd6e000-6fd82000 r--p 00211000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
-6fd82000-6fe47000 rw-p 00000000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
-6fe47000-6fe52000 r--p 000c5000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
-6fe52000-6fe84000 rw-p 00000000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
-6fe84000-6fe87000 r--p 00032000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
-6fe87000-6feb2000 rw-p 00000000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
-6feb2000-6feb5000 r--p 0002b000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
-6feb5000-6fef4000 rw-p 00000000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
-6fef4000-6fefb000 r--p 0003f000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
-6fefb000-6ff3f000 rw-p 00000000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
-6ff3f000-6ff45000 r--p 00044000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
-6ff45000-6ff7a000 rw-p 00000000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
-6ff7a000-6ff85000 r--p 00035000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
-6ff85000-70594000 rw-p 00000000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
-70594000-705cb000 r--p 0060f000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
-705cb000-7061f000 rw-p 00000000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
-7061f000-70629000 r--p 00054000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
-70629000-70635000 rw-p 00000000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
-70635000-70636000 r--p 0000c000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
-70636000-70644000 rw-p 00000000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
-70644000-70645000 r--p 0000e000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
-70645000-70648000 rw-p 00000000 103:1d 639544 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.base-V1.0-java.art
-70648000-7064c000 rw-p 00000000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
-7064c000-7064d000 r--p 00004000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
-7064d000-7064e000 rw-p 00000000 103:1d 639550 /data/dalvik-cache/arm64/system@framework@boot-framework-oahl-backward-compatibility.art
-7064e000-70652000 rw-p 00000000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
-70652000-70653000 r--p 00004000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
-70653000-70654000 rw-p 00000000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
-70654000-70655000 r--p 00001000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
-70655000-70731000 r--p 00000000 fc:00 940 /system/framework/arm64/boot.oat
-70731000-709ca000 r-xp 000dc000 fc:00 940 /system/framework/arm64/boot.oat
-709ca000-709cb000 rw-p 00000000 00:00 0 [anon:.bss]
-709cb000-70e4c000 r--s 00000000 fc:00 961 /system/framework/boot.vdex
-70e4c000-70e4d000 r--p 00375000 fc:00 940 /system/framework/arm64/boot.oat
-70e4d000-70e4e000 rw-p 00376000 fc:00 940 /system/framework/arm64/boot.oat
-70e4e000-70eab000 r--p 00000000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
-70eab000-70fad000 r-xp 0005d000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
-70fad000-70fae000 rw-p 00000000 00:00 0 [anon:.bss]
-70fae000-712a9000 r--s 00000000 fc:00 702 /system/framework/boot-core-libart.vdex
-712a9000-712aa000 r--p 0015f000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
-712aa000-712ab000 rw-p 00160000 fc:00 916 /system/framework/arm64/boot-core-libart.oat
-712ab000-712bb000 r--p 00000000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
-712bb000-712e4000 r-xp 00010000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
-712e4000-712e5000 rw-p 00000000 00:00 0 [anon:.bss]
-712e5000-71346000 r--s 00000000 fc:00 970 /system/framework/boot-conscrypt.vdex
-71346000-71347000 r--p 00039000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
-71347000-71348000 rw-p 0003a000 fc:00 941 /system/framework/arm64/boot-conscrypt.oat
-71348000-71361000 r--p 00000000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
-71361000-713a3000 r-xp 00019000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
-713a3000-713a4000 rw-p 00000000 00:00 0 [anon:.bss]
-713a4000-71403000 r--s 00000000 fc:00 886 /system/framework/boot-okhttp.vdex
-71403000-71404000 r--p 0005b000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
-71404000-71405000 rw-p 0005c000 fc:00 908 /system/framework/arm64/boot-okhttp.oat
-71405000-71415000 r--p 00000000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
-71415000-71437000 r-xp 00010000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
-71437000-71438000 rw-p 00000000 00:00 0 [anon:.bss]
-71438000-7157b000 r--s 00000000 fc:00 1006 /system/framework/boot-bouncycastle.vdex
-7157b000-7157c000 r--p 00032000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
-7157c000-7157d000 rw-p 00033000 fc:00 936 /system/framework/arm64/boot-bouncycastle.oat
-7157d000-71583000 r--p 00000000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
-71583000-71584000 r-xp 00006000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
-71584000-716a7000 r--s 00000000 fc:00 883 /system/framework/boot-apache-xml.vdex
-716a7000-716a8000 r--p 00007000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
-716a8000-716a9000 rw-p 00008000 fc:00 932 /system/framework/arm64/boot-apache-xml.oat
-716a9000-716b5000 r--p 00000000 fc:00 891 /system/framework/arm64/boot-ext.oat
-716b5000-716cc000 r-xp 0000c000 fc:00 891 /system/framework/arm64/boot-ext.oat
-716cc000-716cd000 rw-p 00000000 00:00 0 [anon:.bss]
-716cd000-717b8000 r--s 00000000 fc:00 879 /system/framework/boot-ext.vdex
-717b8000-717b9000 r--p 00023000 fc:00 891 /system/framework/arm64/boot-ext.oat
-717b9000-717ba000 rw-p 00024000 fc:00 891 /system/framework/arm64/boot-ext.oat
-717ba000-71aeb000 r--p 00000000 fc:00 943 /system/framework/arm64/boot-framework.oat
-71aeb000-72390000 r-xp 00331000 fc:00 943 /system/framework/arm64/boot-framework.oat
-72390000-72396000 rw-p 00000000 00:00 0 [anon:.bss]
-72396000-73746000 r--s 00000000 fc:00 985 /system/framework/boot-framework.vdex
-73746000-73747000 r--p 00bd6000 fc:00 943 /system/framework/arm64/boot-framework.oat
-73747000-73748000 rw-p 00bd7000 fc:00 943 /system/framework/arm64/boot-framework.oat
-73748000-73780000 r--p 00000000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
-73780000-73818000 r-xp 00038000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
-73818000-7381a000 rw-p 00000000 00:00 0 [anon:.bss]
-7381a000-73af0000 r--s 00000000 fc:00 697 /system/framework/boot-telephony-common.vdex
-73af0000-73af1000 r--p 000d0000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
-73af1000-73af2000 rw-p 000d1000 fc:00 893 /system/framework/arm64/boot-telephony-common.oat
-73af2000-73af6000 r--p 00000000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
-73af6000-73af8000 r-xp 00004000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
-73af8000-73af9000 rw-p 00000000 00:00 0 [anon:.bss]
-73af9000-73b1e000 r--s 00000000 fc:00 959 /system/framework/boot-voip-common.vdex
-73b1e000-73b1f000 r--p 00006000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
-73b1f000-73b20000 rw-p 00007000 fc:00 922 /system/framework/arm64/boot-voip-common.oat
-73b20000-73b23000 r--p 00000000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
-73b23000-73b25000 r-xp 00003000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
-73b25000-73b26000 rw-p 00000000 00:00 0 [anon:.bss]
-73b26000-73b48000 r--s 00000000 fc:00 957 /system/framework/boot-ims-common.vdex
-73b48000-73b49000 r--p 00005000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
-73b49000-73b4a000 rw-p 00006000 fc:00 918 /system/framework/arm64/boot-ims-common.oat
-73b4a000-73b4d000 r--p 00000000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
-73b4d000-73b4e000 r-xp 00003000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
-73b4e000-73b55000 r--s 00000000 fc:00 972 /system/framework/boot-android.hidl.base-V1.0-java.vdex
-73b55000-73b56000 r--p 00004000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
-73b56000-73b57000 rw-p 00005000 fc:00 909 /system/framework/arm64/boot-android.hidl.base-V1.0-java.oat
-73b57000-73b5a000 r--p 00000000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
-73b5a000-73b5c000 r-xp 00003000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
-73b5c000-73b5d000 rw-p 00000000 00:00 0 [anon:.bss]
-73b5d000-73b68000 r--s 00000000 fc:00 704 /system/framework/boot-android.hidl.manager-V1.0-java.vdex
-73b68000-73b69000 r--p 00005000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
-73b69000-73b6a000 rw-p 00006000 fc:00 954 /system/framework/arm64/boot-android.hidl.manager-V1.0-java.oat
-73b6a000-73b6d000 r--p 00000000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
-73b6d000-73b6e000 r-xp 00003000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
-73b6e000-73b6f000 r--s 00000000 fc:00 994 /system/framework/boot-framework-oahl-backward-compatibility.vdex
-73b6f000-73b70000 r--p 00004000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
-73b70000-73b71000 rw-p 00005000 fc:00 904 /system/framework/arm64/boot-framework-oahl-backward-compatibility.oat
-73b71000-73b75000 r--p 00000000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
-73b75000-73b79000 r-xp 00004000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
-73b79000-73b7a000 rw-p 00000000 00:00 0 [anon:.bss]
-73b7a000-73b82000 r--s 00000000 fc:00 706 /system/framework/boot-android.test.base.vdex
-73b82000-73b83000 r--p 00008000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
-73b83000-73b84000 rw-p 00009000 fc:00 896 /system/framework/arm64/boot-android.test.base.oat
-73b84000-73b87000 r--p 00000000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
-73b87000-73b88000 r-xp 00003000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
-73b88000-73b89000 r--s 00000000 fc:00 884 /system/framework/boot-com.google.vr.platform.vdex
-73b89000-73b8a000 r--p 00004000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
-73b8a000-73b8b000 rw-p 00005000 fc:00 899 /system/framework/arm64/boot-com.google.vr.platform.oat
-73b8b000-73b93000 rw-p 00000000 00:05 10267640 [anon:dalvik-non moving space]
-73b93000-77b8b000 ---p 00008000 00:05 10267640 [anon:dalvik-non moving space]
-77b8b000-97b8b000 rw-p 00000000 00:05 10267645 [anon:dalvik-free list large object space]
-97b8b000-99b8b000 rw-p 00000000 00:05 10270989 [anon:dalvik-data-code-cache]
-99b8b000-9bb8b000 r-xp 00000000 00:05 10270990 [anon:dalvik-jit-code-cache]
-ebad6000-ebad7000 ---p 00000000 00:05 10269717 [anon:dalvik-Sentinel fault page]
-7ffb6e000-7ffb76000 rw-s 000e5000 00:10 20630 /dev/kgsl-3d0
-7ffb76000-7ffb78000 rw-s 000e0000 00:10 20630 /dev/kgsl-3d0
-7ffbc3000-7ffbc4000 rw-s 000e8000 00:10 20630 /dev/kgsl-3d0
-7ffbc4000-7ffbc5000 rw-s 000e7000 00:10 20630 /dev/kgsl-3d0
-7ffbc6000-7ffbce000 rw-s 000e4000 00:10 20630 /dev/kgsl-3d0
-7ffbd0000-7ffbd2000 rw-s 000df000 00:10 20630 /dev/kgsl-3d0
-7ffbd2000-7ffbd4000 rw-s 000de000 00:10 20630 /dev/kgsl-3d0
-7ffbd4000-7ffbd6000 rw-s 000dd000 00:10 20630 /dev/kgsl-3d0
-7ffbd6000-7ffbd8000 rw-s 000dc000 00:10 20630 /dev/kgsl-3d0
-7ffbd8000-7ffbda000 rw-s 000db000 00:10 20630 /dev/kgsl-3d0
-7ffbda000-7ffbdc000 rw-s 000da000 00:10 20630 /dev/kgsl-3d0
-7ffbdd000-7ffbde000 rw-s 000ec000 00:10 20630 /dev/kgsl-3d0
-7ffbde000-7ffbe0000 rw-s 000d8000 00:10 20630 /dev/kgsl-3d0
-7ffce1000-7ffce2000 rw-s 000e6000 00:10 20630 /dev/kgsl-3d0
-7ffce2000-7ffce4000 rw-s 000d9000 00:10 20630 /dev/kgsl-3d0
-7ffce4000-7ffce8000 rw-s 000d4000 00:10 20630 /dev/kgsl-3d0
-7ffce8000-7ffcf8000 rw-s 000d2000 00:10 20630 /dev/kgsl-3d0
-7ffcf8000-7ffd08000 rw-s 000d1000 00:10 20630 /dev/kgsl-3d0
-7ffd08000-7ffd10000 rw-s 000d0000 00:10 20630 /dev/kgsl-3d0
-7ffd14000-7ffd18000 rw-s 000cd000 00:10 20630 /dev/kgsl-3d0
-7ffd18000-7ffd28000 rw-s 000cc000 00:10 20630 /dev/kgsl-3d0
-7ffd28000-7ffd38000 rw-s 000cb000 00:10 20630 /dev/kgsl-3d0
-7ffd38000-7ffd48000 rw-s 000ca000 00:10 20630 /dev/kgsl-3d0
-7ffd48000-7ffd58000 rw-s 000c9000 00:10 20630 /dev/kgsl-3d0
-7ffd58000-7ffd68000 rw-s 000c8000 00:10 20630 /dev/kgsl-3d0
-7ffd68000-7ffd6c000 rw-s 000c7000 00:10 20630 /dev/kgsl-3d0
-7ffdb1000-7ffdb2000 rw-s 000e3000 00:10 20630 /dev/kgsl-3d0
-7ffdb4000-7ffdb5000 rw-s 000e2000 00:10 20630 /dev/kgsl-3d0
-7ffdb5000-7ffdb7000 rw-s 000d7000 00:10 20630 /dev/kgsl-3d0
-7ffdb7000-7ffdb8000 rw-s 000c2000 00:10 20630 /dev/kgsl-3d0
-7ffdb8000-7ffdbc000 rw-s 000c0000 00:10 20630 /dev/kgsl-3d0
-7ffdbc000-7ffdc0000 rw-s 000be000 00:10 20630 /dev/kgsl-3d0
-7ffdc0000-7ffe00000 rw-s 000bb000 00:10 20630 /dev/kgsl-3d0
-7ffe00000-7ffe20000 rw-s 000ba000 00:10 20630 /dev/kgsl-3d0
-7ffe20000-7ffee0000 rw-s 000b9000 00:10 20630 /dev/kgsl-3d0
-7ffee1000-7ffee3000 rw-s 000c1000 00:10 20630 /dev/kgsl-3d0
-7ffee3000-7ffee4000 rw-s 000bf000 00:10 20630 /dev/kgsl-3d0
-7ffee4000-7ffee8000 rw-s 000bd000 00:10 20630 /dev/kgsl-3d0
-7ffee8000-7ffee9000 rw-s 000bc000 00:10 20630 /dev/kgsl-3d0
-7ffeea000-7ffeeb000 rw-s 000e1000 00:10 20630 /dev/kgsl-3d0
-7ffeeb000-7ffeec000 rw-s 000b6000 00:10 20630 /dev/kgsl-3d0
-7ffeec000-7ffeed000 rw-s 000b5000 00:10 20630 /dev/kgsl-3d0
-7ffeed000-7ffeee000 rw-s 000b4000 00:10 20630 /dev/kgsl-3d0
-7ffeee000-7ffeef000 rw-s 000b3000 00:10 20630 /dev/kgsl-3d0
-7ffeef000-7ffef0000 rw-s 000b2000 00:10 20630 /dev/kgsl-3d0
-7ffef0000-7ffef1000 rw-s 000b1000 00:10 20630 /dev/kgsl-3d0
-7ffef1000-7ffef2000 rw-s 000b0000 00:10 20630 /dev/kgsl-3d0
-7ffef2000-7ffef3000 rw-s 000af000 00:10 20630 /dev/kgsl-3d0
-7ffef3000-7ffef4000 rw-s 000ae000 00:10 20630 /dev/kgsl-3d0
-7ffef4000-7ffef5000 rw-s 000ad000 00:10 20630 /dev/kgsl-3d0
-7ffef5000-7ffef6000 rw-s 000ac000 00:10 20630 /dev/kgsl-3d0
-7ffef6000-7ffef7000 rw-s 000ab000 00:10 20630 /dev/kgsl-3d0
-7ffef7000-7ffef8000 rw-s 000aa000 00:10 20630 /dev/kgsl-3d0
-7ffef8000-7ffef9000 rw-s 000a9000 00:10 20630 /dev/kgsl-3d0
-7ffef9000-7ffefa000 rw-s 000a8000 00:10 20630 /dev/kgsl-3d0
-7ffefa000-7ffefb000 rw-s 000a7000 00:10 20630 /dev/kgsl-3d0
-7ffefb000-7ffefc000 rw-s 000a6000 00:10 20630 /dev/kgsl-3d0
-7ffefc000-7ffefd000 rw-s 000a5000 00:10 20630 /dev/kgsl-3d0
-7ffefd000-7ffefe000 rw-s 000a4000 00:10 20630 /dev/kgsl-3d0
-7ffefe000-7ffeff000 rw-s 000a3000 00:10 20630 /dev/kgsl-3d0
-7ffeff000-7fff00000 rw-s 000a2000 00:10 20630 /dev/kgsl-3d0
-7fff00000-7fff01000 rw-s 000a1000 00:10 20630 /dev/kgsl-3d0
-7fff01000-7fff02000 rw-s 000a0000 00:10 20630 /dev/kgsl-3d0
-7fff02000-7fff03000 rw-s 0009f000 00:10 20630 /dev/kgsl-3d0
-7fff03000-7fff04000 rw-s 0009e000 00:10 20630 /dev/kgsl-3d0
-7fff04000-7fff05000 rw-s 0009d000 00:10 20630 /dev/kgsl-3d0
-7fff05000-7fff06000 rw-s 0009c000 00:10 20630 /dev/kgsl-3d0
-7fff06000-7fff07000 rw-s 0009b000 00:10 20630 /dev/kgsl-3d0
-7fff07000-7fff08000 rw-s 0009a000 00:10 20630 /dev/kgsl-3d0
-7fff08000-7fff09000 rw-s 00099000 00:10 20630 /dev/kgsl-3d0
-7fff09000-7fff0a000 rw-s 00098000 00:10 20630 /dev/kgsl-3d0
-7fff0a000-7fff0b000 rw-s 00097000 00:10 20630 /dev/kgsl-3d0
-7fff0b000-7fff0c000 rw-s 00096000 00:10 20630 /dev/kgsl-3d0
-7fff0c000-7fff0d000 rw-s 00095000 00:10 20630 /dev/kgsl-3d0
-7fff0d000-7fff0e000 rw-s 00094000 00:10 20630 /dev/kgsl-3d0
-7fff0e000-7fff0f000 rw-s 00093000 00:10 20630 /dev/kgsl-3d0
-7fff0f000-7fff10000 rw-s 00092000 00:10 20630 /dev/kgsl-3d0
-7fff10000-7fff11000 rw-s 00091000 00:10 20630 /dev/kgsl-3d0
-7fff11000-7fff12000 rw-s 00090000 00:10 20630 /dev/kgsl-3d0
-7fff12000-7fff13000 rw-s 0008f000 00:10 20630 /dev/kgsl-3d0
-7fff13000-7fff14000 rw-s 0008e000 00:10 20630 /dev/kgsl-3d0
-7fff14000-7fff15000 rw-s 0008d000 00:10 20630 /dev/kgsl-3d0
-7fff15000-7fff16000 rw-s 0008c000 00:10 20630 /dev/kgsl-3d0
-7fff16000-7fff17000 rw-s 0008b000 00:10 20630 /dev/kgsl-3d0
-7fff17000-7fff18000 rw-s 0008a000 00:10 20630 /dev/kgsl-3d0
-7fff18000-7fff19000 rw-s 00089000 00:10 20630 /dev/kgsl-3d0
-7fff19000-7fff1a000 rw-s 00088000 00:10 20630 /dev/kgsl-3d0
-7fff1a000-7fff1b000 rw-s 00087000 00:10 20630 /dev/kgsl-3d0
-7fff1b000-7fff1c000 rw-s 00086000 00:10 20630 /dev/kgsl-3d0
-7fff1c000-7fff1d000 rw-s 00085000 00:10 20630 /dev/kgsl-3d0
-7fff1d000-7fff1e000 rw-s 00084000 00:10 20630 /dev/kgsl-3d0
-7fff1e000-7fff1f000 rw-s 00083000 00:10 20630 /dev/kgsl-3d0
-7fff1f000-7fff20000 rw-s 00082000 00:10 20630 /dev/kgsl-3d0
-7fff20000-7fff21000 rw-s 00081000 00:10 20630 /dev/kgsl-3d0
-7fff21000-7fff22000 rw-s 00080000 00:10 20630 /dev/kgsl-3d0
-7fff22000-7fff23000 rw-s 0007f000 00:10 20630 /dev/kgsl-3d0
-7fff23000-7fff24000 rw-s 0007e000 00:10 20630 /dev/kgsl-3d0
-7fff24000-7fff25000 rw-s 0007d000 00:10 20630 /dev/kgsl-3d0
-7fff25000-7fff26000 rw-s 0007c000 00:10 20630 /dev/kgsl-3d0
-7fff26000-7fff27000 rw-s 0007b000 00:10 20630 /dev/kgsl-3d0
-7fff27000-7fff28000 rw-s 0007a000 00:10 20630 /dev/kgsl-3d0
-7fff28000-7fff29000 rw-s 00079000 00:10 20630 /dev/kgsl-3d0
-7fff29000-7fff2a000 rw-s 00078000 00:10 20630 /dev/kgsl-3d0
-7fff2a000-7fff2b000 rw-s 00077000 00:10 20630 /dev/kgsl-3d0
-7fff2b000-7fff2c000 rw-s 00076000 00:10 20630 /dev/kgsl-3d0
-7fff2c000-7fff2d000 rw-s 00075000 00:10 20630 /dev/kgsl-3d0
-7fff2d000-7fff2e000 rw-s 00074000 00:10 20630 /dev/kgsl-3d0
-7fff2e000-7fff2f000 rw-s 00073000 00:10 20630 /dev/kgsl-3d0
-7fff2f000-7fff30000 rw-s 00072000 00:10 20630 /dev/kgsl-3d0
-7fff30000-7fff31000 rw-s 00071000 00:10 20630 /dev/kgsl-3d0
-7fff31000-7fff32000 rw-s 00070000 00:10 20630 /dev/kgsl-3d0
-7fff32000-7fff33000 rw-s 0006f000 00:10 20630 /dev/kgsl-3d0
-7fff33000-7fff34000 rw-s 0006e000 00:10 20630 /dev/kgsl-3d0
-7fff34000-7fff35000 rw-s 0006d000 00:10 20630 /dev/kgsl-3d0
-7fff35000-7fff36000 rw-s 0006c000 00:10 20630 /dev/kgsl-3d0
-7fff36000-7fff37000 rw-s 0006b000 00:10 20630 /dev/kgsl-3d0
-7fff37000-7fff38000 rw-s 0006a000 00:10 20630 /dev/kgsl-3d0
-7fff38000-7fff39000 rw-s 00069000 00:10 20630 /dev/kgsl-3d0
-7fff39000-7fff3a000 rw-s 00068000 00:10 20630 /dev/kgsl-3d0
-7fff3a000-7fff3b000 rw-s 00067000 00:10 20630 /dev/kgsl-3d0
-7fff3b000-7fff3c000 rw-s 00066000 00:10 20630 /dev/kgsl-3d0
-7fff3c000-7fff3d000 rw-s 00065000 00:10 20630 /dev/kgsl-3d0
-7fff3d000-7fff3e000 rw-s 00064000 00:10 20630 /dev/kgsl-3d0
-7fff3e000-7fff3f000 rw-s 00063000 00:10 20630 /dev/kgsl-3d0
-7fff3f000-7fff40000 rw-s 00062000 00:10 20630 /dev/kgsl-3d0
-7fff40000-7fff41000 rw-s 00061000 00:10 20630 /dev/kgsl-3d0
-7fff41000-7fff42000 rw-s 00060000 00:10 20630 /dev/kgsl-3d0
-7fff42000-7fff43000 rw-s 0005f000 00:10 20630 /dev/kgsl-3d0
-7fff43000-7fff44000 rw-s 0005e000 00:10 20630 /dev/kgsl-3d0
-7fff44000-7fff45000 rw-s 0005d000 00:10 20630 /dev/kgsl-3d0
-7fff45000-7fff46000 rw-s 0005c000 00:10 20630 /dev/kgsl-3d0
-7fff46000-7fff47000 rw-s 0005b000 00:10 20630 /dev/kgsl-3d0
-7fff47000-7fff48000 rw-s 0005a000 00:10 20630 /dev/kgsl-3d0
-7fff48000-7fff49000 rw-s 00059000 00:10 20630 /dev/kgsl-3d0
-7fff49000-7fff4a000 rw-s 00058000 00:10 20630 /dev/kgsl-3d0
-7fff4a000-7fff4b000 rw-s 00057000 00:10 20630 /dev/kgsl-3d0
-7fff4b000-7fff4c000 rw-s 00056000 00:10 20630 /dev/kgsl-3d0
-7fff4c000-7fff4d000 rw-s 00055000 00:10 20630 /dev/kgsl-3d0
-7fff4d000-7fff4e000 rw-s 00054000 00:10 20630 /dev/kgsl-3d0
-7fff4e000-7fff4f000 rw-s 00053000 00:10 20630 /dev/kgsl-3d0
-7fff4f000-7fff50000 rw-s 00052000 00:10 20630 /dev/kgsl-3d0
-7fff50000-7fff51000 rw-s 00051000 00:10 20630 /dev/kgsl-3d0
-7fff51000-7fff52000 rw-s 00050000 00:10 20630 /dev/kgsl-3d0
-7fff52000-7fff53000 rw-s 0004f000 00:10 20630 /dev/kgsl-3d0
-7fff53000-7fff54000 rw-s 0004e000 00:10 20630 /dev/kgsl-3d0
-7fff54000-7fff55000 rw-s 0004d000 00:10 20630 /dev/kgsl-3d0
-7fff55000-7fff56000 rw-s 0004c000 00:10 20630 /dev/kgsl-3d0
-7fff56000-7fff57000 rw-s 0004b000 00:10 20630 /dev/kgsl-3d0
-7fff57000-7fff58000 rw-s 0004a000 00:10 20630 /dev/kgsl-3d0
-7fff58000-7fff59000 rw-s 00049000 00:10 20630 /dev/kgsl-3d0
-7fff59000-7fff5a000 rw-s 00048000 00:10 20630 /dev/kgsl-3d0
-7fff5a000-7fff5b000 rw-s 00047000 00:10 20630 /dev/kgsl-3d0
-7fff5b000-7fff5c000 rw-s 00046000 00:10 20630 /dev/kgsl-3d0
-7fff5c000-7fff5d000 rw-s 00045000 00:10 20630 /dev/kgsl-3d0
-7fff5d000-7fff5e000 rw-s 00044000 00:10 20630 /dev/kgsl-3d0
-7fff5e000-7fff5f000 rw-s 00043000 00:10 20630 /dev/kgsl-3d0
-7fff5f000-7fff60000 rw-s 00042000 00:10 20630 /dev/kgsl-3d0
-7fff60000-7fff61000 rw-s 00041000 00:10 20630 /dev/kgsl-3d0
-7fff61000-7fff62000 rw-s 00040000 00:10 20630 /dev/kgsl-3d0
-7fff62000-7fff63000 rw-s 0003f000 00:10 20630 /dev/kgsl-3d0
-7fff63000-7fff64000 rw-s 0003e000 00:10 20630 /dev/kgsl-3d0
-7fff64000-7fff65000 rw-s 0003d000 00:10 20630 /dev/kgsl-3d0
-7fff65000-7fff66000 rw-s 0003c000 00:10 20630 /dev/kgsl-3d0
-7fff66000-7fff67000 rw-s 0003b000 00:10 20630 /dev/kgsl-3d0
-7fff67000-7fff68000 rw-s 0003a000 00:10 20630 /dev/kgsl-3d0
-7fff68000-7fff69000 rw-s 00039000 00:10 20630 /dev/kgsl-3d0
-7fff69000-7fff6a000 rw-s 00038000 00:10 20630 /dev/kgsl-3d0
-7fff6a000-7fff6b000 rw-s 00037000 00:10 20630 /dev/kgsl-3d0
-7fff6b000-7fff6c000 rw-s 00036000 00:10 20630 /dev/kgsl-3d0
-7fff6c000-7fff6d000 rw-s 00035000 00:10 20630 /dev/kgsl-3d0
-7fff6d000-7fff6e000 rw-s 00034000 00:10 20630 /dev/kgsl-3d0
-7fff6e000-7fff6f000 rw-s 00033000 00:10 20630 /dev/kgsl-3d0
-7fff6f000-7fff70000 rw-s 00032000 00:10 20630 /dev/kgsl-3d0
-7fff70000-7fff71000 rw-s 00031000 00:10 20630 /dev/kgsl-3d0
-7fff71000-7fff72000 rw-s 00030000 00:10 20630 /dev/kgsl-3d0
-7fff72000-7fff73000 rw-s 0002f000 00:10 20630 /dev/kgsl-3d0
-7fff73000-7fff74000 rw-s 0002e000 00:10 20630 /dev/kgsl-3d0
-7fff74000-7fff75000 rw-s 0002d000 00:10 20630 /dev/kgsl-3d0
-7fff75000-7fff76000 rw-s 0002c000 00:10 20630 /dev/kgsl-3d0
-7fff76000-7fff77000 rw-s 0002b000 00:10 20630 /dev/kgsl-3d0
-7fff77000-7fff78000 rw-s 0002a000 00:10 20630 /dev/kgsl-3d0
-7fff78000-7fff79000 rw-s 00029000 00:10 20630 /dev/kgsl-3d0
-7fff79000-7fff7a000 rw-s 00028000 00:10 20630 /dev/kgsl-3d0
-7fff7a000-7fff7b000 rw-s 00027000 00:10 20630 /dev/kgsl-3d0
-7fff7b000-7fff7c000 rw-s 00026000 00:10 20630 /dev/kgsl-3d0
-7fff7c000-7fff7d000 rw-s 00025000 00:10 20630 /dev/kgsl-3d0
-7fff7d000-7fff7e000 rw-s 00024000 00:10 20630 /dev/kgsl-3d0
-7fff7e000-7fff7f000 rw-s 00023000 00:10 20630 /dev/kgsl-3d0
-7fff7f000-7fff80000 rw-s 00022000 00:10 20630 /dev/kgsl-3d0
-7fff80000-7fff90000 rw-s 00019000 00:10 20630 /dev/kgsl-3d0
-7fff90000-7fffb0000 rw-s 00018000 00:10 20630 /dev/kgsl-3d0
-7fffb1000-7fffb2000 rw-s 00021000 00:10 20630 /dev/kgsl-3d0
-7fffb2000-7fffb3000 rw-s 00020000 00:10 20630 /dev/kgsl-3d0
-7fffb3000-7fffb4000 rw-s 0001f000 00:10 20630 /dev/kgsl-3d0
-7fffba000-7fffbe000 rw-s 0001b000 00:10 20630 /dev/kgsl-3d0
-7fffbe000-7fffbf000 rw-s 0001a000 00:10 20630 /dev/kgsl-3d0
-7fffbf000-7fffc0000 rw-s 00017000 00:10 20630 /dev/kgsl-3d0
-7fffc0000-7fffe0000 rw-s 00016000 00:10 20630 /dev/kgsl-3d0
-7fffe0000-7fffe1000 rw-s 00014000 00:10 20630 /dev/kgsl-3d0
-7fffe1000-7fffe5000 rw-s 00013000 00:10 20630 /dev/kgsl-3d0
-7fffe5000-7fffe6000 rw-s 00012000 00:10 20630 /dev/kgsl-3d0
-7fffe6000-7fffe7000 rw-s 00011000 00:10 20630 /dev/kgsl-3d0
-7fffe7000-7fffe8000 rw-s 00010000 00:10 20630 /dev/kgsl-3d0
-7fffe8000-7fffe9000 rw-s 0000f000 00:10 20630 /dev/kgsl-3d0
-7fffe9000-7fffea000 rw-s 0000e000 00:10 20630 /dev/kgsl-3d0
-7fffea000-7fffeb000 rw-s 0000d000 00:10 20630 /dev/kgsl-3d0
-7fffeb000-7fffec000 rw-s 0000c000 00:10 20630 /dev/kgsl-3d0
-7fffec000-7ffff0000 rw-s 0000b000 00:10 20630 /dev/kgsl-3d0
-7ffff0000-7ffff1000 rw-s 0000a000 00:10 20630 /dev/kgsl-3d0
-7ffff1000-7ffff5000 rw-s 00009000 00:10 20630 /dev/kgsl-3d0
-7ffff5000-7ffff6000 rw-s 00008000 00:10 20630 /dev/kgsl-3d0
-7ffff6000-7ffff7000 rw-s 00007000 00:10 20630 /dev/kgsl-3d0
-7ffff7000-7ffff8000 rw-s 00006000 00:10 20630 /dev/kgsl-3d0
-7ffff8000-7ffff9000 rw-s 00005000 00:10 20630 /dev/kgsl-3d0
-7ffff9000-7ffffa000 rw-s 00004000 00:10 20630 /dev/kgsl-3d0
-7ffffa000-7ffffb000 rw-s 00003000 00:10 20630 /dev/kgsl-3d0
-7ffffb000-7ffffc000 rw-s 00002000 00:10 20630 /dev/kgsl-3d0
-7ffffc000-800000000 rw-s 00001000 00:10 20630 /dev/kgsl-3d0
-5ff1d4f000-5ff1d54000 r-xp 00000000 fc:00 3419 /system/bin/app_process64
-5ff1d6e000-5ff1d6f000 r--p 0000f000 fc:00 3419 /system/bin/app_process64
-5ff1d6f000-5ff1d71000 rw-p 00000000 00:00 0
-704defa000-704defb000 ---p 00000000 00:00 0 [anon:thread stack guard]
-704defb000-704defc000 ---p 00000000 00:00 0
-704defc000-704e000000 rw-p 00000000 00:00 0
-704e000000-704e400000 rw-p 00000000 00:00 0 [anon:libc_malloc]
-704e455000-704e456000 ---p 00000000 00:00 0 [anon:thread stack guard]
-704e456000-704e457000 ---p 00000000 00:00 0
-704e457000-704e553000 rw-p 00000000 00:00 0
-704e553000-704e651000 r--p 00000000 00:10 16029 /dev/hwbinder
-704e651000-704e65f000 r-xp 00000000 fc:01 1040 /vendor/lib64/egl/eglSubDriverAndroid.so
-704e65f000-704e660000 r--p 0000e000 fc:01 1040 /vendor/lib64/egl/eglSubDriverAndroid.so
-704e660000-704e661000 rw-p 0000f000 fc:01 1040 /vendor/lib64/egl/eglSubDriverAndroid.so
-704e69d000-704e69e000 ---p 00000000 00:00 0 [anon:thread stack guard]
-704e69e000-704e79b000 rw-p 00000000 00:00 0
-704e79b000-704f79b000 rw-s 00000000 00:05 10271021 /dev/ashmem/AudioFlinger::Client(29312) (deleted)
-704f79b000-704f79c000 ---p 00000000 00:00 0 [anon:thread stack guard]
-704f79c000-704f899000 rw-p 00000000 00:00 0
-704f899000-704f89a000 ---p 00000000 00:00 0 [anon:thread stack guard]
-704f89a000-704f89b000 ---p 00000000 00:00 0
-704f89b000-704f997000 rw-p 00000000 00:00 0
-704f997000-704f9ee000 r-xp 00000000 103:1d 1737338 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
-704f9ee000-704f9fd000 ---p 00000000 00:00 0
-704f9fd000-704fa00000 r--p 00056000 103:1d 1737338 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
-704fa00000-704fa01000 rw-p 00059000 103:1d 1737338 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/lib/arm64/libgame.so
-704fa01000-704fa19000 rw-p 00000000 00:00 0 [anon:.bss]
-704fa40000-70507e7000 r-xp 00000000 fc:01 1026 /vendor/lib64/libllvm-glnext.so
-70507e7000-70507fc000 ---p 00000000 00:00 0
-70507fc000-7050835000 r--p 00da7000 fc:01 1026 /vendor/lib64/libllvm-glnext.so
-7050835000-705083a000 rw-p 00de0000 fc:01 1026 /vendor/lib64/libllvm-glnext.so
-705083a000-7050855000 rw-p 00000000 00:00 0 [anon:.bss]
-705089b000-7050f19000 r-xp 00000000 fc:01 1039 /vendor/lib64/egl/libGLESv2_adreno.so
-7050f19000-7050f22000 r--p 0067e000 fc:01 1039 /vendor/lib64/egl/libGLESv2_adreno.so
-7050f22000-7050f29000 rw-p 00687000 fc:01 1039 /vendor/lib64/egl/libGLESv2_adreno.so
-7050f29000-7050f2c000 rw-p 00000000 00:00 0 [anon:.bss]
-7050f83000-7050fbc000 r-xp 00000000 fc:01 1041 /vendor/lib64/egl/libGLESv1_CM_adreno.so
-7050fbc000-7050fbd000 r--p 00039000 fc:01 1041 /vendor/lib64/egl/libGLESv1_CM_adreno.so
-7050fbd000-7050fbe000 rw-p 0003a000 fc:01 1041 /vendor/lib64/egl/libGLESv1_CM_adreno.so
-7050fbe000-7050fbf000 rw-p 00000000 00:00 0 [anon:.bss]
-7050fc6000-705111d000 r-xp 00000000 fc:01 865 /vendor/lib64/libgsl.so
-705111d000-705111e000 r--p 00157000 fc:01 865 /vendor/lib64/libgsl.so
-705111e000-705111f000 rw-p 00158000 fc:01 865 /vendor/lib64/libgsl.so
-705111f000-7051120000 rw-p 00000000 00:00 0 [anon:.bss]
-7051146000-705115d000 r-xp 00000000 fc:00 2587 /system/lib64/vndk-sp-28/libz.so
-705115d000-7051175000 ---p 00000000 00:00 0
-7051175000-7051176000 r--p 0001f000 fc:00 2587 /system/lib64/vndk-sp-28/libz.so
-7051176000-7051177000 rw-p 00020000 fc:00 2587 /system/lib64/vndk-sp-28/libz.so
-705119f000-70511ac000 r-xp 00000000 fc:01 886 /vendor/lib64/libadreno_utils.so
-70511ac000-70511ad000 r--p 0000d000 fc:01 886 /vendor/lib64/libadreno_utils.so
-70511ad000-70511ae000 rw-p 0000e000 fc:01 886 /vendor/lib64/libadreno_utils.so
-70511ae000-70511b0000 rw-p 00000000 00:00 0 [anon:.bss]
-70511c0000-70511d7000 r-xp 00000000 fc:01 1044 /vendor/lib64/egl/libEGL_adreno.so
-70511d7000-70511d8000 r--p 00017000 fc:01 1044 /vendor/lib64/egl/libEGL_adreno.so
-70511d8000-70511d9000 rw-p 00018000 fc:01 1044 /vendor/lib64/egl/libEGL_adreno.so
-70511d9000-70511da000 rw-p 00000000 00:00 0 [anon:.bss]
-705120a000-705120d000 r-xp 00000000 fc:01 972 /vendor/lib64/libdrmutils.so
-705120d000-7051229000 ---p 00000000 00:00 0
-7051229000-705122a000 r--p 0000f000 fc:01 972 /vendor/lib64/libdrmutils.so
-705122a000-705122b000 rw-p 00010000 fc:01 972 /vendor/lib64/libdrmutils.so
-705125a000-705125c000 r-xp 00000000 fc:01 1046 /vendor/lib64/libqdMetaData.so
-705125c000-7051279000 ---p 00000000 00:00 0
-7051279000-705127a000 r--p 0000f000 fc:01 1046 /vendor/lib64/libqdMetaData.so
-705127a000-705127b000 rw-p 00010000 fc:01 1046 /vendor/lib64/libqdMetaData.so
-7051286000-7051297000 r-xp 00000000 fc:01 1024 /vendor/lib64/libdrm.so
-7051297000-70512b5000 ---p 00000000 00:00 0
-70512b5000-70512b6000 r--p 0001f000 fc:01 1024 /vendor/lib64/libdrm.so
-70512b6000-70512b7000 rw-p 00020000 fc:01 1024 /vendor/lib64/libdrm.so
-70512cb000-70512de000 r-xp 00000000 fc:01 1008 /vendor/lib64/hw/gralloc.msm8998.so
-70512de000-70512fa000 ---p 00000000 00:00 0
-70512fa000-70512fb000 r--p 0001f000 fc:01 1008 /vendor/lib64/hw/gralloc.msm8998.so
-70512fb000-70512fc000 rw-p 00020000 fc:01 1008 /vendor/lib64/hw/gralloc.msm8998.so
-7051326000-7051327000 ---p 00000000 00:00 0 [anon:thread stack guard]
-7051327000-7051328000 ---p 00000000 00:00 0
-7051328000-7051424000 rw-p 00000000 00:00 0
-7051424000-705143d000 r--p 00000000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
-705143d000-7051480000 r-xp 00019000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
-7051480000-7051494000 r--p 00211000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
-7051494000-705149f000 r--p 000c5000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
-705149f000-70514a2000 r--p 00032000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
-70514a2000-70514a5000 r--p 0002b000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
-70514a5000-70514ac000 r--p 0003f000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
-70514ac000-70514b2000 r--p 00044000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
-70514b2000-70514bd000 r--p 00035000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
-70514bd000-70514f4000 r--p 0060f000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
-70514f4000-70514fe000 r--p 00054000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
-70514fe000-70514ff000 r--p 0000c000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
-70514ff000-7051500000 r--p 0000e000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
-7051500000-7051501000 r--p 00004000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
-7051501000-7051502000 r--p 00004000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
-7051502000-7051503000 r--p 00001000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
-7051503000-7051504000 rw-p 00000000 00:00 0 [anon:.bss]
-7051504000-7051579000 r--s 00000000 fc:00 790 /system/framework/oat/arm64/org.apache.http.legacy.boot.vdex
-7051579000-705157a000 r--p 0005c000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
-705157a000-705157b000 rw-p 0005d000 fc:00 739 /system/framework/oat/arm64/org.apache.http.legacy.boot.odex
-705158b000-7057f4d000 ---p 00000000 00:00 0
-7057f4d000-7057f4f000 r-xp 00000000 fc:00 2646 /system/lib64/libwebviewchromium_loader.so
-7057f4f000-7057f6c000 ---p 00000000 00:00 0
-7057f6c000-7057f6d000 r--p 0000f000 fc:00 2646 /system/lib64/libwebviewchromium_loader.so
-7057f6d000-7057f6e000 rw-p 00010000 fc:00 2646 /system/lib64/libwebviewchromium_loader.so
-7057f76000-7057f96000 r--s 00000000 00:10 16615 /dev/__properties__/u:object_r:hwservicemanager_prop:s0
-7057f96000-7057fb6000 r--s 00000000 00:10 16639 /dev/__properties__/u:object_r:public_vendor_default_prop:s0
-7057fb6000-7058004000 r--s 00000000 fc:00 1112 /system/usr/hyphen-data/hyph-hu.hyb
-7058004000-7058024000 r-xp 00000000 fc:00 2354 /system/lib64/libcompiler_rt.so
-7058024000-7058043000 ---p 00000000 00:00 0
-7058043000-7058044000 r--p 0002f000 fc:00 2354 /system/lib64/libcompiler_rt.so
-7058044000-7058045000 rw-p 00030000 fc:00 2354 /system/lib64/libcompiler_rt.so
-7058045000-70580b2000 rw-p 00000000 00:00 0 [anon:.bss]
-70580bd000-70580dd000 rw-p 00000000 00:05 10265386 [anon:dalvik-LinearAlloc]
-70580dd000-70580df000 r-xp 00000000 fc:00 2597 /system/lib64/vndk-sp-28/libhardware.so
-70580df000-70580fc000 ---p 00000000 00:00 0
-70580fc000-70580fd000 r--p 0000f000 fc:00 2597 /system/lib64/vndk-sp-28/libhardware.so
-70580fd000-70580fe000 rw-p 00010000 fc:00 2597 /system/lib64/vndk-sp-28/libhardware.so
-705810e000-705811f000 r-xp 00000000 fc:00 2589 /system/lib64/vndk-sp-28/libbase.so
-705811f000-705813d000 ---p 00000000 00:00 0
-705813d000-705813e000 r--p 0001f000 fc:00 2589 /system/lib64/vndk-sp-28/libbase.so
-705813e000-705813f000 rw-p 00020000 fc:00 2589 /system/lib64/vndk-sp-28/libbase.so
-7058140000-7058167000 r-xp 00000000 fc:00 2572 /system/lib64/vndk-sp-28/libhwbinder.so
-7058167000-705817d000 ---p 00000000 00:00 0
-705817d000-705817f000 r--p 0002e000 fc:00 2572 /system/lib64/vndk-sp-28/libhwbinder.so
-705817f000-7058180000 rw-p 00030000 fc:00 2572 /system/lib64/vndk-sp-28/libhwbinder.so
-705818c000-705818d000 r-xp 00000000 fc:00 2584 /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
-705818d000-70581ab000 ---p 00000000 00:00 0
-70581ab000-70581ac000 r--p 0000f000 fc:00 2584 /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
-70581ac000-70581ad000 rw-p 00010000 fc:00 2584 /system/lib64/vndk-sp-28/android.hardware.graphics.common@1.0.so
-70581b7000-70581d7000 r--s 00000000 00:10 16619 /dev/__properties__/u:object_r:log_prop:s0
-70581d7000-7058237000 r-xp 00000000 fc:00 2574 /system/lib64/vndk-sp-28/libhidltransport.so
-7058237000-7058255000 ---p 00000000 00:00 0
-7058255000-705825d000 r--p 00068000 fc:00 2574 /system/lib64/vndk-sp-28/libhidltransport.so
-705825d000-705825e000 rw-p 00070000 fc:00 2574 /system/lib64/vndk-sp-28/libhidltransport.so
-7058260000-7058284000 r--s 00000000 fc:00 1138 /system/usr/hyphen-data/hyph-nn.hyb
-7058284000-70582a0000 r-xp 00000000 fc:00 2576 /system/lib64/vndk-sp-28/libutils.so
-70582a0000-70582b3000 ---p 00000000 00:00 0
-70582b3000-70582b4000 r--p 0001f000 fc:00 2576 /system/lib64/vndk-sp-28/libutils.so
-70582b4000-70582b5000 rw-p 00020000 fc:00 2576 /system/lib64/vndk-sp-28/libutils.so
-70582c4000-7058391000 r-xp 00000000 fc:00 2568 /system/lib64/vndk-sp-28/libc++.so
-7058391000-70583ad000 ---p 00000000 00:00 0
-70583ad000-70583b7000 r--p 000d6000 fc:00 2568 /system/lib64/vndk-sp-28/libc++.so
-70583b7000-70583b8000 rw-p 000e0000 fc:00 2568 /system/lib64/vndk-sp-28/libc++.so
-70583b8000-70583bb000 rw-p 00000000 00:00 0 [anon:.bss]
-70583cd000-70583e4000 r-xp 00000000 fc:00 2580 /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
-70583e4000-70583f9000 ---p 00000000 00:00 0
-70583f9000-70583fb000 r--p 0001e000 fc:00 2580 /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
-70583fb000-70583fc000 rw-p 00020000 fc:00 2580 /system/lib64/vndk-sp-28/android.hardware.graphics.mapper@2.0.so
-705841b000-7058421000 r-xp 00000000 fc:01 1001 /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
-7058421000-705843a000 ---p 00000000 00:00 0
-705843a000-705843b000 r--p 0000f000 fc:01 1001 /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
-705843b000-705843c000 rw-p 00010000 fc:01 1001 /vendor/lib64/hw/android.hardware.graphics.mapper@2.0-impl.so
-705844f000-7058473000 r--s 00000000 fc:00 1150 /system/usr/hyphen-data/hyph-nb.hyb
-7058473000-7058495000 r-xp 00000000 fc:00 2582 /system/lib64/vndk-sp-28/libhidlbase.so
-7058495000-70584b1000 ---p 00000000 00:00 0
-70584b1000-70584b3000 r--p 0002e000 fc:00 2582 /system/lib64/vndk-sp-28/libhidlbase.so
-70584b3000-70584b4000 rw-p 00030000 fc:00 2582 /system/lib64/vndk-sp-28/libhidlbase.so
-70584cd000-70584df000 r-xp 00000000 fc:00 2595 /system/lib64/vndk-sp-28/libcutils.so
-70584df000-70584fb000 ---p 00000000 00:00 0
-70584fb000-70584fd000 r--p 0001e000 fc:00 2595 /system/lib64/vndk-sp-28/libcutils.so
-70584fd000-70584fe000 rw-p 00020000 fc:00 2595 /system/lib64/vndk-sp-28/libcutils.so
-7058519000-7058537000 r--s 00000000 fc:00 1124 /system/usr/hyphen-data/hyph-de-ch-1901.hyb
-7058537000-7059fd1000 r--s 0070b000 fc:00 989 /system/framework/framework-res.apk
-7059fd1000-705a013000 r-xp 00000000 fc:00 2610 /system/lib64/libjavacrypto.so
-705a013000-705a02b000 ---p 00000000 00:00 0
-705a02b000-705a02d000 r--p 0004e000 fc:00 2610 /system/lib64/libjavacrypto.so
-705a02d000-705a02f000 rw-p 00050000 fc:00 2610 /system/lib64/libjavacrypto.so
-705a041000-705a05f000 r--s 00000000 fc:00 1128 /system/usr/hyphen-data/hyph-de-1996.hyb
-705a05f000-705a06a000 r-xp 00000000 fc:00 2917 /system/lib64/libsoundpool.so
-705a06a000-705a07e000 ---p 00000000 00:00 0
-705a07e000-705a07f000 r--p 0000f000 fc:00 2917 /system/lib64/libsoundpool.so
-705a07f000-705a080000 rw-p 00010000 fc:00 2917 /system/lib64/libsoundpool.so
-705a087000-705a102000 r--s 00000000 fc:00 1246 /system/usr/share/zoneinfo/tzdata
-705a102000-705a863000 r--s 00000000 fc:00 101 /system/fonts/NotoColorEmoji.ttf
-705a863000-705c000000 r--s 00000000 fc:00 251 /system/fonts/NotoSerifCJK-Regular.ttc
-705c000000-705c200000 rw-p 00000000 00:00 0 [anon:libc_malloc]
-705c209000-705c227000 r--s 00000000 fc:00 1077 /system/usr/hyphen-data/hyph-de-1901.hyb
-705c227000-705c26e000 r--s 02284000 fc:00 989 /system/framework/framework-res.apk
-705c26e000-705d43e000 r--s 00000000 fc:00 95 /system/fonts/NotoSansCJK-Regular.ttc
-705d43e000-705d4ec000 r--s 00000000 fc:00 278 /system/fonts/NotoSansSymbols-Regular-Subsetted.ttf
-705d4ec000-705d548000 r--s 00000000 fc:00 233 /system/fonts/NotoSansTibetan-Bold.ttf
-705d548000-705d5ab000 r--s 00000000 fc:00 177 /system/fonts/NotoSansTibetan-Regular.ttf
-705d5ab000-705d627000 r--s 00000000 fc:00 197 /system/fonts/NotoSansEgyptianHieroglyphs-Regular.ttf
-705d627000-705d6a2000 r--s 00000000 fc:00 76 /system/fonts/NotoSansCuneiform-Regular.ttf
-705d6a2000-705d6f3000 r--s 00000000 fc:00 67 /system/fonts/RobotoCondensed-BoldItalic.ttf
-705d6f3000-705d73e000 r--s 00000000 fc:00 199 /system/fonts/RobotoCondensed-Bold.ttf
-705d73e000-705d78f000 r--s 00000000 fc:00 230 /system/fonts/RobotoCondensed-MediumItalic.ttf
-705d78f000-705d7da000 r--s 00000000 fc:00 92 /system/fonts/RobotoCondensed-Medium.ttf
-705d7da000-705d82b000 r--s 00000000 fc:00 128 /system/fonts/RobotoCondensed-Italic.ttf
-705d82b000-705d875000 r--s 00000000 fc:00 164 /system/fonts/RobotoCondensed-Regular.ttf
-705d875000-705d8c7000 r--s 00000000 fc:00 292 /system/fonts/RobotoCondensed-LightItalic.ttf
-705d8c7000-705d919000 r--s 00000000 fc:00 85 /system/fonts/Roboto-BoldItalic.ttf
-705d919000-705d964000 r--s 00000000 fc:00 175 /system/fonts/Roboto-Bold.ttf
-705d964000-705d9b5000 r--s 00000000 fc:00 266 /system/fonts/Roboto-BlackItalic.ttf
-705d9b5000-705da00000 r--s 00000000 fc:00 187 /system/fonts/Roboto-Black.ttf
-705da00000-705dc00000 rw-p 00000000 00:00 0 [anon:libc_malloc]
-705dc1d000-705dc6e000 r--s 00000000 fc:00 148 /system/fonts/Roboto-MediumItalic.ttf
-705dc6e000-705dcb9000 r--s 00000000 fc:00 284 /system/fonts/Roboto-Medium.ttf
-705dcb9000-705dd0a000 r--s 00000000 fc:00 105 /system/fonts/Roboto-Italic.ttf
-705dd0a000-705dd55000 r--s 00000000 fc:00 156 /system/fonts/Roboto-Regular.ttf
-705dd55000-705dda7000 r--s 00000000 fc:00 217 /system/fonts/Roboto-LightItalic.ttf
-705dda7000-705ddf8000 r--s 00000000 fc:00 166 /system/fonts/Roboto-ThinItalic.ttf
-705ddf8000-705ddf9000 ---p 00000000 00:00 0 [anon:thread stack guard]
-705ddf9000-705ddfa000 ---p 00000000 00:00 0
-705ddfa000-705def6000 rw-p 00000000 00:00 0
-705def6000-705f5ec000 r--s 00000000 fc:00 1350 /system/usr/icu/icudt60l.dat
-705f5ec000-705f5ed000 ---p 00000000 00:00 0 [anon:thread stack guard]
-705f5ed000-705f5ee000 ---p 00000000 00:00 0
-705f5ee000-705f6ea000 rw-p 00000000 00:00 0
-705f6ea000-705f7e8000 r--p 00000000 00:10 20636 /dev/binder
-705f7e8000-705f7e9000 ---p 00000000 00:00 0 [anon:thread stack guard]
-705f7e9000-705f7ea000 ---p 00000000 00:00 0
-705f7ea000-705f8ee000 rw-p 00000000 00:00 0
-705f8ee000-705f8ef000 ---p 00000000 00:00 0 [anon:thread stack guard]
-705f8ef000-705f8f0000 ---p 00000000 00:00 0
-705f8f0000-705f9f4000 rw-p 00000000 00:00 0
-705f9f4000-705f9f5000 ---p 00000000 00:00 0 [anon:thread stack guard]
-705f9f5000-705f9f6000 ---p 00000000 00:00 0
-705f9f6000-705fafa000 rw-p 00000000 00:00 0
-705fafa000-705fafb000 ---p 00000000 00:00 0 [anon:thread stack guard]
-705fafb000-705fafc000 ---p 00000000 00:00 0
-705fafc000-705fc00000 rw-p 00000000 00:00 0
-705fc00000-705fe00000 rw-p 00000000 00:00 0 [anon:libc_malloc]
-705fe01000-705fe4c000 r--s 00000000 fc:00 97 /system/fonts/Roboto-Light.ttf
-705fe4c000-705fe4d000 ---p 00000000 00:00 0 [anon:thread stack guard]
-705fe4d000-705fe4e000 ---p 00000000 00:00 0
-705fe4e000-705ff4a000 rw-p 00000000 00:00 0
-705ff4a000-705ff4b000 ---p 00000000 00:05 10270991 [anon:dalvik-Jit thread pool worker thread 0]
-705ff4b000-705ff4c000 ---p 00001000 00:05 10270991 [anon:dalvik-Jit thread pool worker thread 0]
-705ff4c000-706004b000 rw-p 00002000 00:05 10270991 [anon:dalvik-Jit thread pool worker thread 0]
-706004b000-706010f000 r-xp 00000000 fc:00 2390 /system/lib64/libvixl-arm64.so
-706010f000-7060120000 ---p 00000000 00:00 0
-7060120000-7060125000 r--p 000cb000 fc:00 2390 /system/lib64/libvixl-arm64.so
-7060125000-7060126000 rw-p 000d0000 fc:00 2390 /system/lib64/libvixl-arm64.so
-7060126000-706012d000 rw-p 00000000 00:00 0 [anon:.bss]
-7060135000-7060151000 r--s 00000000 fc:01 1180 /vendor/overlay/framework-res__auto_generated_rro.apk
-7060151000-7060263000 r-xp 00000000 fc:00 2669 /system/lib64/libvixl-arm.so
-7060263000-7060275000 ---p 00000000 00:00 0
-7060275000-706027a000 r--p 0011b000 fc:00 2669 /system/lib64/libvixl-arm.so
-706027a000-706027b000 rw-p 00120000 fc:00 2669 /system/lib64/libvixl-arm.so
-706028b000-706056c000 r-xp 00000000 fc:00 2972 /system/lib64/libart-compiler.so
-706056c000-7060580000 ---p 00000000 00:00 0
-7060580000-7060598000 r--p 002e8000 fc:00 2972 /system/lib64/libart-compiler.so
-7060598000-7060599000 rw-p 00300000 fc:00 2972 /system/lib64/libart-compiler.so
-7060599000-70605a0000 rw-p 00000000 00:00 0 [anon:.bss]
-70605b0000-70605d0000 r--s 00000000 00:10 16571 /dev/__properties__/u:object_r:config_prop:s0
-70605d0000-7060619000 r-xp 00000000 fc:00 2702 /system/lib64/libssl.so
-7060619000-706062d000 ---p 00000000 00:00 0
-706062d000-7060630000 r--p 0004d000 fc:00 2702 /system/lib64/libssl.so
-7060630000-7060631000 rw-p 00050000 fc:00 2702 /system/lib64/libssl.so
-7060647000-7060667000 r--s 00000000 00:10 16595 /dev/__properties__/u:object_r:exported3_radio_prop:s0
-7060667000-706069d000 r-xp 00000000 fc:00 2371 /system/lib64/libopenjdk.so
-706069d000-70606b2000 ---p 00000000 00:00 0
-70606b2000-70606b4000 r--p 0003e000 fc:00 2371 /system/lib64/libopenjdk.so
-70606b4000-70606b6000 rw-p 00040000 fc:00 2371 /system/lib64/libopenjdk.so
-70606bb000-70606db000 r--s 00000000 00:10 16608 /dev/__properties__/u:object_r:exported_system_prop:s0
-70606db000-70606e3000 r-xp 00000000 fc:00 2538 /system/lib64/libopenjdkjvm.so
-70606e3000-70606fa000 ---p 00000000 00:00 0
-70606fa000-70606fb000 r--p 0000f000 fc:00 2538 /system/lib64/libopenjdkjvm.so
-70606fb000-70606fc000 rw-p 00010000 fc:00 2538 /system/lib64/libopenjdkjvm.so
-7060701000-7060722000 r--s 00000000 fc:00 227 /system/fonts/NotoSansAnatolianHieroglyphs-Regular.otf
-7060722000-7061e18000 r--s 00000000 fc:00 1350 /system/usr/icu/icudt60l.dat
-7061e18000-7061e5d000 r-xp 00000000 fc:00 2368 /system/lib64/libjavacore.so
-7061e5d000-7061e71000 ---p 00000000 00:00 0
-7061e71000-7061e73000 r--p 0004e000 fc:00 2368 /system/lib64/libjavacore.so
-7061e73000-7061e75000 rw-p 00050000 fc:00 2368 /system/lib64/libjavacore.so
-7061e75000-7061e76000 rw-p 00000000 00:00 0 [anon:.bss]
-7061e77000-7061e96000 r--s 00000000 fc:00 186 /system/fonts/NotoSansYi-Regular.ttf
-7061e96000-7061e99000 r-xp 00000000 fc:00 2953 /system/lib64/libwebviewchromium_plat_support.so
-7061e99000-7061eb5000 ---p 00000000 00:00 0
-7061eb5000-7061eb6000 r--p 0000f000 fc:00 2953 /system/lib64/libwebviewchromium_plat_support.so
-7061eb6000-7061eb7000 rw-p 00010000 fc:00 2953 /system/lib64/libwebviewchromium_plat_support.so
-7061ebc000-7061edd000 r--s 00000000 fc:00 100 /system/fonts/NotoSansBamum-Regular.ttf
-7061edd000-7061eed000 r-xp 00000000 fc:00 2945 /system/lib64/libRS.so
-7061eed000-7061efc000 ---p 00000000 00:00 0
-7061efc000-7061efd000 r--p 0000f000 fc:00 2945 /system/lib64/libRS.so
-7061efd000-7061efe000 rw-p 00010000 fc:00 2945 /system/lib64/libRS.so
-7061f05000-7061f6b000 r-xp 00000000 fc:00 2423 /system/lib64/android.hardware.renderscript@1.0.so
-7061f6b000-7061f7a000 ---p 00000000 00:00 0
-7061f7a000-7061f7f000 r--p 0006b000 fc:00 2423 /system/lib64/android.hardware.renderscript@1.0.so
-7061f7f000-7061f80000 rw-p 00070000 fc:00 2423 /system/lib64/android.hardware.renderscript@1.0.so
-7061f99000-7061f9b000 r-xp 00000000 fc:00 2614 /system/lib64/libOpenSLES.so
-7061f9b000-7061fb8000 ---p 00000000 00:00 0
-7061fb8000-7061fb9000 r--p 0000f000 fc:00 2614 /system/lib64/libOpenSLES.so
-7061fb9000-7061fba000 rw-p 00010000 fc:00 2614 /system/lib64/libOpenSLES.so
-7061fc6000-7061fc8000 r-xp 00000000 fc:00 2963 /system/lib64/libOpenMAXAL.so
-7061fc8000-7061fe5000 ---p 00000000 00:00 0
-7061fe5000-7061fe6000 r--p 0000f000 fc:00 2963 /system/lib64/libOpenMAXAL.so
-7061fe6000-7061fe7000 rw-p 00010000 fc:00 2963 /system/lib64/libOpenMAXAL.so
-7061fe7000-7062000000 r--s 00000000 fc:00 143 /system/fonts/NotoSansBhaiksuki-Regular.otf
-7062000000-7062003000 r-xp 00000000 fc:00 2447 /system/lib64/libtextclassifier_hash.so
-7062003000-706201f000 ---p 00000000 00:00 0
-706201f000-7062020000 r--p 0000f000 fc:00 2447 /system/lib64/libtextclassifier_hash.so
-7062020000-7062021000 rw-p 00010000 fc:00 2447 /system/lib64/libtextclassifier_hash.so
-7062022000-7062042000 rw-p 00000000 00:05 10269731 [anon:dalvik-CompilerMetadata]
-7062042000-7062077000 r-xp 00000000 fc:00 2372 /system/lib64/android.hardware.neuralnetworks@1.0.so
-7062077000-7062095000 ---p 00000000 00:00 0
-7062095000-706209b000 r--p 0003a000 fc:00 2372 /system/lib64/android.hardware.neuralnetworks@1.0.so
-706209b000-706209c000 rw-p 00040000 fc:00 2372 /system/lib64/android.hardware.neuralnetworks@1.0.so
-70620a9000-70620c9000 rw-p 00000000 00:05 10269730 [anon:dalvik-CompilerMetadata]
-70620c9000-70620e3000 r-xp 00000000 fc:00 2956 /system/lib64/android.hardware.neuralnetworks@1.1.so
-70620e3000-70620f4000 ---p 00000000 00:00 0
-70620f4000-70620f7000 r--p 0001d000 fc:00 2956 /system/lib64/android.hardware.neuralnetworks@1.1.so
-70620f7000-70620f8000 rw-p 00020000 fc:00 2956 /system/lib64/android.hardware.neuralnetworks@1.1.so
-706210b000-70621d0000 r-xp 00000000 fc:00 2387 /system/lib64/libneuralnetworks.so
-70621d0000-70621e3000 ---p 00000000 00:00 0
-70621e3000-70621e5000 r--p 000ce000 fc:00 2387 /system/lib64/libneuralnetworks.so
-70621e5000-70621e7000 rw-p 000d0000 fc:00 2387 /system/lib64/libneuralnetworks.so
-70621e7000-7062372000 rw-p 00000000 00:00 0 [anon:.bss]
-7062373000-7062395000 r--s 00000000 fc:00 274 /system/fonts/NotoSerifMyanmar-Bold.otf
-7062395000-7062398000 r-xp 00000000 fc:00 2937 /system/lib64/libjnigraphics.so
-7062398000-70623b4000 ---p 00000000 00:00 0
-70623b4000-70623b5000 r--p 0000f000 fc:00 2937 /system/lib64/libjnigraphics.so
-70623b5000-70623b6000 rw-p 00010000 fc:00 2937 /system/lib64/libjnigraphics.so
-70623c8000-70623e0000 r-xp 00000000 fc:00 2662 /system/lib64/libGLESv3.so
-70623e0000-70623f7000 ---p 00000000 00:00 0
-70623f7000-70623f8000 r--p 0001f000 fc:00 2662 /system/lib64/libGLESv3.so
-70623f8000-70623f9000 rw-p 00020000 fc:00 2662 /system/lib64/libGLESv3.so
-70623fc000-706241c000 rw-p 00000000 00:05 10269729 [anon:dalvik-CompilerMetadata]
-706241c000-7062444000 r-xp 00000000 fc:00 2603 /system/lib64/libexif.so
-7062444000-706245f000 ---p 00000000 00:00 0
-706245f000-7062472000 r--p 0002d000 fc:00 2603 /system/lib64/libexif.so
-7062472000-7062473000 rw-p 00040000 fc:00 2603 /system/lib64/libexif.so
-7062474000-7062490000 r--s 00000000 fc:00 286 /system/fonts/NotoSansMongolian-Regular.ttf
-7062490000-7062491000 r-xp 00000000 fc:00 2357 /system/lib64/libasyncio.so
-7062491000-70624af000 ---p 00000000 00:00 0
-70624af000-70624b0000 r--p 0000f000 fc:00 2357 /system/lib64/libasyncio.so
-70624b0000-70624b1000 rw-p 00010000 fc:00 2357 /system/lib64/libasyncio.so
-70624b5000-70624cf000 r--s 00000000 fc:00 221 /system/fonts/NotoSansMyanmarUI-Bold.ttf
-70624cf000-7062508000 r-xp 00000000 fc:00 2401 /system/lib64/libmtp.so
-7062508000-7062522000 ---p 00000000 00:00 0
-7062522000-7062525000 r--p 0003d000 fc:00 2401 /system/lib64/libmtp.so
-7062525000-706252c000 rw-p 00040000 fc:00 2401 /system/lib64/libmtp.so
-7062530000-7062550000 rw-p 00000000 00:05 10269728 [anon:dalvik-CompilerMetadata]
-7062550000-7062572000 r--s 00000000 fc:00 234 /system/fonts/NotoSerifMyanmar-Regular.otf
-7062572000-706259e000 r-xp 00000000 fc:00 2620 /system/lib64/libmediandk.so
-706259e000-70625b9000 ---p 00000000 00:00 0
-70625b9000-70625bc000 r--p 0002d000 fc:00 2620 /system/lib64/libmediandk.so
-70625bc000-70625c0000 rw-p 00030000 fc:00 2620 /system/lib64/libmediandk.so
-70625c2000-70625d1000 r-xp 00000000 fc:00 2613 /system/lib64/libmidi.so
-70625d1000-70625ef000 ---p 00000000 00:00 0
-70625ef000-70625f1000 r--p 0000e000 fc:00 2613 /system/lib64/libmidi.so
-70625f1000-70625f2000 rw-p 00010000 fc:00 2613 /system/lib64/libmidi.so
-7062600000-7062621000 r-xp 00000000 fc:00 2366 /system/lib64/libmediadrmmetrics_lite.so
-7062621000-706263d000 ---p 00000000 00:00 0
-706263d000-706263f000 r--p 0002e000 fc:00 2366 /system/lib64/libmediadrmmetrics_lite.so
-706263f000-7062640000 rw-p 00030000 fc:00 2366 /system/lib64/libmediadrmmetrics_lite.so
-706264b000-706266b000 rw-p 00000000 00:05 10269727 [anon:dalvik-CompilerMetadata]
-706266b000-70626d4000 r-xp 00000000 fc:00 2727 /system/lib64/libmedia_jni.so
-70626d4000-70626eb000 ---p 00000000 00:00 0
-70626eb000-70626f2000 r--p 00069000 fc:00 2727 /system/lib64/libmedia_jni.so
-70626f2000-70626f3000 rw-p 00070000 fc:00 2727 /system/lib64/libmedia_jni.so
-7062703000-7062732000 r-xp 00000000 fc:00 2399 /system/lib64/libcamera2ndk.so
-7062732000-7062748000 ---p 00000000 00:00 0
-7062748000-706274b000 r--p 0003d000 fc:00 2399 /system/lib64/libcamera2ndk.so
-706274b000-7062750000 rw-p 00040000 fc:00 2399 /system/lib64/libcamera2ndk.so
-7062768000-7062788000 rw-p 00000000 00:05 10269726 [anon:dalvik-CompilerMetadata]
-7062788000-70627ee000 r-xp 00000000 fc:00 2974 /system/lib64/android.hardware.drm@1.0.so
-70627ee000-7062805000 ---p 00000000 00:00 0
-7062805000-706280d000 r--p 00068000 fc:00 2974 /system/lib64/android.hardware.drm@1.0.so
-706280d000-706280e000 rw-p 00070000 fc:00 2974 /system/lib64/android.hardware.drm@1.0.so
-706281a000-706281b000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-706281b000-706281f000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-706281f000-7062843000 r--s 00000000 fc:00 142 /system/fonts/NotoSansKhmer-VF.ttf
-7062843000-7062886000 r-xp 00000000 fc:00 2637 /system/lib64/android.hardware.drm@1.1.so
-7062886000-70628a5000 ---p 00000000 00:00 0
-70628a5000-70628ab000 r--p 0004a000 fc:00 2637 /system/lib64/android.hardware.drm@1.1.so
-70628ab000-70628ac000 rw-p 00050000 fc:00 2637 /system/lib64/android.hardware.drm@1.1.so
-70628b0000-70628b1000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70628b1000-70628b5000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70628b5000-70628db000 r--s 00000000 fc:00 137 /system/fonts/NotoSansSinhala-Bold.ttf
-70628db000-7062907000 r-xp 00000000 fc:00 2478 /system/lib64/libmediadrm.so
-7062907000-7062918000 ---p 00000000 00:00 0
-7062918000-7062920000 r--p 00038000 fc:00 2478 /system/lib64/libmediadrm.so
-7062920000-7062921000 rw-p 00040000 fc:00 2478 /system/lib64/libmediadrm.so
-7062922000-7062929000 rw-p 00000000 fc:00 583 /system/etc/event-log-tags
-7062929000-7062951000 r--s 00000000 fc:00 296 /system/fonts/NotoSansSinhala-Regular.ttf
-7062951000-7062997000 r-xp 00000000 fc:00 2448 /system/lib64/libaaudio.so
-7062997000-70629ac000 ---p 00000000 00:00 0
-70629ac000-70629b2000 r--p 0004a000 fc:00 2448 /system/lib64/libaaudio.so
-70629b2000-70629ba000 rw-p 00050000 fc:00 2448 /system/lib64/libaaudio.so
-70629ba000-70629bb000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70629bb000-70629bf000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70629bf000-70629c0000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70629c0000-70629c3000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70629c3000-70629c4000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70629c4000-70629c5000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70629c5000-70629c9000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70629c9000-70629e3000 r-xp 00000000 fc:00 2940 /system/lib64/libandroid.so
-70629e3000-70629f3000 ---p 00000000 00:00 0
-70629f3000-70629f6000 r--p 0001d000 fc:00 2940 /system/lib64/libandroid.so
-70629f6000-70629f7000 rw-p 00020000 fc:00 2940 /system/lib64/libandroid.so
-70629f8000-70629f9000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70629f9000-70629fc000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70629fc000-70629fd000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70629fd000-7062a3e000 r--s 00000000 fc:00 216 /system/fonts/NotoSerif-BoldItalic.ttf
-7062a3e000-7062b06000 rw-p 00000000 00:05 10270984 [anon:dalvik-indirect ref table]
-7062b06000-7062bce000 rw-p 00000000 00:05 10270983 [anon:dalvik-indirect ref table]
-7062bce000-7062dce000 rw-p 00000000 00:05 10270726 [anon:dalvik-rb copying gc mark stack]
-7062dce000-70635ce000 rw-p 00000000 00:05 10270725 [anon:dalvik-concurrent copying gc mark stack]
-70635ce000-7063dcf000 rw-p 00000000 00:05 10270724 [anon:dalvik-live stack]
-7063dcf000-70645d0000 rw-p 00000000 00:05 10270723 [anon:dalvik-allocation stack]
-70645d0000-70649d1000 rw-p 00000000 00:05 10270721 [anon:dalvik-card table]
-70649d1000-7064ad1000 rw-p 00000000 00:05 10267648 [anon:dalvik-large object free list space allocation info map]
-7064ad1000-7065ad1000 rw-p 00000000 00:05 10267644 [anon:dalvik-region space live bitmap]
-7065ad1000-7065bd1000 rw-p 00000000 00:05 10267642 [anon:dalvik-allocspace zygote / non moving space mark-bitmap 0]
-7065bd1000-7065cd1000 rw-p 00000000 00:05 10267641 [anon:dalvik-allocspace zygote / non moving space live-bitmap 0]
-7065cd1000-7065cd2000 r-xp 00000000 fc:00 2946 /system/lib64/libsigchain.so
-7065cd2000-7065cf0000 ---p 00000000 00:00 0
-7065cf0000-7065cf1000 r--p 0000f000 fc:00 2946 /system/lib64/libsigchain.so
-7065cf1000-7065cf2000 rw-p 00010000 fc:00 2946 /system/lib64/libsigchain.so
-7065cf4000-7065d0f000 r--s 00000000 fc:00 190 /system/fonts/NotoSansMyanmar-Bold.ttf
-7065d0f000-7065d22000 r-xp 00000000 fc:00 2405 /system/lib64/liblz4.so
-7065d22000-7065d3e000 ---p 00000000 00:00 0
-7065d3e000-7065d3f000 r--p 0001f000 fc:00 2405 /system/lib64/liblz4.so
-7065d3f000-7065d40000 rw-p 00020000 fc:00 2405 /system/lib64/liblz4.so
-7065d40000-7065d5a000 r--s 00000000 fc:00 222 /system/fonts/NotoSansMyanmarUI-Regular.ttf
-7065d5a000-7065d5e000 r-xp 00000000 fc:00 2609 /system/lib64/libtombstoned_client.so
-7065d5e000-7065d79000 ---p 00000000 00:00 0
-7065d79000-7065d7a000 r--p 0000f000 fc:00 2609 /system/lib64/libtombstoned_client.so
-7065d7a000-7065d7b000 rw-p 00010000 fc:00 2609 /system/lib64/libtombstoned_client.so
-7065d7f000-7065d80000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-7065d80000-7065d84000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-7065d84000-706636e000 r-xp 00000000 fc:00 2671 /system/lib64/libart.so
-706636e000-706638d000 ---p 00000000 00:00 0
-706638d000-706639e000 r--p 005ef000 fc:00 2671 /system/lib64/libart.so
-706639e000-70663a1000 rw-p 00600000 fc:00 2671 /system/lib64/libart.so
-70663a1000-70663a4000 rw-p 00000000 00:00 0 [anon:.bss]
-70663a6000-70663c6000 rw-p 00000000 00:05 10269725 [anon:dalvik-CompilerMetadata]
-70663c6000-70663c8000 r-xp 00000000 fc:00 2673 /system/lib64/libmetricslogger.so
-70663c8000-70663e5000 ---p 00000000 00:00 0
-70663e5000-70663e6000 r--p 0000f000 fc:00 2673 /system/lib64/libmetricslogger.so
-70663e6000-70663e7000 rw-p 00010000 fc:00 2673 /system/lib64/libmetricslogger.so
-70663e7000-7066400000 r--s 00000000 fc:00 110 /system/fonts/NotoSansLepcha-Regular.ttf
-7066400000-7066800000 rw-p 00000000 00:00 0 [anon:libc_malloc]
-7066803000-706681e000 r--s 00000000 fc:00 297 /system/fonts/NotoSansMyanmar-Regular.ttf
-706681e000-7066821000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066821000-7066822000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066822000-7066b1d000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066b1d000-7066b1e000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066b1e000-7066ba0000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066ba0000-7066ba1000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066ba1000-7066ba2000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066ba2000-7066ba5000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066ba5000-7066ba6000 r--p 00000000 00:00 0 [anon:cfi shadow]
-7066ba6000-70e681e000 r--p 00000000 00:00 0 [anon:cfi shadow]
-70e681e000-70e6854000 r-xp 00000000 fc:00 2431 /system/lib64/libstagefright_foundation.so
-70e6854000-70e6865000 ---p 00000000 00:00 0
-70e6865000-70e6867000 r--p 0003e000 fc:00 2431 /system/lib64/libstagefright_foundation.so
-70e6867000-70e686c000 rw-p 00040000 fc:00 2431 /system/lib64/libstagefright_foundation.so
-70e686d000-70e686e000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70e686e000-70e6871000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70e6871000-70e6873000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70e6873000-70e6876000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70e6876000-70e6877000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70e6877000-70e688c000 r--s 00000000 fc:00 301 /system/fonts/NotoSansSinhalaUI-Bold.otf
-70e688c000-70e688e000 r-xp 00000000 fc:00 2943 /system/lib64/libion.so
-70e688e000-70e68ab000 ---p 00000000 00:00 0
-70e68ab000-70e68ac000 r--p 0000f000 fc:00 2943 /system/lib64/libion.so
-70e68ac000-70e68ad000 rw-p 00010000 fc:00 2943 /system/lib64/libion.so
-70e68ad000-70e68af000 rw-p 00000000 00:05 10282496 [anon:dalvik-indirect ref table]
-70e68af000-70e68b1000 rw-p 00000000 00:05 10282493 [anon:dalvik-indirect ref table]
-70e68b1000-70e68ee000 r--s 00000000 fc:00 256 /system/fonts/NotoSerif-Italic.ttf
-70e68ee000-70e6910000 r-xp 00000000 fc:00 2502 /system/lib64/libhidlbase.so
-70e6910000-70e692c000 ---p 00000000 00:00 0
-70e692c000-70e692e000 r--p 0002e000 fc:00 2502 /system/lib64/libhidlbase.so
-70e692e000-70e692f000 rw-p 00030000 fc:00 2502 /system/lib64/libhidlbase.so
-70e6930000-70e693f000 r--s 00000000 fc:00 1082 /system/usr/hyphen-data/hyph-en-us.hyb
-70e693f000-70e6954000 r--s 00000000 fc:00 138 /system/fonts/NotoSansSinhalaUI-Regular.otf
-70e6954000-70e6978000 r-xp 00000000 fc:00 2482 /system/lib64/libui.so
-70e6978000-70e6992000 ---p 00000000 00:00 0
-70e6992000-70e6994000 r--p 0002e000 fc:00 2482 /system/lib64/libui.so
-70e6994000-70e6995000 rw-p 00030000 fc:00 2482 /system/lib64/libui.so
-70e6996000-70e69a2000 r--s 00000000 fc:00 1117 /system/usr/hyphen-data/hyph-en-gb.hyb
-70e69a2000-70e69b7000 r--s 00000000 fc:00 202 /system/fonts/NotoSerifSinhala-Bold.otf
-70e69b7000-70e69cb000 r--s 00000000 fc:00 124 /system/fonts/NotoSansOriyaUI-Bold.ttf
-70e69cb000-70e69e1000 r-xp 00000000 fc:00 2537 /system/lib64/liblog.so
-70e69e1000-70e69fa000 ---p 00000000 00:00 0
-70e69fa000-70e69fb000 r--p 0001f000 fc:00 2537 /system/lib64/liblog.so
-70e69fb000-70e69fc000 rw-p 00020000 fc:00 2537 /system/lib64/liblog.so
-70e69fc000-70e69fe000 rw-p 00000000 00:05 10266158 [anon:dalvik-indirect ref table]
-70e69fe000-70e69ff000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70e69ff000-70e6a02000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70e6a02000-70e6a03000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70e6a03000-70e6a05000 r-xp 00000000 fc:00 2489 /system/lib64/android.hidl.token@1.0-utils.so
-70e6a05000-70e6a22000 ---p 00000000 00:00 0
-70e6a22000-70e6a23000 r--p 0000f000 fc:00 2489 /system/lib64/android.hidl.token@1.0-utils.so
-70e6a23000-70e6a24000 rw-p 00010000 fc:00 2489 /system/lib64/android.hidl.token@1.0-utils.so
-70e6a25000-70e6a2e000 r--s 00000000 fc:00 1120 /system/usr/hyphen-data/hyph-ga.hyb
-70e6a2e000-70e6a42000 r--s 00000000 fc:00 109 /system/fonts/NotoSansOriyaUI-Regular.ttf
-70e6a42000-70e6a59000 r-xp 00000000 fc:00 2446 /system/lib64/android.hardware.graphics.mapper@2.0.so
-70e6a59000-70e6a6e000 ---p 00000000 00:00 0
-70e6a6e000-70e6a70000 r--p 0001e000 fc:00 2446 /system/lib64/android.hardware.graphics.mapper@2.0.so
-70e6a70000-70e6a71000 rw-p 00020000 fc:00 2446 /system/lib64/android.hardware.graphics.mapper@2.0.so
-70e6a72000-70e6a78000 r--s 00000000 fc:00 1084 /system/usr/hyphen-data/hyph-et.hyb
-70e6a78000-70e6a9d000 r--s 00000000 fc:00 207 /system/fonts/NotoSerifTelugu-Bold.ttf
-70e6a9d000-70e6a9f000 r-xp 00000000 fc:00 2330 /system/lib64/android.hardware.configstore-utils.so
-70e6a9f000-70e6abc000 ---p 00000000 00:00 0
-70e6abc000-70e6abd000 r--p 0000f000 fc:00 2330 /system/lib64/android.hardware.configstore-utils.so
-70e6abd000-70e6abe000 rw-p 00010000 fc:00 2330 /system/lib64/android.hardware.configstore-utils.so
-70e6abe000-70e6ac0000 r--s f8042000 00:10 20630 /dev/kgsl-3d0
-70e6ac0000-70e6adc000 r--s 00000000 fc:00 172 /system/fonts/NotoSansTeluguUI-Bold.ttf
-70e6adc000-70e6ae0000 r-xp 00000000 fc:00 2555 /system/lib64/libstagefright_omx_utils.so
-70e6ae0000-70e6afb000 ---p 00000000 00:00 0
-70e6afb000-70e6afc000 r--p 0000f000 fc:00 2555 /system/lib64/libstagefright_omx_utils.so
-70e6afc000-70e6afd000 rw-p 00010000 fc:00 2555 /system/lib64/libstagefright_omx_utils.so
-70e6afd000-70e6afe000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70e6afe000-70e6b02000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70e6b02000-70e6b27000 r--s 00000000 fc:00 271 /system/fonts/NotoSerifTelugu-Regular.ttf
-70e6b27000-70e6b61000 r-xp 00000000 fc:00 2695 /system/lib64/libdexfile.so
-70e6b61000-70e6b73000 ---p 00000000 00:00 0
-70e6b73000-70e6b75000 r--p 0003e000 fc:00 2695 /system/lib64/libdexfile.so
-70e6b75000-70e6b76000 rw-p 00040000 fc:00 2695 /system/lib64/libdexfile.so
-70e6b76000-70e6b78000 rw-p 00000000 00:05 10253452 [anon:dalvik-indirect ref table]
-70e6b78000-70e6b85000 r--s 00000000 fc:00 1080 /system/usr/hyphen-data/hyph-cu.hyb
-70e6b85000-70e6b96000 r-xp 00000000 fc:00 2957 /system/lib64/libaudioutils.so
-70e6b96000-70e6bb4000 ---p 00000000 00:00 0
-70e6bb4000-70e6bb5000 r--p 0001f000 fc:00 2957 /system/lib64/libaudioutils.so
-70e6bb5000-70e6bb6000 rw-p 00020000 fc:00 2957 /system/lib64/libaudioutils.so
-70e6bb6000-70e6bb7000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70e6bb7000-70e6bba000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70e6bba000-70e6bbb000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70e6bbb000-70e6bd7000 r--s 00000000 fc:00 132 /system/fonts/NotoSansTeluguUI-Regular.ttf
-70e6bd7000-70e6bdc000 r-xp 00000000 fc:00 2409 /system/lib64/libprocessgroup.so
-70e6bdc000-70e6bf6000 ---p 00000000 00:00 0
-70e6bf6000-70e6bf7000 r--p 0000f000 fc:00 2409 /system/lib64/libprocessgroup.so
-70e6bf7000-70e6bf8000 rw-p 00010000 fc:00 2409 /system/lib64/libprocessgroup.so
-70e6bf8000-70e6c09000 r--s 00000000 fc:00 79 /system/fonts/NotoSansNewa-Regular.otf
-70e6c09000-70e6c1c000 r-xp 00000000 fc:00 2329 /system/lib64/android.hidl.memory.token@1.0.so
-70e6c1c000-70e6c36000 ---p 00000000 00:00 0
-70e6c36000-70e6c38000 r--p 0001e000 fc:00 2329 /system/lib64/android.hidl.memory.token@1.0.so
-70e6c38000-70e6c39000 rw-p 00020000 fc:00 2329 /system/lib64/android.hidl.memory.token@1.0.so
-70e6c3a000-70e6c4f000 r--s 00000000 fc:00 253 /system/fonts/NotoSansOriya-Bold.ttf
-70e6c4f000-70e6c6b000 r-xp 00000000 fc:00 2407 /system/lib64/libutils.so
-70e6c6b000-70e6c7e000 ---p 00000000 00:00 0
-70e6c7e000-70e6c7f000 r--p 0001f000 fc:00 2407 /system/lib64/libutils.so
-70e6c7f000-70e6c80000 rw-p 00020000 fc:00 2407 /system/lib64/libutils.so
-70e6c80000-70e6c9d000 r-xp 00000000 fc:00 2934 /system/lib64/libtinyxml2.so
-70e6c9d000-70e6cba000 ---p 00000000 00:00 0
-70e6cba000-70e6cbc000 r--p 0001e000 fc:00 2934 /system/lib64/libtinyxml2.so
-70e6cbc000-70e6cbf000 rw-p 00020000 fc:00 2934 /system/lib64/libtinyxml2.so
-70e6cbf000-70e6ccf000 r--s 00000000 fc:00 80 /system/fonts/NotoSansMarchen-Regular.otf
-70e6ccf000-70e6ce0000 r-xp 00000000 fc:00 2655 /system/lib64/libbase.so
-70e6ce0000-70e6cfe000 ---p 00000000 00:00 0
-70e6cfe000-70e6cff000 r--p 0001f000 fc:00 2655 /system/lib64/libbase.so
-70e6cff000-70e6d00000 rw-p 00020000 fc:00 2655 /system/lib64/libbase.so
-70e6d00000-70e6d09000 r--s 00000000 fc:00 1113 /system/usr/hyphen-data/hyph-cy.hyb
-70e6d09000-70e6d50000 r-xp 00000000 fc:00 2495 /system/lib64/libRScpp.so
-70e6d50000-70e6d68000 ---p 00000000 00:00 0
-70e6d68000-70e6d69000 r--p 0004f000 fc:00 2495 /system/lib64/libRScpp.so
-70e6d69000-70e6d6a000 rw-p 00050000 fc:00 2495 /system/lib64/libRScpp.so
-70e6d6b000-70e6d6d000 r--s 00088000 103:1d 1736830 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk
-70e6d6d000-70e6d7d000 r--s 00000000 fc:00 238 /system/fonts/NotoSansVai-Regular.ttf
-70e6d7d000-70e6d98000 r--s 00000000 fc:00 276 /system/fonts/NotoSansTelugu-Bold.ttf
-70e6d98000-70e6f2b000 r-xp 00000000 fc:00 2961 /system/lib64/libicuuc.so
-70e6f2b000-70e6f47000 ---p 00000000 00:00 0
-70e6f47000-70e6f5c000 r--p 0019b000 fc:00 2961 /system/lib64/libicuuc.so
-70e6f5c000-70e6f5d000 rw-p 001b0000 fc:00 2961 /system/lib64/libicuuc.so
-70e6f5d000-70e6f5e000 rw-p 00000000 00:00 0 [anon:.bss]
-70e6f5f000-70e6f68000 r--s 00000000 fc:00 159 /system/fonts/NotoSansLinearA-Regular.otf
-70e6f68000-70e6f84000 r--s 00000000 fc:00 170 /system/fonts/NotoSansTelugu-Regular.ttf
-70e6f84000-70e7058000 r-xp 00000000 fc:00 2356 /system/lib64/libc.so
-70e7058000-70e706e000 ---p 00000000 00:00 0
-70e706e000-70e7074000 r--p 000da000 fc:00 2356 /system/lib64/libc.so
-70e7074000-70e7076000 rw-p 000e0000 fc:00 2356 /system/lib64/libc.so
-70e7076000-70e7077000 rw-p 00000000 00:00 0 [anon:.bss]
-70e7077000-70e7078000 r--p 00000000 00:00 0 [anon:.bss]
-70e7078000-70e7080000 rw-p 00000000 00:00 0 [anon:.bss]
-70e7080000-70e7087000 r--s 00000000 fc:00 102 /system/fonts/NotoSansSharada-Regular.otf
-70e7087000-70e708e000 r-xp 00000000 fc:00 2378 /system/lib64/libheif.so
-70e708e000-70e70a4000 ---p 00000000 00:00 0
-70e70a4000-70e70a6000 r--p 0000e000 fc:00 2378 /system/lib64/libheif.so
-70e70a6000-70e70a7000 rw-p 00010000 fc:00 2378 /system/lib64/libheif.so
-70e70a7000-70e70a9000 r--s 00000000 fc:00 1116 /system/usr/hyphen-data/hyph-sl.hyb
-70e70a9000-70e70ab000 r--s 00000000 fc:00 1147 /system/usr/hyphen-data/hyph-mn-cyrl.hyb
-70e70ab000-70e70c5000 r--s 00000000 fc:00 291 /system/fonts/NotoSansBengaliUI-Bold.ttf
-70e70c5000-70e70ea000 r-xp 00000000 fc:00 2545 /system/lib64/libEGL.so
-70e70ea000-70e7109000 ---p 00000000 00:00 0
-70e7109000-70e710d000 r--p 0002c000 fc:00 2545 /system/lib64/libEGL.so
-70e710d000-70e710e000 rw-p 00030000 fc:00 2545 /system/lib64/libEGL.so
-70e710e000-70e7115000 rw-p 00000000 00:00 0 [anon:.bss]
-70e7115000-70e7119000 r--s 00000000 fc:00 1143 /system/usr/hyphen-data/hyph-es.hyb
-70e7119000-70e712e000 r--s 00000000 fc:00 71 /system/fonts/NotoSansOriya-Regular.ttf
-70e712e000-70e717a000 r--s 00000000 fc:00 272 /system/fonts/Roboto-Thin.ttf
-70e717a000-70e71db000 r-xp 00000000 fc:00 2393 /system/lib64/libpdx_default_transport.so
-70e71db000-70e71f7000 ---p 00000000 00:00 0
-70e71f7000-70e71f9000 r--p 0006e000 fc:00 2393 /system/lib64/libpdx_default_transport.so
-70e71f9000-70e71fa000 rw-p 00070000 fc:00 2393 /system/lib64/libpdx_default_transport.so
-70e71fa000-70e71fb000 rw-p 00000000 00:00 0 [anon:.bss]
-70e71fc000-70e71fe000 r--s 00000000 fc:00 1107 /system/usr/hyphen-data/hyph-fr.hyb
-70e71fe000-70e7200000 r--s 00000000 fc:00 1097 /system/usr/hyphen-data/hyph-da.hyb
-70e7200000-70e7223000 r-xp 00000000 fc:00 2380 /system/lib64/libminikin.so
-70e7223000-70e723e000 ---p 00000000 00:00 0
-70e723e000-70e723f000 r--p 0002f000 fc:00 2380 /system/lib64/libminikin.so
-70e723f000-70e7240000 rw-p 00030000 fc:00 2380 /system/lib64/libminikin.so
-70e7241000-70e724d000 r--s 00000000 fc:00 179 /system/fonts/NotoSansTaiTham-Regular.ttf
-70e724d000-70e725c000 r-xp 00000000 fc:00 2527 /system/lib64/libmediautils.so
-70e725c000-70e7279000 ---p 00000000 00:00 0
-70e7279000-70e727b000 r--p 0001e000 fc:00 2527 /system/lib64/libmediautils.so
-70e727b000-70e727c000 rw-p 00020000 fc:00 2527 /system/lib64/libmediautils.so
-70e727d000-70e7283000 r--s 00000000 fc:00 136 /system/fonts/NotoSansMiao-Regular.otf
-70e7283000-70e74d2000 r-xp 00000000 fc:00 2349 /system/lib64/libicui18n.so
-70e74d2000-70e74e6000 ---p 00000000 00:00 0
-70e74e6000-70e74fa000 r--p 0025c000 fc:00 2349 /system/lib64/libicui18n.so
-70e74fa000-70e74fb000 rw-p 00270000 fc:00 2349 /system/lib64/libicui18n.so
-70e74fc000-70e74ff000 r--s 00000000 103:1d 1474562 /data/resource-cache/vendor@overlay@framework-res__auto_generated_rro.apk@idmap
-70e74ff000-70e750c000 r--s 00000000 fc:00 126 /system/fonts/NotoSansSyriacWestern-Regular.ttf
-70e750c000-70e751b000 r-xp 00000000 fc:00 2466 /system/lib64/libmediaextractor.so
-70e751b000-70e753a000 ---p 00000000 00:00 0
-70e753a000-70e753b000 r--p 0000f000 fc:00 2466 /system/lib64/libmediaextractor.so
-70e753b000-70e753c000 rw-p 00010000 fc:00 2466 /system/lib64/libmediaextractor.so
-70e753d000-70e7540000 r--s 00000000 fc:00 107 /system/fonts/NotoSansPauCinHau-Regular.otf
-70e7540000-70e7593000 r-xp 00000000 fc:00 2363 /system/lib64/libandroidfw.so
-70e7593000-70e75ac000 ---p 00000000 00:00 0
-70e75ac000-70e75af000 r--p 0005d000 fc:00 2363 /system/lib64/libandroidfw.so
-70e75af000-70e75b0000 rw-p 00060000 fc:00 2363 /system/lib64/libandroidfw.so
-70e75b0000-70e75b2000 r--s 00000000 fc:00 1083 /system/usr/hyphen-data/hyph-be.hyb
-70e75b2000-70e75cd000 r--s 00000000 fc:00 270 /system/fonts/NotoSansBengaliUI-Regular.ttf
-70e75cd000-70e75cf000 r-xp 00000000 fc:00 2701 /system/lib64/libmemtrack.so
-70e75cf000-70e75ec000 ---p 00000000 00:00 0
-70e75ec000-70e75ed000 r--p 0000f000 fc:00 2701 /system/lib64/libmemtrack.so
-70e75ed000-70e75ee000 rw-p 00010000 fc:00 2701 /system/lib64/libmemtrack.so
-70e75ee000-70e75f0000 r--s 00000000 fc:00 209 /system/fonts/NotoSansSoraSompeng-Regular.otf
-70e75f0000-70e760d000 r--s 00000000 fc:00 243 /system/fonts/NotoSerifBengali-Bold.ttf
-70e760d000-70e7613000 r-xp 00000000 fc:00 2667 /system/lib64/libutilscallstack.so
-70e7613000-70e762c000 ---p 00000000 00:00 0
-70e762c000-70e762d000 r--p 0000f000 fc:00 2667 /system/lib64/libutilscallstack.so
-70e762d000-70e762e000 rw-p 00010000 fc:00 2667 /system/lib64/libutilscallstack.so
-70e762e000-70e7632000 r--s 00000000 fc:00 99 /system/fonts/NotoSansPahawhHmong-Regular.otf
-70e7632000-70e764f000 r--s 00000000 fc:00 205 /system/fonts/NotoSerifBengali-Regular.ttf
-70e764f000-70e7661000 r-xp 00000000 fc:00 2710 /system/lib64/libcutils.so
-70e7661000-70e767d000 ---p 00000000 00:00 0
-70e767d000-70e767f000 r--p 0001e000 fc:00 2710 /system/lib64/libcutils.so
-70e767f000-70e7680000 rw-p 00020000 fc:00 2710 /system/lib64/libcutils.so
-70e7680000-70e7683000 r--s 00000000 fc:00 257 /system/fonts/NotoSansPalmyrene-Regular.otf
-70e7683000-70e7697000 r--s 00000000 fc:00 78 /system/fonts/NotoSansKannadaUI-Bold.ttf
-70e7697000-70e769a000 r-xp 00000000 fc:00 2362 /system/lib64/libstagefright_http_support.so
-70e769a000-70e76b6000 ---p 00000000 00:00 0
-70e76b6000-70e76b7000 r--p 0000f000 fc:00 2362 /system/lib64/libstagefright_http_support.so
-70e76b7000-70e76b8000 rw-p 00010000 fc:00 2362 /system/lib64/libstagefright_http_support.so
-70e76b8000-70e76b9000 rw-p 00000000 00:00 0 [anon:linker_alloc_lob]
-70e76b9000-70e76be000 r--s 00000000 fc:00 165 /system/fonts/NotoSansMeroitic-Regular.otf
-70e76be000-70e76cb000 r--s 00000000 fc:00 112 /system/fonts/NotoSansSyriacEastern-Regular.ttf
-70e76cb000-70e76de000 r-xp 00000000 fc:00 2343 /system/lib64/libsensor.so
-70e76de000-70e76f5000 ---p 00000000 00:00 0
-70e76f5000-70e76f8000 r--p 0001d000 fc:00 2343 /system/lib64/libsensor.so
-70e76f8000-70e76f9000 rw-p 00020000 fc:00 2343 /system/lib64/libsensor.so
-70e76f9000-70e76fc000 r--s 00000000 fc:00 157 /system/fonts/NotoSansOldPermic-Regular.otf
-70e76fc000-70e7708000 r--s 00000000 fc:00 189 /system/fonts/NotoSansSyriacEstrangela-Regular.ttf
-70e7708000-70e771d000 r-xp 00000000 fc:00 2339 /system/lib64/android.hidl.token@1.0.so
-70e771d000-70e7735000 ---p 00000000 00:00 0
-70e7735000-70e7737000 r--p 0001e000 fc:00 2339 /system/lib64/android.hidl.token@1.0.so
-70e7737000-70e7738000 rw-p 00020000 fc:00 2339 /system/lib64/android.hidl.token@1.0.so
-70e7738000-70e7739000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70e7739000-70e773b000 r--s 00000000 fc:00 267 /system/fonts/NotoSansOldNorthArabian-Regular.otf
-70e773b000-70e7740000 r--s 00000000 fc:00 208 /system/fonts/NotoSansManichaean-Regular.otf
-70e7740000-70e775c000 r--s 00000000 fc:00 118 /system/fonts/NotoSansGujaratiUI-Bold.ttf
-70e775c000-70e7767000 r-xp 00000000 fc:00 2525 /system/lib64/libappfuse.so
-70e7767000-70e777b000 ---p 00000000 00:00 0
-70e777b000-70e777c000 r--p 0000f000 fc:00 2525 /system/lib64/libappfuse.so
-70e777c000-70e777d000 rw-p 00010000 fc:00 2525 /system/lib64/libappfuse.so
-70e777e000-70e7795000 r--s 00000000 fc:00 250 /system/fonts/NotoSerifKannada-Bold.ttf
-70e7795000-70e7798000 r-xp 00000000 fc:00 2413 /system/lib64/libpackagelistparser.so
-70e7798000-70e77b4000 ---p 00000000 00:00 0
-70e77b4000-70e77b5000 r--p 0000f000 fc:00 2413 /system/lib64/libpackagelistparser.so
-70e77b5000-70e77b6000 rw-p 00010000 fc:00 2413 /system/lib64/libpackagelistparser.so
-70e77b6000-70e77b8000 r--s 00000000 fc:00 147 /system/fonts/NotoSansNabataean-Regular.otf
-70e77b8000-70e77ba000 r--s 00000000 fc:00 146 /system/fonts/NotoSansMultani-Regular.otf
-70e77ba000-70e77c1000 r--s 00000000 fc:00 214 /system/fonts/NotoSansPhagsPa-Regular.ttf
-70e77c1000-70e77de000 r--s 00000000 fc:00 90 /system/fonts/NotoSansGujaratiUI-Regular.ttf
-70e77de000-70e77e0000 r-xp 00000000 fc:00 2430 /system/lib64/libdl.so
-70e77e0000-70e77fd000 ---p 00000000 00:00 0
-70e77fd000-70e77fe000 r--p 0000f000 fc:00 2430 /system/lib64/libdl.so
-70e77fe000-70e77ff000 r--p 00000000 00:00 0 [anon:.bss]
-70e7800000-70e7809000 r--s 00000000 fc:00 258 /system/fonts/NotoSansSymbols-Regular-Subsetted2.ttf
-70e7809000-70e7857000 r-xp 00000000 fc:00 2560 /system/lib64/libjpeg.so
-70e7857000-70e7868000 ---p 00000000 00:00 0
-70e7868000-70e7869000 r--p 0004f000 fc:00 2560 /system/lib64/libjpeg.so
-70e7869000-70e786a000 rw-p 00050000 fc:00 2560 /system/lib64/libjpeg.so
-70e786a000-70e7887000 r--s 00000000 fc:00 237 /system/fonts/NotoSansGujarati-Bold.ttf
-70e7887000-70e788a000 r-xp 00000000 fc:00 2608 /system/lib64/libnetd_client.so
-70e788a000-70e78a6000 ---p 00000000 00:00 0
-70e78a6000-70e78a7000 r--p 0000f000 fc:00 2608 /system/lib64/libnetd_client.so
-70e78a7000-70e78a8000 rw-p 00010000 fc:00 2608 /system/lib64/libnetd_client.so
-70e78a8000-70e78aa000 r--s 00000000 fc:00 290 /system/fonts/NotoSansMro-Regular.otf
-70e78aa000-70e78b9000 r--s 00000000 fc:00 84 /system/fonts/NotoSansLinearB-Regular.ttf
-70e78b9000-70e78d7000 r--s 00000000 fc:00 287 /system/fonts/NotoSansGujarati-Regular.ttf
-70e78d7000-70e78d8000 r-xp 00000000 fc:00 2651 /system/lib64/libvndksupport.so
-70e78d8000-70e78f6000 ---p 00000000 00:00 0
-70e78f6000-70e78f7000 r--p 0000f000 fc:00 2651 /system/lib64/libvndksupport.so
-70e78f7000-70e78f8000 rw-p 00010000 fc:00 2651 /system/lib64/libvndksupport.so
-70e78f9000-70e78fc000 r--s 00000000 fc:00 178 /system/fonts/NotoSansTaiLe-Regular.ttf
-70e78fc000-70e7900000 r--s 00000000 fc:00 163 /system/fonts/NotoSansTifinagh-Regular.ttf
-70e7900000-70e7906000 r-xp 00000000 fc:00 2659 /system/lib64/libnativeloader.so
-70e7906000-70e791f000 ---p 00000000 00:00 0
-70e791f000-70e7920000 r--p 0000f000 fc:00 2659 /system/lib64/libnativeloader.so
-70e7920000-70e7921000 rw-p 00010000 fc:00 2659 /system/lib64/libnativeloader.so
-70e7921000-70e7923000 r--s 00000000 fc:00 268 /system/fonts/NotoSansHatran-Regular.otf
-70e7923000-70e7927000 r--s 00000000 fc:00 195 /system/fonts/NotoSansTaiViet-Regular.ttf
-70e7927000-70e7945000 r--s 00000000 fc:00 139 /system/fonts/NotoSansDevanagariUI-Bold.ttf
-70e7945000-70e79a3000 r-xp 00000000 fc:00 2450 /system/lib64/libharfbuzz_ng.so
-70e79a3000-70e79b3000 ---p 00000000 00:00 0
-70e79b3000-70e79b5000 r--p 0005e000 fc:00 2450 /system/lib64/libharfbuzz_ng.so
-70e79b5000-70e79b6000 rw-p 00060000 fc:00 2450 /system/lib64/libharfbuzz_ng.so
-70e79b6000-70e79c5000 r--s 00000000 fc:00 111 /system/fonts/NotoSansKaithi-Regular.ttf
-70e79c5000-70e7a92000 r-xp 00000000 fc:00 2332 /system/lib64/libc++.so
-70e7a92000-70e7aae000 ---p 00000000 00:00 0
-70e7aae000-70e7ab8000 r--p 000d6000 fc:00 2332 /system/lib64/libc++.so
-70e7ab8000-70e7ab9000 rw-p 000e0000 fc:00 2332 /system/lib64/libc++.so
-70e7ab9000-70e7abc000 rw-p 00000000 00:00 0 [anon:.bss]
-70e7abc000-70e7abe000 r--s 00000000 fc:00 73 /system/fonts/NotoSansBassaVah-Regular.otf
-70e7abe000-70e7ac8000 r--s 00000000 fc:00 254 /system/fonts/NotoSansJavanese-Regular.ttf
-70e7ac8000-70e7acb000 r-xp 00000000 fc:00 2660 /system/lib64/libnativebridge.so
-70e7acb000-70e7ae7000 ---p 00000000 00:00 0
-70e7ae7000-70e7ae8000 r--p 0000f000 fc:00 2660 /system/lib64/libnativebridge.so
-70e7ae8000-70e7ae9000 rw-p 00010000 fc:00 2660 /system/lib64/libnativebridge.so
-70e7ae9000-70e7aee000 r--s 00000000 fc:00 158 /system/fonts/NotoSansSaurashtra-Regular.ttf
-70e7aee000-70e7b0f000 r--s 00000000 fc:00 82 /system/fonts/NotoSansDevanagari-Bold.ttf
-70e7b0f000-70e7b2e000 r-xp 00000000 fc:00 2612 /system/lib64/libpcre2.so
-70e7b2e000-70e7b3e000 ---p 00000000 00:00 0
-70e7b3e000-70e7b3f000 r--p 0001f000 fc:00 2612 /system/lib64/libpcre2.so
-70e7b3f000-70e7b40000 rw-p 00020000 fc:00 2612 /system/lib64/libpcre2.so
-70e7b40000-70e7bcc000 r-xp 00000000 fc:00 2975 /system/lib64/libgui.so
-70e7bcc000-70e7be2000 ---p 00000000 00:00 0
-70e7be2000-70e7bf5000 r--p 0008d000 fc:00 2975 /system/lib64/libgui.so
-70e7bf5000-70e7bf6000 rw-p 000a0000 fc:00 2975 /system/lib64/libgui.so
-70e7bf6000-70e7bf7000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70e7bf7000-70e7bf9000 r--s 00000000 fc:00 228 /system/fonts/NotoSansUgaritic-Regular.ttf
-70e7bf9000-70e7c08000 r--s 00000000 fc:00 89 /system/fonts/NotoSansCherokee-Regular.ttf
-70e7c08000-70e7dea000 r-xp 00000000 fc:00 2441 /system/lib64/libandroid_runtime.so
-70e7dea000-70e7e04000 ---p 00000000 00:00 0
-70e7e04000-70e7e23000 r--p 001e1000 fc:00 2441 /system/lib64/libandroid_runtime.so
-70e7e23000-70e7e24000 rw-p 00200000 fc:00 2441 /system/lib64/libandroid_runtime.so
-70e7e24000-70e7e28000 rw-p 00000000 00:00 0 [anon:.bss]
-70e7e29000-70e7e66000 r--s 00000000 fc:00 74 /system/fonts/NotoSerif-Bold.ttf
-70e7e66000-70e7ed0000 r-xp 00000000 fc:00 2547 /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
-70e7ed0000-70e7edf000 ---p 00000000 00:00 0
-70e7edf000-70e7ee1000 r--p 00069000 fc:00 2547 /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
-70e7ee1000-70e7ee4000 rw-p 0006b000 fc:00 2547 /system/lib64/libclang_rt.ubsan_standalone-aarch64-android.so
-70e7ee4000-70e89f6000 rw-p 00000000 00:00 0 [anon:.bss]
-70e89f6000-70e89fa000 r--s 00000000 fc:00 127 /system/fonts/NotoSansSylotiNagri-Regular.ttf
-70e89fa000-70e8a06000 r--s 00000000 fc:00 93 /system/fonts/NotoSansCanadianAboriginal-Regular.ttf
-70e8a06000-70e8a1b000 r-xp 00000000 fc:00 2460 /system/lib64/android.hardware.graphics.allocator@2.0.so
-70e8a1b000-70e8a33000 ---p 00000000 00:00 0
-70e8a33000-70e8a35000 r--p 0001e000 fc:00 2460 /system/lib64/android.hardware.graphics.allocator@2.0.so
-70e8a35000-70e8a36000 rw-p 00020000 fc:00 2460 /system/lib64/android.hardware.graphics.allocator@2.0.so
-70e8a36000-70e8a55000 r--s 00000000 fc:00 145 /system/fonts/NotoSansDevanagariUI-Regular.ttf
-70e8a55000-70e8a61000 r-xp 00000000 fc:00 2540 /system/lib64/libstagefright_xmlparser.so
-70e8a61000-70e8a74000 ---p 00000000 00:00 0
-70e8a74000-70e8a75000 r--p 0000f000 fc:00 2540 /system/lib64/libstagefright_xmlparser.so
-70e8a75000-70e8a76000 rw-p 00010000 fc:00 2540 /system/lib64/libstagefright_xmlparser.so
-70e8a76000-70e8a78000 r--s 00000000 fc:00 293 /system/fonts/NotoSansTagbanwa-Regular.ttf
-70e8a78000-70e8a8f000 r--s 00000000 fc:00 161 /system/fonts/NotoSerifKannada-Regular.ttf
-70e8a8f000-70e8b23000 r-xp 00000000 fc:00 2633 /system/lib64/libaudioclient.so
-70e8b23000-70e8b37000 ---p 00000000 00:00 0
-70e8b37000-70e8b49000 r--p 0009e000 fc:00 2633 /system/lib64/libaudioclient.so
-70e8b49000-70e8b55000 rw-p 000b0000 fc:00 2633 /system/lib64/libaudioclient.so
-70e8b55000-70e8b9f000 r--s 00000000 fc:00 83 /system/fonts/RobotoCondensed-Light.ttf
-70e8b9f000-70e8ba1000 r-xp 00000000 fc:00 2520 /system/lib64/libhardware_legacy.so
-70e8ba1000-70e8bbe000 ---p 00000000 00:00 0
-70e8bbe000-70e8bbf000 r--p 0000f000 fc:00 2520 /system/lib64/libhardware_legacy.so
-70e8bbf000-70e8bc0000 rw-p 00010000 fc:00 2520 /system/lib64/libhardware_legacy.so
-70e8bc0000-70e8be0000 r-xp 00000000 fc:00 2410 /system/lib64/android.hidl.memory@1.0.so
-70e8be0000-70e8bfa000 ---p 00000000 00:00 0
-70e8bfa000-70e8bfd000 r--p 0002d000 fc:00 2410 /system/lib64/android.hidl.memory@1.0.so
-70e8bfd000-70e8bfe000 rw-p 00030000 fc:00 2410 /system/lib64/android.hidl.memory@1.0.so
-70e8bfe000-70e8bff000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70e8bff000-70e8c02000 r--s 00000000 fc:00 273 /system/fonts/NotoSansSundanese-Regular.ttf
-70e8c02000-70e8c0f000 r--s 00000000 fc:00 115 /system/fonts/NotoSansAdlam-Regular.ttf
-70e8c0f000-70e8c18000 r-xp 00000000 fc:00 2350 /system/lib64/libnetdutils.so
-70e8c18000-70e8c2e000 ---p 00000000 00:00 0
-70e8c2e000-70e8c2f000 r--p 0000f000 fc:00 2350 /system/lib64/libnetdutils.so
-70e8c2f000-70e8c30000 rw-p 00010000 fc:00 2350 /system/lib64/libnetdutils.so
-70e8c30000-70e8c44000 r--s 00000000 fc:00 283 /system/fonts/NotoSansKannadaUI-Regular.ttf
-70e8c44000-70e8c45000 r-xp 00000000 fc:00 2926 /system/lib64/libhidlallocatorutils.so
-70e8c45000-70e8c63000 ---p 00000000 00:00 0
-70e8c63000-70e8c64000 r--p 0000f000 fc:00 2926 /system/lib64/libhidlallocatorutils.so
-70e8c64000-70e8c65000 rw-p 00010000 fc:00 2926 /system/lib64/libhidlallocatorutils.so
-70e8c65000-70e8c67000 r--s 00000000 fc:00 65 /system/fonts/NotoSansTagalog-Regular.ttf
-70e8c67000-70e8c70000 r--s 00000000 fc:00 294 /system/fonts/NotoSansChakma-Regular.ttf
-70e8c70000-70e8c92000 r--s 00000000 fc:00 116 /system/fonts/NotoSansDevanagari-Regular.ttf
-70e8c92000-70e8c94000 r-xp 00000000 fc:00 2501 /system/lib64/libsync.so
-70e8c94000-70e8cb1000 ---p 00000000 00:00 0
-70e8cb1000-70e8cb2000 r--p 0000f000 fc:00 2501 /system/lib64/libsync.so
-70e8cb2000-70e8cb3000 rw-p 00010000 fc:00 2501 /system/lib64/libsync.so
-70e8cb3000-70e8cc6000 r--s 00000000 fc:00 196 /system/fonts/NotoSerifSinhala-Regular.otf
-70e8cc6000-70e8d5c000 r-xp 00000000 fc:00 2403 /system/lib64/libmedia.so
-70e8d5c000-70e8d70000 ---p 00000000 00:00 0
-70e8d70000-70e8d88000 r--p 00098000 fc:00 2403 /system/lib64/libmedia.so
-70e8d88000-70e8d95000 rw-p 000b0000 fc:00 2403 /system/lib64/libmedia.so
-70e8d95000-70e8d96000 r--p 00000000 00:00 0 [anon:atexit handlers]
-70e8d96000-70e8d99000 r--s 00000000 fc:00 247 /system/fonts/NotoSansSamaritan-Regular.ttf
-70e8d99000-70e8dad000 r--s 00000000 fc:00 108 /system/fonts/NotoSansKannada-Bold.ttf
-70e8dad000-70e8dcd000 r--s 00000000 fc:00 303 /system/fonts/NotoSerifEthiopic-Bold.otf
-70e8dcd000-70e8de5000 r-xp 00000000 fc:00 2954 /system/lib64/libGLESv2.so
-70e8de5000-70e8dfc000 ---p 00000000 00:00 0
-70e8dfc000-70e8dfd000 r--p 0001f000 fc:00 2954 /system/lib64/libGLESv2.so
-70e8dfd000-70e8dfe000 rw-p 00020000 fc:00 2954 /system/lib64/libGLESv2.so
-70e8dfe000-70e8e06000 r--s 00000000 fc:00 265 /system/fonts/NotoSansBalinese-Regular.ttf
-70e8e06000-70e8e0e000 r--s 00000000 fc:00 219 /system/fonts/NotoSansLaoUI-Bold.ttf
-70e8e0e000-70e8e12000 r-xp 00000000 fc:00 2617 /system/lib64/libdebuggerd_client.so
-70e8e12000-70e8e2d000 ---p 00000000 00:00 0
-70e8e2d000-70e8e2e000 r--p 0000f000 fc:00 2617 /system/lib64/libdebuggerd_client.so
-70e8e2e000-70e8e2f000 rw-p 00010000 fc:00 2617 /system/lib64/libdebuggerd_client.so
-70e8e2f000-70e8e4b000 r--s 00000000 fc:00 211 /system/fonts/NotoSerifEthiopic-Regular.otf
-70e8e4b000-70e8e5e000 r-xp 00000000 fc:00 2484 /system/lib64/android.hardware.memtrack@1.0.so
-70e8e5e000-70e8e78000 ---p 00000000 00:00 0
-70e8e78000-70e8e7a000 r--p 0001e000 fc:00 2484 /system/lib64/android.hardware.memtrack@1.0.so
-70e8e7a000-70e8e7b000 rw-p 00020000 fc:00 2484 /system/lib64/android.hardware.memtrack@1.0.so
-70e8e7b000-70e8e7d000 r--s 00000000 fc:00 261 /system/fonts/NotoSansShavian-Regular.ttf
-70e8e7d000-70e8e80000 r--s 00000000 fc:00 204 /system/fonts/NotoSansRunic-Regular.ttf
-70e8e80000-70e8ea1000 r-xp 00000000 fc:00 2512 /system/lib64/android.hardware.configstore@1.0.so
-70e8ea1000-70e8ebb000 ---p 00000000 00:00 0
-70e8ebb000-70e8ebe000 r--p 0002d000 fc:00 2512 /system/lib64/android.hardware.configstore@1.0.so
-70e8ebe000-70e8ebf000 rw-p 00030000 fc:00 2512 /system/lib64/android.hardware.configstore@1.0.so
-70e8ebf000-70e8ee3000 r--s 00000000 fc:00 226 /system/fonts/NotoSansEthiopic-Bold.ttf
-70e8ee3000-70e8f1a000 r-xp 00000000 fc:00 2337 /system/lib64/libm.so
-70e8f1a000-70e8f32000 ---p 00000000 00:00 0
-70e8f32000-70e8f33000 r--p 0003f000 fc:00 2337 /system/lib64/libm.so
-70e8f33000-70e8f34000 rw-p 00040000 fc:00 2337 /system/lib64/libm.so
-70e8f34000-70e8f36000 r--s 00000000 fc:00 133 /system/fonts/NotoSansRejang-Regular.ttf
-70e8f36000-70e8f38000 r--s 00000000 fc:00 69 /system/fonts/NotoSansPhoenician-Regular.ttf
-70e8f38000-70e8f40000 r--s 00000000 fc:00 245 /system/fonts/NotoSansLaoUI-Regular.ttf
-70e8f40000-70e8f45000 r-xp 00000000 fc:00 2341 /system/lib64/libstagefright_codecbase.so
-70e8f45000-70e8f5f000 ---p 00000000 00:00 0
-70e8f5f000-70e8f60000 r--p 0000f000 fc:00 2341 /system/lib64/libstagefright_codecbase.so
-70e8f60000-70e8f61000 rw-p 00010000 fc:00 2341 /system/lib64/libstagefright_codecbase.so
-70e8f61000-70e8f62000 r--p 00000000 00:00 0 [anon:atexit handlers]
-70e8f62000-70e8f66000 r--s 00000000 fc:00 225 /system/fonts/NotoSansOldPersian-Regular.ttf
-70e8f66000-70e8f89000 r--s 00000000 fc:00 167 /system/fonts/NotoSansEthiopic-Regular.ttf
-70e8f89000-70e8f92000 r-xp 00000000 fc:00 2515 /system/lib64/libGLESv1_CM.so
-70e8f92000-70e8fa8000 ---p 00000000 00:00 0
-70e8fa8000-70e8fa9000 r--p 0000f000 fc:00 2515 /system/lib64/libGLESv1_CM.so
-70e8fa9000-70e8faa000 rw-p 00010000 fc:00 2515 /system/lib64/libGLESv1_CM.so
-70e8faa000-70e8fad000 r--s 00000000 fc:00 206 /system/fonts/NotoSansOsage-Regular.ttf
-70e8fad000-70e8fb5000 r--s 00000000 fc:00 121 /system/fonts/NotoSerifLao-Bold.ttf
-70e8fb5000-70e8fd3000 r--s 00000000 fc:00 68 /system/fonts/NotoNaskhArabicUI-Bold.ttf
-70e8fd3000-70e9010000 r-xp 00000000 fc:00 2600 /system/lib64/android.hardware.cas@1.0.so
-70e9010000-70e9026000 ---p 00000000 00:00 0
-70e9026000-70e902c000 r--p 0004a000 fc:00 2600 /system/lib64/android.hardware.cas@1.0.so
-70e902c000-70e902d000 rw-p 00050000 fc:00 2600 /system/lib64/android.hardware.cas@1.0.so
-70e902d000-70e902e000 r--s 00000000 00:05 31475 /dev/ashmem/5c7d41a6-003d-45a5-9e3b-2d34c5829a2d (deleted)
-70e902e000-70e9043000 r--s 00000000 fc:00 120 /system/fonts/NotoSansKannada-Regular.ttf
-70e9043000-70e9067000 r-xp 00000000 fc:00 2729 /system/lib64/libexpat.so
-70e9067000-70e9081000 ---p 00000000 00:00 0
-70e9081000-70e9083000 r--p 0002e000 fc:00 2729 /system/lib64/libexpat.so
-70e9083000-70e9084000 rw-p 00030000 fc:00 2729 /system/lib64/libexpat.so
-70e9084000-70e9086000 r--s 00000000 fc:00 155 /system/fonts/NotoSansOsmanya-Regular.ttf
-70e9086000-70e90c3000 r--s 00000000 fc:00 91 /system/fonts/NotoSerif-Regular.ttf
-70e90c3000-70e91ce000 r-xp 00000000 fc:00 2647 /system/lib64/libcrypto.so
-70e91ce000-70e91e2000 ---p 00000000 00:00 0
-70e91e2000-70e91f3000 r--p 0010f000 fc:00 2647 /system/lib64/libcrypto.so
-70e91f3000-70e91f4000 rw-p 00120000 fc:00 2647 /system/lib64/libcrypto.so
-70e91f4000-70e91f5000 rw-p 00000000 00:00 0 [anon:.bss]
-70e91f5000-70e91fa000 r--s 00000000 fc:00 149 /system/fonts/NotoSansNKo-Regular.ttf
-70e91fa000-70e9202000 r--s 00000000 fc:00 198 /system/fonts/NotoSerifLao-Regular.ttf
-70e9202000-70e921b000 r-xp 00000000 fc:00 2682 /system/lib64/libmedia_helper.so
-70e921b000-70e922d000 ---p 00000000 00:00 0
-70e922d000-70e9230000 r--p 0001d000 fc:00 2682 /system/lib64/libmedia_helper.so
-70e9230000-70e9231000 rw-p 00020000 fc:00 2682 /system/lib64/libmedia_helper.so
-70e9231000-70e924a000 r--s 00000000 fc:00 232 /system/fonts/NotoSansBengali-Bold.ttf
-70e924a000-70e9256000 r-xp 00000000 fc:00 2467 /system/lib64/libsoundtrigger.so
-70e9256000-70e9272000 ---p 00000000 00:00 0
-70e9272000-70e9276000 r--p 0000c000 fc:00 2467 /system/lib64/libsoundtrigger.so
-70e9276000-70e9277000 rw-p 00010000 fc:00 2467 /system/lib64/libsoundtrigger.so
-70e9277000-70e9278000 r--s 00000000 fc:01 1177 /vendor/overlay/Pixel/PixelThemeOverlay.apk
-70e9278000-70e927c000 r--s 00000000 fc:00 215 /system/fonts/NotoSansNewTaiLue-Regular.ttf
-70e927c000-70e929a000 r--s 00000000 fc:00 235 /system/fonts/NotoNaskhArabicUI-Regular.ttf
-70e929a000-70e929b000 r-xp 00000000 fc:00 2375 /system/lib64/android.hardware.graphics.common@1.1.so
-70e929b000-70e92b9000 ---p 00000000 00:00 0
-70e92b9000-70e92ba000 r--p 0000f000 fc:00 2375 /system/lib64/android.hardware.graphics.common@1.1.so
-70e92ba000-70e92bb000 rw-p 00010000 fc:00 2375 /system/lib64/android.hardware.graphics.common@1.1.so
-70e92bb000-70e92da000 r--s 00000000 fc:00 281 /system/fonts/GoogleSans-BoldItalic.ttf
-70e92da000-70e9302000 r-xp 00000000 fc:00 2529 /system/lib64/libinput.so
-70e9302000-70e931b000 ---p 00000000 00:00 0
-70e931b000-70e9322000 r--p 00029000 fc:00 2529 /system/lib64/libinput.so
-70e9322000-70e9323000 rw-p 00030000 fc:00 2529 /system/lib64/libinput.so
-70e9323000-70e9340000 r--s 00000000 fc:00 130 /system/fonts/NotoNaskhArabic-Bold.ttf
-70e9340000-70e934b000 r-xp 00000000 fc:00 2451 /system/lib64/libbpf.so
-70e934b000-70e935f000 ---p 00000000 00:00 0
-70e935f000-70e9360000 r--p 0000f000 fc:00 2451 /system/lib64/libbpf.so
-70e9360000-70e9361000 rw-p 00010000 fc:00 2451 /system/lib64/libbpf.so
-70e9361000-70e9367000 r--s 00000000 fc:00 96 /system/fonts/NotoSansKharoshthi-Regular.ttf
-70e9367000-70e9385000 r--s 00000000 fc:00 151 /system/fonts/GoogleSans-Bold.ttf
-70e9385000-70e93b8000 r-xp 00000000 fc:00 2494 /system/lib64/libpng.so
-70e93b8000-70e93d4000 ---p 00000000 00:00 0
-70e93d4000-70e93d5000 r--p 0003f000 fc:00 2494 /system/lib64/libpng.so
-70e93d5000-70e93d6000 rw-p 00040000 fc:00 2494 /system/lib64/libpng.so
-70e93d6000-70e93d7000 r--s 00004000 fc:01 1177 /vendor/overlay/Pixel/PixelThemeOverlay.apk
-70e93d7000-70e93d9000 r--s 00000000 fc:00 295 /system/fonts/NotoSansOldTurkic-Regular.ttf
-70e93d9000-70e93e5000 r--s 00000000 fc:00 86 /system/fonts/NotoSerifKhmer-Bold.otf
-70e93e5000-70e9404000 r--s 00000000 fc:00 240 /system/fonts/GoogleSans-MediumItalic.ttf
-70e9404000-70e9409000 r-xp 00000000 fc:00 2404 /system/lib64/libhidlmemory.so
-70e9409000-70e9423000 ---p 00000000 00:00 0
-70e9423000-70e9424000 r--p 0000f000 fc:00 2404 /system/lib64/libhidlmemory.so
-70e9424000-70e9425000 rw-p 00010000 fc:00 2404 /system/lib64/libhidlmemory.so
-70e9425000-70e943e000 r--s 00000000 fc:00 185 /system/fonts/NotoSansBengali-Regular.ttf
-70e943e000-70e945c000 r--s 00000000 fc:00 129 /system/fonts/GoogleSans-Medium.ttf
-70e945c000-70e960c000 r-xp 00000000 fc:00 2398 /system/lib64/libstagefright.so
-70e960c000-70e9625000 ---p 00000000 00:00 0
-70e9625000-70e9638000 r--p 001bd000 fc:00 2398 /system/lib64/libstagefright.so
-70e9638000-70e966c000 rw-p 001d0000 fc:00 2398 /system/lib64/libstagefright.so
-70e966c000-70e966d000 rw-p 00000000 00:00 0 [anon:.bss]
-70e966d000-70e966e000 r--s 00000000 103:1d 1474566 /data/resource-cache/vendor@overlay@Pixel@PixelThemeOverlay.apk@idmap
-70e966e000-70e9672000 r--s 00000000 fc:00 241 /system/fonts/NotoSansMeeteiMayek-Regular.ttf
-70e9672000-70e9680000 r--s 00000000 fc:00 150 /system/fonts/NotoSansMalayalamUI-Bold.ttf
-70e9680000-70e96a7000 r-xp 00000000 fc:00 2365 /system/lib64/libhwbinder.so
-70e96a7000-70e96bd000 ---p 00000000 00:00 0
-70e96bd000-70e96bf000 r--p 0002e000 fc:00 2365 /system/lib64/libhwbinder.so
-70e96bf000-70e96c0000 rw-p 00030000 fc:00 2365 /system/lib64/libhwbinder.so
-70e96c0000-70e96c1000 r--s 00088000 103:1d 1736830 /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk
-70e96c1000-70e96cb000 r--s 00000000 fc:00 94 /system/fonts/NotoSansKhmerUI-Regular.ttf
-70e96cb000-70e96d9000 r--s 00000000 fc:00 275 /system/fonts/NotoSansMalayalamUI-Regular.ttf
-70e96d9000-70e96dd000 r-xp 00000000 fc:00 2386 /system/lib64/libusbhost.so
-70e96dd000-70e96f8000 ---p 00000000 00:00 0
-70e96f8000-70e96f9000 r--p 0000f000 fc:00 2386 /system/lib64/libusbhost.so
-70e96f9000-70e96fa000 rw-p 00010000 fc:00 2386 /system/lib64/libusbhost.so
-70e96fa000-70e96fb000 r--p 00000000 00:05 10266154 [anon:dalvik-classes.dex extracted in memory from /data/app/com.google.sample.tunnel-HGGRU03Gu1Mwkf_-RnFmvw==/base.apk]
-70e96fb000-70e9701000 r--s 00000000 fc:00 280 /system/fonts/NotoSansCoptic-Regular.ttf
-70e9701000-70e9720000 r-xp 00000000 fc:00 2490 /system/lib64/libstagefright_bufferqueue_helper.so
-70e9720000-70e973b000 ---p 00000000 00:00 0
-70e973b000-70e973e000 r--p 0002d000 fc:00 2490 /system/lib64/libstagefright_bufferqueue_helper.so
-70e973e000-70e9740000 rw-p 00030000 fc:00 2490 /system/lib64/libstagefright_bufferqueue_helper.so
-70e9740000-70e9742000 r--s 00000000 fc:00 141 /system/fonts/NotoSansOldSouthArabian-Regular.ttf
-70e9742000-70e974c000 r--s 00000000 fc:00 229 /system/fonts/NotoSerifKhmer-Regular.otf
-70e974c000-70e9759000 r--s 00000000 fc:00 260 /system/fonts/NotoSerifMalayalam-Bold.ttf
-70e9759000-70e97c7000 r-xp 00000000 fc:00 2428 /system/lib64/libstagefright_omx.so
-70e97c7000-70e97dc000 ---p 00000000 00:00 0
-70e97dc000-70e97e6000 r--p 00076000 fc:00 2428 /system/lib64/libstagefright_omx.so
-70e97e6000-70e97ed000 rw-p 00080000 fc:00 2428 /system/lib64/libstagefright_omx.so
-70e97ed000-70e97fa000 r--s 00000000 fc:00 66 /system/fonts/NotoSerifMalayalam-Regular.ttf
-70e97fa000-70e9819000 r--s 00000000 fc:00 183 /system/fonts/GoogleSans-Italic.ttf
-70e9819000-70e9856000 r-xp 00000000 fc:00 2434 /system/lib64/libprotobuf-cpp-lite.so
-70e9856000-70e9867000 ---p 00000000 00:00 0
-70e9867000-70e9869000 r--p 0003e000 fc:00 2434 /system/lib64/libprotobuf-cpp-lite.so
-70e9869000-70e986a000 rw-p 00040000 fc:00 2434 /system/lib64/libprotobuf-cpp-lite.so
-70e986a000-70e9873000 r--s 00000000 fc:00 134 /system/fonts/NotoSansKhmerUI-Bold.ttf
-70e9873000-70e9891000 r--s 00000000 fc:00 81 /system/fonts/GoogleSans-Regular.ttf
-70e9891000-70e989e000 r-xp 00000000 fc:00 2377 /system/lib64/libmediametrics.so
-70e989e000-70e98ae000 ---p 00000000 00:00 0
-70e98ae000-70e98b0000 r--p 0000e000 fc:00 2377 /system/lib64/libmediametrics.so
-70e98b0000-70e98b1000 rw-p 00010000 fc:00 2377 /system/lib64/libmediametrics.so
-70e98b1000-70e98b9000 r--s 00000000 fc:00 152 /system/fonts/NotoSansLao-Bold.ttf
-70e98b9000-70e98c7000 r--s 00000000 fc:00 279 /system/fonts/NotoSansMalayalam-Bold.ttf
-70e98c7000-70e98ca000 r-xp 00000000 fc:00 2952 /system/lib64/libETC1.so
-70e98ca000-70e98e6000 ---p 00000000 00:00 0
-70e98e6000-70e98e7000 r--p 0000f000 fc:00 2952 /system/lib64/libETC1.so
-70e98e7000-70e98e8000 rw-p 00010000 fc:00 2952 /system/lib64/libETC1.so
-70e98e8000-70e98e9000 r--s 00000000 fc:00 1121 /system/usr/hyphen-data/hyph-und-ethi.hyb
-70e98e9000-70e98ef000 r--s 00000000 fc:00 64 /system/fonts/NotoSansBrahmi-Regular.ttf
-70e98ef000-70e990f000 rw-p 00000000 00:05 10271012 [anon:dalvik-CompilerMetadata]
-70e990f000-70e9926000 r-xp 00000000 fc:00 2526 /system/lib64/libbacktrace.so
-70e9926000-70e993e000 ---p 00000000 00:00 0
-70e993e000-70e993f000 r--p 0001f000 fc:00 2526 /system/lib64/libbacktrace.so
-70e993f000-70e9940000 rw-p 00020000 fc:00 2526 /system/lib64/libbacktrace.so
-70e9940000-70e9941000 r--s 00000000 fc:00 1129 /system/usr/hyphen-data/hyph-tk.hyb
-70e9941000-70e99a4000 r-xp 00000000 fc:00 2528 /system/lib64/libcamera_client.so
-70e99a4000-70e99bc000 ---p 00000000 00:00 0
-70e99bc000-70e99c9000 r--p 00063000 fc:00 2528 /system/lib64/libcamera_client.so
-70e99c9000-70e99d0000 rw-p 00070000 fc:00 2528 /system/lib64/libcamera_client.so
-70e99d0000-70e99d1000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70e99d1000-70e99d3000 r--s 00000000 fc:00 200 /system/fonts/NotoSansOldItalic-Regular.ttf
-70e99d3000-70e99e1000 r--s 00000000 fc:00 153 /system/fonts/NotoSansMalayalam-Regular.ttf
-70e99e1000-70e9a01000 rw-p 00000000 00:05 10271011 [anon:dalvik-CompilerMetadata]
-70e9a01000-70e9a1e000 r-xp 00000000 fc:00 2542 /system/lib64/libimg_utils.so
-70e9a1e000-70e9a39000 ---p 00000000 00:00 0
-70e9a39000-70e9a3c000 r--p 0001d000 fc:00 2542 /system/lib64/libimg_utils.so
-70e9a3c000-70e9a3f000 rw-p 00020000 fc:00 2542 /system/lib64/libimg_utils.so
-70e9a3f000-70e9a5c000 r--s 00000000 fc:00 262 /system/fonts/NotoNaskhArabic-Regular.ttf
-70e9a5c000-70e9a69000 r-xp 00000000 fc:00 2706 /system/lib64/libziparchive.so
-70e9a69000-70e9a7b000 ---p 00000000 00:00 0
-70e9a7b000-70e9a7c000 r--p 0000f000 fc:00 2706 /system/lib64/libziparchive.so
-70e9a7c000-70e9a7d000 rw-p 00010000 fc:00 2706 /system/lib64/libziparchive.so
-70e9a7d000-70e9a85000 r--s 00000000 fc:00 119 /system/fonts/NotoSansLao-Regular.ttf
-70e9a85000-70e9a8e000 r--s 00000000 fc:00 77 /system/fonts/NotoSansTamilUI-Bold.ttf
-70e9a8e000-70e9a97000 r--s 00000000 fc:00 160 /system/fonts/NotoSansTamilUI-Regular.ttf
-70e9a97000-70e9a9d000 r-xp 00000000 fc:00 2536 /system/lib64/libnativehelper.so
-70e9a9d000-70e9ab6000 ---p 00000000 00:00 0
-70e9ab6000-70e9ab7000 r--p 0000f000 fc:00 2536 /system/lib64/libnativehelper.so
-70e9ab7000-70e9ab8000 rw-p 00010000 fc:00 2536 /system/lib64/libnativehelper.so
-70e9ab8000-70e9ab9000 r--s 00000000 fc:00 1134 /system/usr/hyphen-data/hyph-te.hyb
-70e9ab9000-70e9ac2000 r--s 00000000 fc:00 246 /system/fonts/NotoSerifTamil-Bold.ttf
-70e9ac2000-70e9acb000 r--s 00000000 fc:00 302 /system/fonts/NotoSerifTamil-Regular.ttf
-70e9acb000-70e9af4000 r-xp 00000000 fc:00 2950 /system/lib64/libmemunreachable.so
-70e9af4000-70e9b09000 ---p 00000000 00:00 0
-70e9b09000-70e9b0b000 r--p 0002e000 fc:00 2950 /system/lib64/libmemunreachable.so
-70e9b0b000-70e9b0c000 rw-p 00030000 fc:00 2950 /system/lib64/libmemunreachable.so
-70e9b0c000-70e9b0d000 r--s 00000000 fc:00 1088 /system/usr/hyphen-data/hyph-ta.hyb
-70e9b0d000-70e9b0f000 r--s 00000000 fc:00 72 /system/fonts/NotoSansOlChiki-Regular.ttf
-70e9b0f000-70e9b2f000 rw-p 00000000 00:05 10271010 [anon:dalvik-CompilerMetadata]
-70e9b2f000-70e9b4f000 r--s 00000000 00:10 16633 /dev/__properties__/u:object_r:persist_debug_prop:s0
-70e9b4f000-70e9b65000 r-xp 00000000 fc:00 2920 /system/lib64/android.hardware.cas.native@1.0.so
-70e9b65000-70e9b7b000 ---p 00000000 00:00 0
-70e9b7b000-70e9b7d000 r--p 0001e000 fc:00 2920 /system/lib64/android.hardware.cas.native@1.0.so
-70e9b7d000-70e9b7e000 rw-p 00020000 fc:00 2920 /system/lib64/android.hardware.cas.native@1.0.so
-70e9b7e000-70e9b7f000 r--s 00000000 fc:00 1145 /system/usr/hyphen-data/hyph-pt.hyb
-70e9b7f000-70e9b83000 r--s 00000000 fc:00 277 /system/fonts/NotoSansMandaic-Regular.ttf
-70e9b83000-70e9bdb000 r-xp 00000000 fc:00 2334 /system/lib64/libsonivox.so
-70e9bdb000-70e9bf2000 ---p 00000000 00:00 0
-70e9bf2000-70e9bf3000 r--p 0005f000 fc:00 2334 /system/lib64/libsonivox.so
-70e9bf3000-70e9bf4000 rw-p 00060000 fc:00 2334 /system/lib64/libsonivox.so
-70e9bf4000-70e9bfb000 rw-p 00000000 00:00 0 [anon:.bss]
-70e9bfb000-70e9c01000 r--s 00000000 fc:00 123 /system/fonts/NotoSansCham-Bold.ttf
-70e9c01000-70e9c0a000 r--s 00000000 fc:00 255 /system/fonts/NotoSansTamil-Bold.ttf
-70e9c0a000-70e9c13000 r--s 00000000 fc:00 135 /system/fonts/NotoSansTamil-Regular.ttf
-70e9c13000-70e9c15000 r-xp 00000000 fc:00 2519 /system/lib64/libgraphicsenv.so
-70e9c15000-70e9c32000 ---p 00000000 00:00 0
-70e9c32000-70e9c33000 r--p 0000f000 fc:00 2519 /system/lib64/libgraphicsenv.so
-70e9c33000-70e9c34000 rw-p 00010000 fc:00 2519 /system/lib64/libgraphicsenv.so
-70e9c34000-70e9c3a000 r--s 00000000 fc:00 259 /system/fonts/NotoSansCham-Regular.ttf
-70e9c3a000-70e9c42000 r--s 00000000 fc:00 114 /system/fonts/NotoSansGurmukhiUI-Bold.ttf
-70e9c42000-70e9c4a000 r--s 00000000 fc:00 122 /system/fonts/NotoSansGurmukhiUI-Regular.ttf
-70e9c4a000-70e9c5f000 r-xp 00000000 fc:00 2348 /system/lib64/android.hidl.allocator@1.0.so
-70e9c5f000-70e9c77000 ---p 00000000 00:00 0
-70e9c77000-70e9c79000 r--p 0001e000 fc:00 2348 /system/lib64/android.hidl.allocator@1.0.so
-70e9c79000-70e9c7a000 rw-p 00020000 fc:00 2348 /system/lib64/android.hidl.allocator@1.0.so
-70e9c7a000-70e9c7b000 r--s 00000000 fc:00 1095 /system/usr/hyphen-data/hyph-pa.hyb
-70e9c7b000-70e9c83000 r--s 00000000 fc:00 298 /system/fonts/NotoSerifGurmukhi-Bold.otf
-70e9c83000-70e9d01000 r-xp 00000000 fc:00 2665 /system/lib64/libbinder.so
-70e9d01000-70e9d1e000 ---p 00000000 00:00 0
-70e9d1e000-70e9d2e000 r--p 00080000 fc:00 2665 /system/lib64/libbinder.so
-70e9d2e000-70e9d2f000 rw-p 00090000 fc:00 2665 /system/lib64/libbinder.so
-70e9d2f000-70e9d4f000 rw-p 00000000 00:05 10271009 [anon:dalvik-CompilerMetadata]
-70e9d4f000-70e9d53000 r-xp 00000000 fc:00 2454 /system/lib64/libaudiomanager.so
-70e9d53000-70e9d6e000 ---p 00000000 00:00 0
-70e9d6e000-70e9d6f000 r--p 0000f000 fc:00 2454 /system/lib64/libaudiomanager.so
-70e9d6f000-70e9d70000 rw-p 00010000 fc:00 2454 /system/lib64/libaudiomanager.so
-70e9d70000-70e9d71000 r--s 00000000 fc:00 1087 /system/usr/hyphen-data/hyph-or.hyb
-70e9d71000-70e9d91000 rw-p 00000000 00:05 10271008 [anon:dalvik-CompilerMetadata]
-70e9d91000-70e9e21000 r-xp 00000000 fc:00 2627 /system/lib64/libft2.so
-70e9e21000-70e9e37000 ---p 00000000 00:00 0
-70e9e37000-70e9e3c000 r--p 0009b000 fc:00 2627 /system/lib64/libft2.so
-70e9e3c000-70e9e3d000 rw-p 000a0000 fc:00 2627 /system/lib64/libft2.so
-70e9e3d000-70e9e3e000 r--s 00000000 fc:00 1142 /system/usr/hyphen-data/hyph-mr.hyb
-70e9e3e000-70e9e45000 r--s 00000000 fc:00 88 /system/fonts/NotoSerifGurmukhi-Regular.otf
-70e9e45000-70e9e65000 r--s 00000000 00:10 16594 /dev/__properties__/u:object_r:exported3_default_prop:s0
-70e9e65000-70e9e7f000 r-xp 00000000 fc:00 2643 /system/lib64/libunwind.so
-70e9e7f000-70e9e94000 ---p 00000000 00:00 0
-70e9e94000-70e9e95000 r--p 0001f000 fc:00 2643 /system/lib64/libunwind.so
-70e9e95000-70e9e96000 rw-p 00020000 fc:00 2643 /system/lib64/libunwind.so
-70e9e96000-70e9eff000 rw-p 00000000 00:00 0 [anon:.bss]
-70e9eff000-70e9f00000 r--s 00000000 fc:00 1130 /system/usr/hyphen-data/hyph-ml.hyb
-70e9f00000-70e9f02000 r--s 00000000 fc:00 75 /system/fonts/NotoSansOgham-Regular.ttf
-70e9f02000-70e9f0a000 r--s 00000000 fc:00 193 /system/fonts/NotoSansGurmukhi-Bold.ttf
-70e9f0a000-70ea022000 r-xp 00000000 fc:00 2328 /system/lib64/libsqlite.so
-70ea022000-70ea033000 ---p 00000000 00:00 0
-70ea033000-70ea036000 r--p 0011d000 fc:00 2328 /system/lib64/libsqlite.so
-70ea036000-70ea038000 rw-p 00120000 fc:00 2328 /system/lib64/libsqlite.so
-70ea038000-70ea03c000 r--s 00000000 fc:00 285 /system/fonts/NotoSansGlagolitic-Regular.ttf
-70ea03c000-70ea04c000 r--s 00000000 fc:00 184 /system/fonts/NotoSerifGujarati-Bold.ttf
-70ea04c000-70ea060000 r-xp 00000000 fc:00 2731 /system/lib64/libstatslog.so
-70ea060000-70ea07b000 ---p 00000000 00:00 0
-70ea07b000-70ea07c000 r--p 0001f000 fc:00 2731 /system/lib64/libstatslog.so
-70ea07c000-70ea07d000 rw-p 00020000 fc:00 2731 /system/lib64/libstatslog.so
-70ea07d000-70ea081000 r--s 00000000 fc:00 182 /system/fonts/NotoSansBatak-Regular.ttf
-70ea081000-70ea091000 r--s 00000000 fc:00 264 /system/fonts/NotoSerifGujarati-Regular.ttf
-70ea091000-70ea160000 r-xp 00000000 fc:00 2728 /system/lib64/libdng_sdk.so
-70ea160000-70ea173000 ---p 00000000 00:00 0
-70ea173000-70ea17a000 r--p 000d9000 fc:00 2728 /system/lib64/libdng_sdk.so
-70ea17a000-70ea17b000 rw-p 000e0000 fc:00 2728 /system/lib64/libdng_sdk.so
-70ea17b000-70ea198000 r--s 00000000 fc:00 223 /system/fonts/DancingScript-Bold.ttf
-70ea198000-70ea19c000 r-xp 00000000 fc:00 2344 /system/lib64/libnativewindow.so
-70ea19c000-70ea1b7000 ---p 00000000 00:00 0
-70ea1b7000-70ea1b8000 r--p 0000f000 fc:00 2344 /system/lib64/libnativewindow.so
-70ea1b8000-70ea1b9000 rw-p 00010000 fc:00 2344 /system/lib64/libnativewindow.so
-70ea1b9000-70ea1bd000 r--s 00000000 fc:00 98 /system/fonts/NotoSansAhom-Regular.otf
-70ea1bd000-70ea1d1000 r--s 00000000 fc:00 104 /system/fonts/NotoSerifDevanagari-Bold.ttf
-70ea1d1000-70ea1d4000 r-xp 00000000 fc:00 2923 /system/lib64/libstdc++.so
-70ea1d4000-70ea1f0000 ---p 00000000 00:00 0
-70ea1f0000-70ea1f1000 r--p 0000f000 fc:00 2923 /system/lib64/libstdc++.so
-70ea1f1000-70ea1f2000 rw-p 00010000 fc:00 2923 /system/lib64/libstdc++.so
-70ea1f2000-70ea1f4000 r--s 00000000 fc:00 117 /system/fonts/NotoSansLydian-Regular.ttf
-70ea1f4000-70ea211000 r--s 00000000 fc:00 239 /system/fonts/DancingScript-Regular.ttf
-70ea211000-70ea24a000 r-xp 00000000 fc:00 2933 /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
-70ea24a000-70ea268000 ---p 00000000 00:00 0
-70ea268000-70ea26c000 r--p 0003c000 fc:00 2933 /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
-70ea26c000-70ea26d000 rw-p 00040000 fc:00 2933 /system/lib64/android.hardware.graphics.bufferqueue@1.0.so
-70ea26d000-70ea26f000 r--s 00000000 fc:00 244 /system/fonts/NotoSansLycian-Regular.ttf
-70ea26f000-70ea273000 r--s 00000000 fc:00 173 /system/fonts/NotoSansThaana-Bold.ttf
-70ea273000-70ea287000 r--s 00000000 fc:00 106 /system/fonts/NotoSerifDevanagari-Regular.ttf
-70ea287000-70ea29e000 r-xp 00000000 fc:00 2938 /system/lib64/libpiex.so
-70ea29e000-70ea2b6000 ---p 00000000 00:00 0
-70ea2b6000-70ea2b7000 r--p 0001f000 fc:00 2938 /system/lib64/libpiex.so
-70ea2b7000-70ea2b8000 rw-p 00020000 fc:00 2938 /system/lib64/libpiex.so
-70ea2b8000-70ea2c0000 r--s 00000000 fc:00 113 /system/fonts/NotoSansGurmukhi-Regular.ttf
-70ea2c0000-70ea2c6000 r--s 00000000 fc:00 263 /system/fonts/NotoSerifGeorgian-Bold.ttf
-70ea2c6000-70ea2cc000 r--s 00000000 fc:00 249 /system/fonts/NotoSerifGeorgian-Regular.ttf
-70ea2cc000-70ea9b4000 r-xp 00000000 fc:00 2532 /system/lib64/libhwui.so
-70ea9b4000-70ea9d3000 ---p 00000000 00:00 0
-70ea9d3000-70eaa0b000 r--p 006e8000 fc:00 2532 /system/lib64/libhwui.so
-70eaa0b000-70eaa0c000 rw-p 00720000 fc:00 2532 /system/lib64/libhwui.so
-70eaa0c000-70eaa11000 rw-p 00000000 00:00 0 [anon:.bss]
-70eaa11000-70eaa12000 r--s 00000000 fc:00 1110 /system/usr/hyphen-data/hyph-la.hyb
-70eaa12000-70eaa16000 r--s 00000000 fc:00 87 /system/fonts/NotoSansThaana-Regular.ttf
-70eaa16000-70eaa1b000 r--s 00000000 fc:00 218 /system/fonts/NotoSansGeorgian-Bold.ttf
-70eaa1b000-70eaa20000 r--s 00000000 fc:00 125 /system/fonts/NotoSansGeorgian-Regular.ttf
-70eaa20000-70eaa40000 rw-p 00000000 00:05 10271007 [anon:dalvik-CompilerMetadata]
-70eaa40000-70eaaa0000 r-xp 00000000 fc:00 2384 /system/lib64/libhidltransport.so
-70eaaa0000-70eaabe000 ---p 00000000 00:00 0
-70eaabe000-70eaac6000 r--p 00068000 fc:00 2384 /system/lib64/libhidltransport.so
-70eaac6000-70eaac7000 rw-p 00070000 fc:00 2384 /system/lib64/libhidltransport.so
-70eaac7000-70eaacb000 r--s 00000000 fc:00 192 /system/fonts/NotoSerifArmenian-Bold.ttf
-70eaacb000-70eaad0000 r--s 00000000 fc:00 210 /system/fonts/NotoSansThaiUI-Bold.ttf
-70eaad0000-70eaaf0000 rw-p 00000000 00:05 10271006 [anon:dalvik-CompilerMetadata]
-70eaaf0000-70eab10000 rw-p 00000000 00:05 10271005 [anon:dalvik-CompilerMetadata]
-70eab10000-70eab57000 r-xp 00000000 fc:00 2546 /system/lib64/libmedia_omx.so
-70eab57000-70eab6d000 ---p 00000000 00:00 0
-70eab6d000-70eab7a000 r--p 00053000 fc:00 2546 /system/lib64/libmedia_omx.so
-70eab7a000-70eab7f000 rw-p 00060000 fc:00 2546 /system/lib64/libmedia_omx.so
-70eab7f000-70eab80000 r--s 00000000 fc:00 1119 /system/usr/hyphen-data/hyph-kn.hyb
-70eab80000-70eab86000 r--s 00000000 fc:00 224 /system/fonts/NotoSansThaiUI-Regular.ttf
-70eab86000-70eab8b000 r--s 00000000 fc:00 300 /system/fonts/NotoSerifThai-Bold.ttf
-70eab8b000-70eabab000 rw-p 00000000 00:05 10271004 [anon:dalvik-CompilerMetadata]
-70eabab000-70eac21000 r-xp 00000000 fc:00 2385 /system/lib64/libvintf.so
-70eac21000-70eac31000 ---p 00000000 00:00 0
-70eac31000-70eac36000 r--p 0007b000 fc:00 2385 /system/lib64/libvintf.so
-70eac36000-70eac37000 rw-p 00080000 fc:00 2385 /system/lib64/libvintf.so
-70eac37000-70eac39000 rw-p 00000000 00:00 0 [anon:.bss]
-70eac39000-70eac3a000 r--s 00000000 fc:00 1104 /system/usr/hyphen-data/hyph-hy.hyb
-70eac3a000-70eac3f000 r--s 00000000 fc:00 212 /system/fonts/NotoSerifThai-Regular.ttf
-70eac3f000-70eac44000 r--s 00000000 fc:00 220 /system/fonts/NotoSansThai-Bold.ttf
-70eac44000-70eacb2000 r-xp 00000000 fc:00 2606 /system/lib64/android.hardware.media.omx@1.0.so
-70eacb2000-70eaccf000 ---p 00000000 00:00 0
-70eaccf000-70eacd8000 r--p 00077000 fc:00 2606 /system/lib64/android.hardware.media.omx@1.0.so
-70eacd8000-70eacd9000 rw-p 00080000 fc:00 2606 /system/lib64/android.hardware.media.omx@1.0.so
-70eacd9000-70eacdf000 r--s 00000000 fc:00 169 /system/fonts/NotoSansThai-Regular.ttf
-70eacdf000-70eace9000 r--s 00000000 fc:00 140 /system/fonts/CarroisGothicSC-Regular.ttf
-70eace9000-70ead09000 rw-p 00000000 00:05 10271003 [anon:dalvik-CompilerMetadata]
-70ead09000-70ead22000 r-xp 00000000 fc:00 2539 /system/lib64/android.hardware.graphics.mapper@2.1.so
-70ead22000-70ead34000 ---p 00000000 00:00 0
-70ead34000-70ead37000 r--p 0001d000 fc:00 2539 /system/lib64/android.hardware.graphics.mapper@2.1.so
-70ead37000-70ead38000 rw-p 00020000 fc:00 2539 /system/lib64/android.hardware.graphics.mapper@2.1.so
-70ead38000-70ead47000 r--s 00000000 fc:00 188 /system/fonts/ComingSoon.ttf
-70ead47000-70ead5d000 r-xp 00000000 fc:00 2379 /system/lib64/libselinux.so
-70ead5d000-70ead76000 ---p 00000000 00:00 0
-70ead76000-70ead77000 r--p 0001f000 fc:00 2379 /system/lib64/libselinux.so
-70ead77000-70ead78000 rw-p 00020000 fc:00 2379 /system/lib64/libselinux.so
-70ead78000-70ead79000 rw-p 00000000 00:00 0 [anon:.bss]
-70ead79000-70ead7d000 r--s 00000000 fc:00 282 /system/fonts/NotoSerifArmenian-Regular.ttf
-70ead7d000-70ead82000 r--s 00000000 fc:00 288 /system/fonts/NotoSerifHebrew-Bold.ttf
-70ead82000-70ead83000 r-xp 00000000 fc:00 2680 /system/lib64/android.hardware.media@1.0.so
-70ead83000-70eada1000 ---p 00000000 00:00 0
-70eada1000-70eada2000 r--p 0000f000 fc:00 2680 /system/lib64/android.hardware.media@1.0.so
-70eada2000-70eada3000 rw-p 00010000 fc:00 2680 /system/lib64/android.hardware.media@1.0.so
-70eada3000-70eada8000 r--s 00000000 fc:00 248 /system/fonts/NotoSerifHebrew-Regular.ttf
-70eada8000-70eadb9000 r--s 00000000 fc:00 252 /system/fonts/CutiveMono.ttf
-70eadb9000-70eadd9000 r--s 00000000 00:10 16641 /dev/__properties__/u:object_r:radio_prop:s0
-70eadd9000-70eadda000 r-xp 00000000 fc:00 2533 /system/lib64/android.hardware.graphics.common@1.0.so
-70eadda000-70eadf8000 ---p 00000000 00:00 0
-70eadf8000-70eadf9000 r--p 0000f000 fc:00 2533 /system/lib64/android.hardware.graphics.common@1.0.so
-70eadf9000-70eadfa000 rw-p 00010000 fc:00 2533 /system/lib64/android.hardware.graphics.common@1.0.so
-70eadfa000-70eadfb000 r--s 00000000 fc:00 1126 /system/usr/hyphen-data/hyph-hr.hyb
-70eadfb000-70eadfd000 r--s 00000000 fc:00 194 /system/fonts/NotoSansLisu-Regular.ttf
-70eadfd000-70eae18000 r--s 00000000 fc:00 201 /system/fonts/DroidSansMono.ttf
-70eae18000-70eae3b000 r-xp 00000000 fc:00 2925 /system/lib64/liblzma.so
-70eae3b000-70eae57000 ---p 00000000 00:00 0
-70eae57000-70eae58000 r--p 0002f000 fc:00 2925 /system/lib64/liblzma.so
-70eae58000-70eae59000 rw-p 00030000 fc:00 2925 /system/lib64/liblzma.so
-70eae59000-70eae5f000 rw-p 00000000 00:00 0 [anon:.bss]
-70eae5f000-70eae62000 r--s 00000000 fc:00 103 /system/fonts/NotoSansLimbu-Regular.ttf
-70eae62000-70eae67000 r--s 00000000 fc:00 236 /system/fonts/NotoSansHebrew-Bold.ttf
-70eae67000-70eae84000 r--s 001c2000 fc:00 990 /system/framework/ext.jar
-70eae84000-70eaea4000 rw-p 00000000 00:05 10269720 [anon:dalvik-LinearAlloc]
-70eaea4000-70eaede000 r-xp 00000000 fc:00 2924 /system/lib64/libwilhelm.so
-70eaede000-70eaefa000 ---p 00000000 00:00 0
-70eaefa000-70eaeff000 r--p 0003b000 fc:00 2924 /system/lib64/libwilhelm.so
-70eaeff000-70eaf00000 rw-p 00040000 fc:00 2924 /system/lib64/libwilhelm.so
-70eaf00000-70eaf03000 r--s 00000000 fc:00 242 /system/fonts/NotoSansElbasan-Regular.otf
-70eaf03000-70eaf21000 r-xp 00000000 fc:00 2415 /system/lib64/libdrmframework.so
-70eaf21000-70eaf38000 ---p 00000000 00:00 0
-70eaf38000-70eaf3d000 r--p 0002b000 fc:00 2415 /system/lib64/libdrmframework.so
-70eaf3d000-70eaf3e000 rw-p 00030000 fc:00 2415 /system/lib64/libdrmframework.so
-70eaf3e000-70eaf43000 r--s 00000000 fc:00 70 /system/fonts/NotoSansHebrew-Regular.ttf
-70eaf43000-70eaf44000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eaf44000-70eaf48000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eaf48000-70eaf49000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eaf49000-70eaf4c000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eaf4c000-70eaf4d000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eaf4d000-70eaf4e000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eaf4e000-70eaf52000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eaf52000-70eaf98000 r-xp 00000000 fc:00 2426 /system/lib64/libunwindstack.so
-70eaf98000-70eafb6000 ---p 00000000 00:00 0
-70eafb6000-70eafbd000 r--p 00049000 fc:00 2426 /system/lib64/libunwindstack.so
-70eafbd000-70eafbe000 rw-p 00050000 fc:00 2426 /system/lib64/libunwindstack.so
-70eafbe000-70eafc0000 r--s 00000000 fc:00 162 /system/fonts/NotoSansKayahLi-Regular.ttf
-70eafc0000-70eafe4000 r-xp 00000000 fc:00 2944 /system/lib64/libvulkan.so
-70eafe4000-70eaffc000 ---p 00000000 00:00 0
-70eaffc000-70eaffe000 r--p 0002e000 fc:00 2944 /system/lib64/libvulkan.so
-70eaffe000-70eafff000 rw-p 00030000 fc:00 2944 /system/lib64/libvulkan.so
-70eafff000-70eb001000 r--s 00000000 fc:00 180 /system/fonts/NotoSansInscriptionalParthian-Regular.ttf
-70eb001000-70eb01d000 r-xp 00000000 fc:00 2400 /system/lib64/libbufferhubqueue.so
-70eb01d000-70eb030000 ---p 00000000 00:00 0
-70eb030000-70eb031000 r--p 0001f000 fc:00 2400 /system/lib64/libbufferhubqueue.so
-70eb031000-70eb032000 rw-p 00020000 fc:00 2400 /system/lib64/libbufferhubqueue.so
-70eb032000-70eb036000 r--s 00000000 fc:00 269 /system/fonts/NotoSansArmenian-Bold.ttf
-70eb036000-70eb037000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb037000-70eb03a000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eb03a000-70eb03b000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb03b000-70eb03c000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eb03c000-70eb040000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eb040000-70eb042000 r-xp 00000000 fc:00 2935 /system/lib64/libhardware.so
-70eb042000-70eb05f000 ---p 00000000 00:00 0
-70eb05f000-70eb060000 r--p 0000f000 fc:00 2935 /system/lib64/libhardware.so
-70eb060000-70eb061000 rw-p 00010000 fc:00 2935 /system/lib64/libhardware.so
-70eb061000-70eb063000 r--s 00000000 fc:00 171 /system/fonts/NotoSansInscriptionalPahlavi-Regular.ttf
-70eb063000-70eb064000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb064000-70eb067000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eb067000-70eb068000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb068000-70eb069000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eb069000-70eb06d000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eb06d000-70eb06e000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb06e000-70eb071000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eb071000-70eb072000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb072000-70eb073000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eb073000-70eb077000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eb077000-70eb078000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb078000-70eb07b000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eb07b000-70eb07c000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb07c000-70eb07d000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eb07d000-70eb081000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eb081000-70eb082000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb082000-70eb085000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eb085000-70eb086000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb086000-70eb09d000 r-xp 00000000 fc:00 2604 /system/lib64/libz.so
-70eb09d000-70eb0b5000 ---p 00000000 00:00 0
-70eb0b5000-70eb0b6000 r--p 0001f000 fc:00 2604 /system/lib64/libz.so
-70eb0b6000-70eb0b7000 rw-p 00020000 fc:00 2604 /system/lib64/libz.so
-70eb0b7000-70eb0bb000 r--s 00000000 fc:00 289 /system/fonts/NotoSansArmenian-Regular.ttf
-70eb0bb000-70eb0bc000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eb0bc000-70eb0c0000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eb0c0000-70eb0c1000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb0c1000-70eb0c4000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eb0c4000-70eb0c5000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb0c5000-70eb0c6000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70eb0c6000-70eb0ca000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70eb0ca000-70eb0cb000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb0cb000-70eb0ce000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70eb0ce000-70eb0cf000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70eb0cf000-70eb0ef000 rw-p 00000000 00:05 10270988 [anon:dalvik-LinearAlloc]
-70eb0ef000-70eb5bb000 r-xp 00000000 fc:00 2374 /system/lib64/libpdfium.so
-70eb5bb000-70eb5cf000 ---p 00000000 00:00 0
-70eb5cf000-70eb5e6000 r--p 004d9000 fc:00 2374 /system/lib64/libpdfium.so
-70eb5e6000-70eb5ea000 rw-p 004f0000 fc:00 2374 /system/lib64/libpdfium.so
-70eb5ea000-70eb5f1000 rw-p 00000000 00:00 0 [anon:.bss]
-70eb5f1000-70eb5f2000 r--s 00000000 fc:00 1094 /system/usr/hyphen-data/hyph-hi.hyb
-70eb5f2000-70eb5f6000 rw-p 00000000 00:05 10270982 [anon:dalvik-thread local mark stack]
-70eb5f6000-70eb5fa000 rw-p 00000000 00:05 10270981 [anon:dalvik-thread local mark stack]
-70eb5fa000-70eb5fe000 rw-p 00000000 00:05 10270980 [anon:dalvik-thread local mark stack]
-70eb5fe000-70eb602000 rw-p 00000000 00:05 10270979 [anon:dalvik-thread local mark stack]
-70eb602000-70eb606000 rw-p 00000000 00:05 10270978 [anon:dalvik-thread local mark stack]
-70eb606000-70eb60a000 rw-p 00000000 00:05 10270977 [anon:dalvik-thread local mark stack]
-70eb60a000-70eb60e000 rw-p 00000000 00:05 10270976 [anon:dalvik-thread local mark stack]
-70eb60e000-70eb612000 rw-p 00000000 00:05 10270975 [anon:dalvik-thread local mark stack]
-70eb612000-70eb616000 rw-p 00000000 00:05 10270974 [anon:dalvik-thread local mark stack]
-70eb616000-70eb61a000 r-xp 00000000 fc:00 2479 /system/lib64/libspeexresampler.so
-70eb61a000-70eb635000 ---p 00000000 00:00 0
-70eb635000-70eb636000 r--p 0000f000 fc:00 2479 /system/lib64/libspeexresampler.so
-70eb636000-70eb637000 rw-p 00010000 fc:00 2479 /system/lib64/libspeexresampler.so
-70eb637000-70eb639000 r--s 00000000 fc:00 299 /system/fonts/NotoSansImperialAramaic-Regular.ttf
-70eb639000-70eb63d000 rw-p 00000000 00:05 10270973 [anon:dalvik-thread local mark stack]
-70eb63d000-70eb641000 rw-p 00000000 00:05 10270972 [anon:dalvik-thread local mark stack]
-70eb641000-70eb645000 rw-p 00000000 00:05 10270971 [anon:dalvik-thread local mark stack]
-70eb645000-70eb649000 rw-p 00000000 00:05 10270970 [anon:dalvik-thread local mark stack]
-70eb649000-70eb64d000 rw-p 00000000 00:05 10270969 [anon:dalvik-thread local mark stack]
-70eb64d000-70eb651000 rw-p 00000000 00:05 10270968 [anon:dalvik-thread local mark stack]
-70eb651000-70eb655000 rw-p 00000000 00:05 10270967 [anon:dalvik-thread local mark stack]
-70eb655000-70eb659000 rw-p 00000000 00:05 10270966 [anon:dalvik-thread local mark stack]
-70eb659000-70eb65d000 rw-p 00000000 00:05 10270965 [anon:dalvik-thread local mark stack]
-70eb65d000-70eb661000 rw-p 00000000 00:05 10270964 [anon:dalvik-thread local mark stack]
-70eb661000-70eb6c5000 r-xp 00000000 fc:00 2461 /system/lib64/libhidl-gen-utils.so
-70eb6c5000-70eb6df000 ---p 00000000 00:00 0
-70eb6df000-70eb6e1000 r--p 0006e000 fc:00 2461 /system/lib64/libhidl-gen-utils.so
-70eb6e1000-70eb6e2000 rw-p 00070000 fc:00 2461 /system/lib64/libhidl-gen-utils.so
-70eb6e2000-70eb6e6000 rw-p 00000000 00:05 10270963 [anon:dalvik-thread local mark stack]
-70eb6e6000-70eb6ea000 rw-p 00000000 00:05 10270962 [anon:dalvik-thread local mark stack]
-70eb6ea000-70eb6ee000 rw-p 00000000 00:05 10270961 [anon:dalvik-thread local mark stack]
-70eb6ee000-70eb6f2000 rw-p 00000000 00:05 10270960 [anon:dalvik-thread local mark stack]
-70eb6f2000-70eb6f6000 rw-p 00000000 00:05 10270959 [anon:dalvik-thread local mark stack]
-70eb6f6000-70eb6fa000 rw-p 00000000 00:05 10270958 [anon:dalvik-thread local mark stack]
-70eb6fa000-70eb6fe000 rw-p 00000000 00:05 10270957 [anon:dalvik-thread local mark stack]
-70eb6fe000-70eb702000 rw-p 00000000 00:05 10270956 [anon:dalvik-thread local mark stack]
-70eb702000-70eb706000 rw-p 00000000 00:05 10270955 [anon:dalvik-thread local mark stack]
-70eb706000-70eb70a000 rw-p 00000000 00:05 10270954 [anon:dalvik-thread local mark stack]
-70eb70a000-70eb70e000 rw-p 00000000 00:05 10270953 [anon:dalvik-thread local mark stack]
-70eb70e000-70eb712000 rw-p 00000000 00:05 10270952 [anon:dalvik-thread local mark stack]
-70eb712000-70eb71a000 r-xp 00000000 fc:00 2652 /system/lib64/libcamera_metadata.so
-70eb71a000-70eb72f000 ---p 00000000 00:00 0
-70eb72f000-70eb730000 r--p 0000f000 fc:00 2652 /system/lib64/libcamera_metadata.so
-70eb730000-70eb732000 rw-p 00010000 fc:00 2652 /system/lib64/libcamera_metadata.so
-70eb732000-70eb734000 r--s 00000000 fc:00 131 /system/fonts/NotoSansHanunoo-Regular.ttf
-70eb734000-70eb738000 rw-p 00000000 00:05 10270951 [anon:dalvik-thread local mark stack]
-70eb738000-70eb73c000 rw-p 00000000 00:05 10270950 [anon:dalvik-thread local mark stack]
-70eb73c000-70eb740000 rw-p 00000000 00:05 10270949 [anon:dalvik-thread local mark stack]
-70eb740000-70eb744000 rw-p 00000000 00:05 10270948 [anon:dalvik-thread local mark stack]
-70eb744000-70eb748000 rw-p 00000000 00:05 10270947 [anon:dalvik-thread local mark stack]
-70eb748000-70eb74c000 rw-p 00000000 00:05 10270946 [anon:dalvik-thread local mark stack]
-70eb74c000-70eb750000 rw-p 00000000 00:05 10270945 [anon:dalvik-thread local mark stack]
-70eb750000-70eb754000 rw-p 00000000 00:05 10270944 [anon:dalvik-thread local mark stack]
-70eb754000-70eb758000 rw-p 00000000 00:05 10270943 [anon:dalvik-thread local mark stack]
-70eb758000-70eb75c000 rw-p 00000000 00:05 10270942 [anon:dalvik-thread local mark stack]
-70eb75c000-70eb760000 rw-p 00000000 00:05 10270941 [anon:dalvik-thread local mark stack]
-70eb760000-70eb764000 rw-p 00000000 00:05 10270940 [anon:dalvik-thread local mark stack]
-70eb764000-70eb767000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb767000-70eb768000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb768000-70eb76c000 rw-p 00000000 00:05 10270939 [anon:dalvik-thread local mark stack]
-70eb76c000-70eb770000 rw-p 00000000 00:05 10270938 [anon:dalvik-thread local mark stack]
-70eb770000-70eb771000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb771000-70eb774000 r--s 00000000 fc:00 231 /system/fonts/NotoSansDeseret-Regular.ttf
-70eb774000-70eb778000 rw-p 00000000 00:05 10270937 [anon:dalvik-thread local mark stack]
-70eb778000-70eb77c000 rw-p 00000000 00:05 10270936 [anon:dalvik-thread local mark stack]
-70eb77c000-70eb780000 rw-p 00000000 00:05 10270935 [anon:dalvik-thread local mark stack]
-70eb780000-70eb784000 rw-p 00000000 00:05 10270934 [anon:dalvik-thread local mark stack]
-70eb784000-70eb788000 rw-p 00000000 00:05 10270933 [anon:dalvik-thread local mark stack]
-70eb788000-70eb78c000 rw-p 00000000 00:05 10270932 [anon:dalvik-thread local mark stack]
-70eb78c000-70eb790000 rw-p 00000000 00:05 10270931 [anon:dalvik-thread local mark stack]
-70eb790000-70eb794000 rw-p 00000000 00:05 10270930 [anon:dalvik-thread local mark stack]
-70eb794000-70eb798000 rw-p 00000000 00:05 10270929 [anon:dalvik-thread local mark stack]
-70eb798000-70eb79c000 rw-p 00000000 00:05 10270928 [anon:dalvik-thread local mark stack]
-70eb79c000-70eb7a0000 rw-p 00000000 00:05 10270927 [anon:dalvik-thread local mark stack]
-70eb7a0000-70eb7a1000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb7a1000-70eb7a3000 r--s 00000000 fc:00 176 /system/fonts/NotoSansGothic-Regular.ttf
-70eb7a3000-70eb7a7000 rw-p 00000000 00:05 10270926 [anon:dalvik-thread local mark stack]
-70eb7a7000-70eb7a8000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb7a8000-70eb7a9000 r--s 00000000 fc:00 1109 /system/usr/hyphen-data/hyph-gu.hyb
-70eb7a9000-70eb7ad000 rw-p 00000000 00:05 10270925 [anon:dalvik-thread local mark stack]
-70eb7ad000-70eb7ae000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb7ae000-70eb7af000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb7af000-70eb7b0000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb7b0000-70eb7b2000 r--s 00000000 fc:00 191 /system/fonts/NotoSansCypriot-Regular.ttf
-70eb7b2000-70eb7b6000 rw-p 00000000 00:05 10270924 [anon:dalvik-thread local mark stack]
-70eb7b6000-70eb7ba000 rw-p 00000000 00:05 10270923 [anon:dalvik-thread local mark stack]
-70eb7ba000-70eb7be000 rw-p 00000000 00:05 10270922 [anon:dalvik-thread local mark stack]
-70eb7be000-70eb7c2000 rw-p 00000000 00:05 10270921 [anon:dalvik-thread local mark stack]
-70eb7c2000-70eb7c6000 rw-p 00000000 00:05 10270920 [anon:dalvik-thread local mark stack]
-70eb7c6000-70eb7ca000 rw-p 00000000 00:05 10270919 [anon:dalvik-thread local mark stack]
-70eb7ca000-70eb7ce000 rw-p 00000000 00:05 10270918 [anon:dalvik-thread local mark stack]
-70eb7ce000-70eb7d2000 rw-p 00000000 00:05 10270917 [anon:dalvik-thread local mark stack]
-70eb7d2000-70eb7d6000 rw-p 00000000 00:05 10270916 [anon:dalvik-thread local mark stack]
-70eb7d6000-70eb7d7000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70eb7d7000-70eb7db000 rw-p 00000000 00:05 10270915 [anon:dalvik-thread local mark stack]
-70eb7db000-70eb7df000 rw-p 00000000 00:05 10270914 [anon:dalvik-thread local mark stack]
-70eb7df000-70eb7e3000 rw-p 00000000 00:05 10270913 [anon:dalvik-thread local mark stack]
-70eb7e3000-70eb7e7000 rw-p 00000000 00:05 10270912 [anon:dalvik-thread local mark stack]
-70eb7e7000-70eb7e8000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb7e8000-70eb7ea000 r--s 00000000 fc:00 174 /system/fonts/NotoSansCarian-Regular.ttf
-70eb7ea000-70eb7ee000 rw-p 00000000 00:05 10270911 [anon:dalvik-thread local mark stack]
-70eb7ee000-70eb7f2000 rw-p 00000000 00:05 10270910 [anon:dalvik-thread local mark stack]
-70eb7f2000-70eb7f6000 rw-p 00000000 00:05 10270909 [anon:dalvik-thread local mark stack]
-70eb7f6000-70eb7f7000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb7f7000-70eb7f8000 r--s 00000000 fc:00 1096 /system/usr/hyphen-data/hyph-eu.hyb
-70eb7f8000-70eb7fc000 rw-p 00000000 00:05 10270908 [anon:dalvik-thread local mark stack]
-70eb7fc000-70eb800000 rw-p 00000000 00:05 10270907 [anon:dalvik-thread local mark stack]
-70eb800000-70eb804000 rw-p 00000000 00:05 10270906 [anon:dalvik-thread local mark stack]
-70eb804000-70eb808000 rw-p 00000000 00:05 10270905 [anon:dalvik-thread local mark stack]
-70eb808000-70eb80c000 rw-p 00000000 00:05 10270904 [anon:dalvik-thread local mark stack]
-70eb80c000-70eb810000 rw-p 00000000 00:05 10270903 [anon:dalvik-thread local mark stack]
-70eb810000-70eb814000 rw-p 00000000 00:05 10270902 [anon:dalvik-thread local mark stack]
-70eb814000-70eb815000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
-70eb815000-70eb819000 rw-p 00000000 00:05 10270901 [anon:dalvik-thread local mark stack]
-70eb819000-70eb81d000 rw-p 00000000 00:05 10270900 [anon:dalvik-thread local mark stack]
-70eb81d000-70eb81e000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb81e000-70eb822000 rw-p 00000000 00:05 10270899 [anon:dalvik-thread local mark stack]
-70eb822000-70eb826000 rw-p 00000000 00:05 10270898 [anon:dalvik-thread local mark stack]
-70eb826000-70eb82a000 rw-p 00000000 00:05 10270897 [anon:dalvik-thread local mark stack]
-70eb82a000-70eb82e000 rw-p 00000000 00:05 10270896 [anon:dalvik-thread local mark stack]
-70eb82e000-70eb832000 rw-p 00000000 00:05 10270895 [anon:dalvik-thread local mark stack]
-70eb832000-70eb836000 rw-p 00000000 00:05 10270894 [anon:dalvik-thread local mark stack]
-70eb836000-70eb837000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb837000-70eb83b000 rw-p 00000000 00:05 10270893 [anon:dalvik-thread local mark stack]
-70eb83b000-70eb83f000 rw-p 00000000 00:05 10270892 [anon:dalvik-thread local mark stack]
-70eb83f000-70eb843000 rw-p 00000000 00:05 10270891 [anon:dalvik-thread local mark stack]
-70eb843000-70eb847000 rw-p 00000000 00:05 10270890 [anon:dalvik-thread local mark stack]
-70eb847000-70eb84b000 rw-p 00000000 00:05 10270889 [anon:dalvik-thread local mark stack]
-70eb84b000-70eb84f000 rw-p 00000000 00:05 10270888 [anon:dalvik-thread local mark stack]
-70eb84f000-70eb850000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb850000-70eb854000 rw-p 00000000 00:05 10270887 [anon:dalvik-thread local mark stack]
-70eb854000-70eb858000 rw-p 00000000 00:05 10270886 [anon:dalvik-thread local mark stack]
-70eb858000-70eb85c000 rw-p 00000000 00:05 10270885 [anon:dalvik-thread local mark stack]
-70eb85c000-70eb860000 rw-p 00000000 00:05 10270884 [anon:dalvik-thread local mark stack]
-70eb860000-70eb864000 rw-p 00000000 00:05 10270883 [anon:dalvik-thread local mark stack]
-70eb864000-70eb868000 rw-p 00000000 00:05 10270882 [anon:dalvik-thread local mark stack]
-70eb868000-70eb869000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb869000-70eb86d000 rw-p 00000000 00:05 10270881 [anon:dalvik-thread local mark stack]
-70eb86d000-70eb871000 rw-p 00000000 00:05 10270880 [anon:dalvik-thread local mark stack]
-70eb871000-70eb875000 rw-p 00000000 00:05 10270879 [anon:dalvik-thread local mark stack]
-70eb875000-70eb879000 rw-p 00000000 00:05 10270878 [anon:dalvik-thread local mark stack]
-70eb879000-70eb87d000 rw-p 00000000 00:05 10270877 [anon:dalvik-thread local mark stack]
-70eb87d000-70eb881000 rw-p 00000000 00:05 10270876 [anon:dalvik-thread local mark stack]
-70eb881000-70eb885000 rw-p 00000000 00:05 10270875 [anon:dalvik-thread local mark stack]
-70eb885000-70eb889000 rw-p 00000000 00:05 10270874 [anon:dalvik-thread local mark stack]
-70eb889000-70eb88d000 rw-p 00000000 00:05 10270873 [anon:dalvik-thread local mark stack]
-70eb88d000-70eb891000 rw-p 00000000 00:05 10270872 [anon:dalvik-thread local mark stack]
-70eb891000-70eb892000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb892000-70eb896000 rw-p 00000000 00:05 10270871 [anon:dalvik-thread local mark stack]
-70eb896000-70eb89a000 rw-p 00000000 00:05 10270870 [anon:dalvik-thread local mark stack]
-70eb89a000-70eb89b000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
-70eb89b000-70eb89c000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70eb89c000-70eb8a0000 rw-p 00000000 00:05 10270869 [anon:dalvik-thread local mark stack]
-70eb8a0000-70eb8a4000 rw-p 00000000 00:05 10270868 [anon:dalvik-thread local mark stack]
-70eb8a4000-70eb8a5000 r--p 00000000 00:00 0 [anon:atexit handlers]
-70eb8a5000-70eb8a9000 rw-p 00000000 00:05 10270867 [anon:dalvik-thread local mark stack]
-70eb8a9000-70eb8ad000 rw-p 00000000 00:05 10270866 [anon:dalvik-thread local mark stack]
-70eb8ad000-70eb8b1000 rw-p 00000000 00:05 10270865 [anon:dalvik-thread local mark stack]
-70eb8b1000-70eb8b5000 rw-p 00000000 00:05 10270864 [anon:dalvik-thread local mark stack]
-70eb8b5000-70eb8b9000 rw-p 00000000 00:05 10270863 [anon:dalvik-thread local mark stack]
-70eb8b9000-70eb8bd000 rw-p 00000000 00:05 10270862 [anon:dalvik-thread local mark stack]
-70eb8bd000-70eb8be000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb8be000-70eb8c1000 r--s 00000000 fc:00 168 /system/fonts/NotoSansAvestan-Regular.ttf
-70eb8c1000-70eb8c5000 rw-p 00000000 00:05 10270861 [anon:dalvik-thread local mark stack]
-70eb8c5000-70eb8c9000 rw-p 00000000 00:05 10270860 [anon:dalvik-thread local mark stack]
-70eb8c9000-70eb8cd000 rw-p 00000000 00:05 10270859 [anon:dalvik-thread local mark stack]
-70eb8cd000-70eb8d1000 rw-p 00000000 00:05 10270858 [anon:dalvik-thread local mark stack]
-70eb8d1000-70eb8d5000 rw-p 00000000 00:05 10270857 [anon:dalvik-thread local mark stack]
-70eb8d5000-70eb8d7000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb8d7000-70eb8db000 rw-p 00000000 00:05 10270856 [anon:dalvik-thread local mark stack]
-70eb8db000-70eb8df000 rw-p 00000000 00:05 10270855 [anon:dalvik-thread local mark stack]
-70eb8df000-70eb8e3000 rw-p 00000000 00:05 10270854 [anon:dalvik-thread local mark stack]
-70eb8e3000-70eb8e7000 rw-p 00000000 00:05 10270853 [anon:dalvik-thread local mark stack]
-70eb8e7000-70eb8eb000 rw-p 00000000 00:05 10270852 [anon:dalvik-thread local mark stack]
-70eb8eb000-70eb8ec000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb8ec000-70eb8ed000 r--s 00000000 fc:00 1099 /system/usr/hyphen-data/hyph-bn.hyb
-70eb8ed000-70eb8f1000 rw-p 00000000 00:05 10270851 [anon:dalvik-thread local mark stack]
-70eb8f1000-70eb8f5000 rw-p 00000000 00:05 10270850 [anon:dalvik-thread local mark stack]
-70eb8f5000-70eb8f9000 rw-p 00000000 00:05 10270849 [anon:dalvik-thread local mark stack]
-70eb8f9000-70eb8fd000 rw-p 00000000 00:05 10270848 [anon:dalvik-thread local mark stack]
-70eb8fd000-70eb901000 rw-p 00000000 00:05 10270847 [anon:dalvik-thread local mark stack]
-70eb901000-70eb905000 rw-p 00000000 00:05 10270846 [anon:dalvik-thread local mark stack]
-70eb905000-70eb909000 rw-p 00000000 00:05 10270845 [anon:dalvik-thread local mark stack]
-70eb909000-70eb90d000 rw-p 00000000 00:05 10270844 [anon:dalvik-thread local mark stack]
-70eb90d000-70eb911000 rw-p 00000000 00:05 10270843 [anon:dalvik-thread local mark stack]
-70eb911000-70eb915000 rw-p 00000000 00:05 10270842 [anon:dalvik-thread local mark stack]
-70eb915000-70eb916000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb916000-70eb917000 r--s 00000000 fc:00 1114 /system/usr/hyphen-data/hyph-bg.hyb
-70eb917000-70eb91b000 rw-p 00000000 00:05 10270841 [anon:dalvik-thread local mark stack]
-70eb91b000-70eb91c000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb91c000-70eb91d000 r--s 00000000 fc:00 1133 /system/usr/hyphen-data/hyph-as.hyb
-70eb91d000-70eb921000 rw-p 00000000 00:05 10270840 [anon:dalvik-thread local mark stack]
-70eb921000-70eb925000 rw-p 00000000 00:05 10270839 [anon:dalvik-thread local mark stack]
-70eb925000-70eb926000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70eb926000-70eb927000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb927000-70eb929000 r--s 00000000 fc:00 203 /system/fonts/NotoSansBuhid-Regular.ttf
-70eb929000-70eb92d000 rw-p 00000000 00:05 10270838 [anon:dalvik-thread local mark stack]
-70eb92d000-70eb931000 rw-p 00000000 00:05 10270837 [anon:dalvik-thread local mark stack]
-70eb931000-70eb935000 rw-p 00000000 00:05 10270836 [anon:dalvik-thread local mark stack]
-70eb935000-70eb939000 rw-p 00000000 00:05 10270835 [anon:dalvik-thread local mark stack]
-70eb939000-70eb93d000 rw-p 00000000 00:05 10270834 [anon:dalvik-thread local mark stack]
-70eb93d000-70eb941000 rw-p 00000000 00:05 10270833 [anon:dalvik-thread local mark stack]
-70eb941000-70eb945000 rw-p 00000000 00:05 10270832 [anon:dalvik-thread local mark stack]
-70eb945000-70eb949000 rw-p 00000000 00:05 10270831 [anon:dalvik-thread local mark stack]
-70eb949000-70eb94d000 rw-p 00000000 00:05 10270830 [anon:dalvik-thread local mark stack]
-70eb94d000-70eb951000 rw-p 00000000 00:05 10270829 [anon:dalvik-thread local mark stack]
-70eb951000-70eb991000 rw-p 00000000 00:05 10270722 [anon:dalvik-mark stack]
-70eb991000-70eb992000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb992000-70eb996000 rw-p 00000000 00:05 10270828 [anon:dalvik-thread local mark stack]
-70eb996000-70eb99a000 rw-p 00000000 00:05 10270827 [anon:dalvik-thread local mark stack]
-70eb99a000-70eb99e000 rw-p 00000000 00:05 10270826 [anon:dalvik-thread local mark stack]
-70eb99e000-70eb9a2000 rw-p 00000000 00:05 10270825 [anon:dalvik-thread local mark stack]
-70eb9a2000-70eb9a4000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb9a4000-70eb9a8000 rw-p 00000000 00:05 10270824 [anon:dalvik-thread local mark stack]
-70eb9a8000-70eb9ac000 rw-p 00000000 00:05 10270823 [anon:dalvik-thread local mark stack]
-70eb9ac000-70eb9b0000 rw-p 00000000 00:05 10270822 [anon:dalvik-thread local mark stack]
-70eb9b0000-70eb9b1000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb9b1000-70eb9b2000 r--s 00021000 fc:01 1180 /vendor/overlay/framework-res__auto_generated_rro.apk
-70eb9b2000-70eb9b6000 rw-p 00000000 00:05 10270821 [anon:dalvik-thread local mark stack]
-70eb9b6000-70eb9ba000 rw-p 00000000 00:05 10270820 [anon:dalvik-thread local mark stack]
-70eb9ba000-70eb9be000 rw-p 00000000 00:05 10270819 [anon:dalvik-thread local mark stack]
-70eb9be000-70eb9c2000 rw-p 00000000 00:05 10270818 [anon:dalvik-thread local mark stack]
-70eb9c2000-70eb9c6000 rw-p 00000000 00:05 10270817 [anon:dalvik-thread local mark stack]
-70eb9c6000-70eb9ca000 rw-p 00000000 00:05 10270816 [anon:dalvik-thread local mark stack]
-70eb9ca000-70eb9ce000 rw-p 00000000 00:05 10270815 [anon:dalvik-thread local mark stack]
-70eb9ce000-70eb9cf000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb9cf000-70eb9d1000 r--s 00000000 fc:00 213 /system/fonts/NotoSansBuginese-Regular.ttf
-70eb9d1000-70eb9d5000 rw-p 00000000 00:05 10270814 [anon:dalvik-thread local mark stack]
-70eb9d5000-70eb9d9000 rw-p 00000000 00:05 10270813 [anon:dalvik-thread local mark stack]
-70eb9d9000-70eb9dd000 rw-p 00000000 00:05 10270812 [anon:dalvik-thread local mark stack]
-70eb9dd000-70eb9e1000 rw-p 00000000 00:05 10270811 [anon:dalvik-thread local mark stack]
-70eb9e1000-70eb9e5000 rw-p 00000000 00:05 10270810 [anon:dalvik-thread local mark stack]
-70eb9e5000-70eb9e9000 rw-p 00000000 00:05 10270809 [anon:dalvik-thread local mark stack]
-70eb9e9000-70eb9ed000 rw-p 00000000 00:05 10270808 [anon:dalvik-thread local mark stack]
-70eb9ed000-70eb9f1000 rw-p 00000000 00:05 10270807 [anon:dalvik-thread local mark stack]
-70eb9f1000-70eb9f5000 rw-p 00000000 00:05 10270806 [anon:dalvik-thread local mark stack]
-70eb9f5000-70eb9f6000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eb9f6000-70eb9f8000 rw-p 00000000 00:05 10271002 [anon:dalvik-indirect ref table]
-70eb9f8000-70eb9fc000 rw-p 00000000 00:05 10270805 [anon:dalvik-thread local mark stack]
-70eb9fc000-70eb9fd000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eb9fd000-70eb9ff000 rw-p 00000000 00:05 10270999 [anon:dalvik-indirect ref table]
-70eb9ff000-70eba00000 r--s 00000000 fc:00 983 /system/framework/com.google.vr.platform.jar
-70eba00000-70eba04000 rw-p 00000000 00:05 10270804 [anon:dalvik-thread local mark stack]
-70eba04000-70eba08000 rw-p 00000000 00:05 10270803 [anon:dalvik-thread local mark stack]
-70eba08000-70eba0c000 rw-p 00000000 00:05 10270802 [anon:dalvik-thread local mark stack]
-70eba0c000-70eba10000 rw-p 00000000 00:05 10270801 [anon:dalvik-thread local mark stack]
-70eba10000-70eba14000 rw-p 00000000 00:05 10270800 [anon:dalvik-thread local mark stack]
-70eba14000-70eba18000 rw-p 00000000 00:05 10270799 [anon:dalvik-thread local mark stack]
-70eba18000-70eba1c000 rw-p 00000000 00:05 10270798 [anon:dalvik-thread local mark stack]
-70eba1c000-70eba20000 rw-p 00000000 00:05 10270797 [anon:dalvik-thread local mark stack]
-70eba20000-70eba24000 rw-p 00000000 00:05 10270796 [anon:dalvik-thread local mark stack]
-70eba24000-70eba28000 rw-p 00000000 00:05 10270795 [anon:dalvik-thread local mark stack]
-70eba28000-70eba2c000 rw-p 00000000 00:05 10270794 [anon:dalvik-thread local mark stack]
-70eba2c000-70eba2d000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eba2d000-70eba2e000 r--s 00000000 fc:00 881 /system/framework/android.test.base.jar
-70eba2e000-70eba2f000 r--s 00000000 fc:00 707 /system/framework/framework-oahl-backward-compatibility.jar
-70eba2f000-70eba30000 r--s 00000000 fc:00 705 /system/framework/android.hidl.manager-V1.0-java.jar
-70eba30000-70eba34000 rw-p 00000000 00:05 10270793 [anon:dalvik-thread local mark stack]
-70eba34000-70eba38000 rw-p 00000000 00:05 10270792 [anon:dalvik-thread local mark stack]
-70eba38000-70eba3c000 rw-p 00000000 00:05 10270791 [anon:dalvik-thread local mark stack]
-70eba3c000-70eba40000 rw-p 00000000 00:05 10270790 [anon:dalvik-thread local mark stack]
-70eba40000-70eba44000 rw-p 00000000 00:05 10270789 [anon:dalvik-thread local mark stack]
-70eba44000-70eba48000 rw-p 00000000 00:05 10270788 [anon:dalvik-thread local mark stack]
-70eba48000-70eba4c000 rw-p 00000000 00:05 10270787 [anon:dalvik-thread local mark stack]
-70eba4c000-70eba50000 rw-p 00000000 00:05 10270786 [anon:dalvik-thread local mark stack]
-70eba50000-70eba52000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70eba52000-70eba53000 r--s 00000000 fc:00 971 /system/framework/android.hidl.base-V1.0-java.jar
-70eba53000-70eba57000 rw-p 00000000 00:05 10270785 [anon:dalvik-thread local mark stack]
-70eba57000-70eba5b000 rw-p 00000000 00:05 10270784 [anon:dalvik-thread local mark stack]
-70eba5b000-70eba5f000 rw-p 00000000 00:05 10270783 [anon:dalvik-thread local mark stack]
-70eba5f000-70eba63000 rw-p 00000000 00:05 10270782 [anon:dalvik-thread local mark stack]
-70eba63000-70eba64000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70eba64000-70eba65000 r--s 00000000 fc:00 889 /system/framework/ims-common.jar
-70eba65000-70eba69000 rw-p 00000000 00:05 10270781 [anon:dalvik-thread local mark stack]
-70eba69000-70eba6d000 rw-p 00000000 00:05 10270780 [anon:dalvik-thread local mark stack]
-70eba6d000-70eba71000 rw-p 00000000 00:05 10270779 [anon:dalvik-thread local mark stack]
-70eba71000-70eba75000 rw-p 00000000 00:05 10270778 [anon:dalvik-thread local mark stack]
-70eba75000-70eba95000 rw-p 00000000 00:05 10267647 [anon:dalvik-large marked objects]
-70eba95000-70ebab5000 rw-p 00000000 00:05 10267646 [anon:dalvik-large live objects]
-70ebab5000-70ebab6000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebab6000-70ebab7000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebab7000-70ebabb000 rw-p 00000000 00:05 10270777 [anon:dalvik-thread local mark stack]
-70ebabb000-70ebadb000 r--s 00000000 00:10 16603 /dev/__properties__/u:object_r:exported_fingerprint_prop:s0
-70ebadb000-70ebadc000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebadc000-70ebadd000 r--s 00000000 fc:00 878 /system/framework/voip-common.jar
-70ebadd000-70ebadf000 rw-p 00000000 00:05 10270995 [anon:dalvik-indirect ref table]
-70ebadf000-70ebae3000 rw-p 00000000 00:05 10270776 [anon:dalvik-thread local mark stack]
-70ebae3000-70ebae7000 rw-p 00000000 00:05 10270775 [anon:dalvik-thread local mark stack]
-70ebae7000-70ebaeb000 rw-p 00000000 00:05 10270774 [anon:dalvik-thread local mark stack]
-70ebaeb000-70ebaef000 rw-p 00000000 00:05 10270773 [anon:dalvik-thread local mark stack]
-70ebaef000-70ebb0f000 r--s 00000000 00:10 16582 /dev/__properties__/u:object_r:debug_prop:s0
-70ebb0f000-70ebb10000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebb10000-70ebb11000 r--s 00000000 fc:00 703 /system/framework/telephony-common.jar
-70ebb11000-70ebb13000 rw-p 00000000 00:05 10270994 [anon:dalvik-indirect ref table]
-70ebb13000-70ebb17000 rw-p 00000000 00:05 10270772 [anon:dalvik-thread local mark stack]
-70ebb17000-70ebb19000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebb19000-70ebb1d000 rw-p 00000000 00:05 10270771 [anon:dalvik-thread local mark stack]
-70ebb1d000-70ebb3d000 r--s 00000000 00:10 16600 /dev/__properties__/u:object_r:exported_default_prop:s0
-70ebb3d000-70ebb5d000 r--s 00000000 00:10 16650 /dev/__properties__/u:object_r:system_prop:s0
-70ebb5d000-70ebb7d000 r--s 00000000 00:10 16610 /dev/__properties__/u:object_r:exported_vold_prop:s0
-70ebb7d000-70ebb9d000 r--s 00000000 00:10 16598 /dev/__properties__/u:object_r:exported_config_prop:s0
-70ebb9d000-70ebb9e000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebb9e000-70ebba2000 rw-p 00000000 00:05 10270770 [anon:dalvik-thread local mark stack]
-70ebba2000-70ebba6000 rw-p 00000000 00:05 10270769 [anon:dalvik-thread local mark stack]
-70ebba6000-70ebba7000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebba7000-70ebba8000 r--s 00000000 fc:00 1004 /system/framework/framework.jar
-70ebba8000-70ebbac000 rw-p 00000000 00:05 10270768 [anon:dalvik-thread local mark stack]
-70ebbac000-70ebbb0000 rw-p 00000000 00:05 10270767 [anon:dalvik-thread local mark stack]
-70ebbb0000-70ebbb4000 rw-p 00000000 00:05 10270766 [anon:dalvik-thread local mark stack]
-70ebbb4000-70ebbb8000 rw-p 00000000 00:05 10270765 [anon:dalvik-thread local mark stack]
-70ebbb8000-70ebbbc000 rw-p 00000000 00:05 10270764 [anon:dalvik-thread local mark stack]
-70ebbbc000-70ebbc0000 rw-p 00000000 00:05 10270763 [anon:dalvik-thread local mark stack]
-70ebbc0000-70ebbc4000 rw-p 00000000 00:05 10270762 [anon:dalvik-thread local mark stack]
-70ebbc4000-70ebbe4000 r--s 00000000 00:10 16581 /dev/__properties__/u:object_r:dalvik_prop:s0
-70ebbe4000-70ebbe5000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebbe5000-70ebbe6000 r--s 00004000 fc:00 877 /system/framework/apache-xml.jar
-70ebbe6000-70ebbe8000 rw-p 00000000 00:05 10270993 [anon:dalvik-indirect ref table]
-70ebbe8000-70ebbec000 rw-p 00000000 00:05 10270761 [anon:dalvik-thread local mark stack]
-70ebbec000-70ebbf0000 rw-p 00000000 00:05 10270760 [anon:dalvik-thread local mark stack]
-70ebbf0000-70ebbf4000 rw-p 00000000 00:05 10270759 [anon:dalvik-thread local mark stack]
-70ebbf4000-70ebbf8000 rw-p 00000000 00:05 10270758 [anon:dalvik-thread local mark stack]
-70ebbf8000-70ebbf9000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebbf9000-70ebbfa000 r--s 00000000 fc:00 968 /system/framework/bouncycastle.jar
-70ebbfa000-70ebbfc000 rw-p 00000000 00:05 10270992 [anon:dalvik-indirect ref table]
-70ebbfc000-70ebc00000 rw-p 00000000 00:05 10270757 [anon:dalvik-thread local mark stack]
-70ebc00000-70ebc04000 rw-p 00000000 00:05 10270756 [anon:dalvik-thread local mark stack]
-70ebc04000-70ebc08000 rw-p 00000000 00:05 10270755 [anon:dalvik-thread local mark stack]
-70ebc08000-70ebc0c000 rw-p 00000000 00:05 10270754 [anon:dalvik-thread local mark stack]
-70ebc0c000-70ebc10000 rw-p 00000000 00:05 10270753 [anon:dalvik-thread local mark stack]
-70ebc10000-70ebc14000 rw-p 00000000 00:05 10270752 [anon:dalvik-thread local mark stack]
-70ebc14000-70ebc15000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebc15000-70ebc16000 r--s 00000000 fc:00 960 /system/framework/okhttp.jar
-70ebc16000-70ebc1a000 rw-p 00000000 00:05 10270751 [anon:dalvik-thread local mark stack]
-70ebc1a000-70ebc1e000 rw-p 00000000 00:05 10270750 [anon:dalvik-thread local mark stack]
-70ebc1e000-70ebc3e000 r--s 00000000 00:10 16584 /dev/__properties__/u:object_r:default_prop:s0
-70ebc3e000-70ebc3f000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebc3f000-70ebc40000 r--s 00000000 fc:00 974 /system/framework/conscrypt.jar
-70ebc40000-70ebc42000 rw-p 00000000 00:05 10269719 [anon:dalvik-indirect ref table]
-70ebc42000-70ebc46000 rw-p 00000000 00:05 10270749 [anon:dalvik-thread local mark stack]
-70ebc46000-70ebc4a000 rw-p 00000000 00:05 10270748 [anon:dalvik-thread local mark stack]
-70ebc4a000-70ebc4e000 rw-p 00000000 00:05 10270747 [anon:dalvik-thread local mark stack]
-70ebc4e000-70ebc4f000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebc4f000-70ebc51000 rw-p 00000000 00:05 10269718 [anon:dalvik-indirect ref table]
-70ebc51000-70ebc55000 rw-p 00000000 00:05 10270746 [anon:dalvik-thread local mark stack]
-70ebc55000-70ebc59000 rw-p 00000000 00:05 10270745 [anon:dalvik-thread local mark stack]
-70ebc59000-70ebc5d000 rw-p 00000000 00:05 10270744 [anon:dalvik-thread local mark stack]
-70ebc5d000-70ebc7d000 r--s 00000000 00:10 16599 /dev/__properties__/u:object_r:exported_dalvik_prop:s0
-70ebc7d000-70ebc7e000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebc7e000-70ebc7f000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebc7f000-70ebc80000 r--s 00004000 fc:00 963 /system/framework/core-libart.jar
-70ebc80000-70ebc81000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebc81000-70ebc85000 rw-p 00000000 00:05 10270743 [anon:dalvik-thread local mark stack]
-70ebc85000-70ebc89000 rw-p 00000000 00:05 10270742 [anon:dalvik-thread local mark stack]
-70ebc89000-70ebc8a000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebc8a000-70ebc8c000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebc8c000-70ebc8d000 r--s 0001e000 fc:00 699 /system/framework/core-oj.jar
-70ebc8d000-70ebc91000 rw-p 00000000 00:05 10270741 [anon:dalvik-thread local mark stack]
-70ebc91000-70ebc95000 rw-p 00000000 00:05 10270740 [anon:dalvik-thread local mark stack]
-70ebc95000-70ebc99000 rw-p 00000000 00:05 10270739 [anon:dalvik-thread local mark stack]
-70ebc99000-70ebc9b000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebc9b000-70ebc9c000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebc9c000-70ebca0000 rw-p 00000000 00:05 10270738 [anon:dalvik-thread local mark stack]
-70ebca0000-70ebca4000 rw-p 00000000 00:05 10270737 [anon:dalvik-thread local mark stack]
-70ebca4000-70ebca8000 rw-p 00000000 00:05 10270736 [anon:dalvik-thread local mark stack]
-70ebca8000-70ebcac000 rw-p 00000000 00:05 10270735 [anon:dalvik-thread local mark stack]
-70ebcac000-70ebcb0000 rw-p 00000000 00:05 10270734 [anon:dalvik-thread local mark stack]
-70ebcb0000-70ebcd0000 r--s 00000000 00:10 16592 /dev/__properties__/u:object_r:exported2_system_prop:s0
-70ebcd0000-70ebcd1000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebcd1000-70ebcd5000 rw-p 00000000 00:05 10270733 [anon:dalvik-thread local mark stack]
-70ebcd5000-70ebcd9000 rw-p 00000000 00:05 10270732 [anon:dalvik-thread local mark stack]
-70ebcd9000-70ebcdd000 rw-p 00000000 00:05 10270731 [anon:dalvik-thread local mark stack]
-70ebcdd000-70ebce1000 rw-p 00000000 00:05 10270730 [anon:dalvik-thread local mark stack]
-70ebce1000-70ebce5000 rw-p 00000000 00:05 10270729 [anon:dalvik-thread local mark stack]
-70ebce5000-70ebce9000 rw-p 00000000 00:05 10270728 [anon:dalvik-thread local mark stack]
-70ebce9000-70ebcea000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebcea000-70ebcec000 rw-p 00000000 00:05 10270987 [anon:dalvik-indirect ref table]
-70ebcec000-70ebcf9000 r--p 00646000 103:1d 639532 /data/dalvik-cache/arm64/system@framework@boot-framework.art
-70ebcf9000-70ebd19000 r--s 00000000 00:10 16620 /dev/__properties__/u:object_r:log_tag_prop:s0
-70ebd19000-70ebd39000 r--s 00000000 00:10 16621 /dev/__properties__/u:object_r:logd_prop:s0
-70ebd39000-70ebd3a000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebd3a000-70ebd3b000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebd3b000-70ebd3f000 rw-p 00000000 00:05 10270727 [anon:dalvik-thread local mark stack]
-70ebd3f000-70ebd40000 r--p 00002000 103:1d 639556 /data/dalvik-cache/arm64/system@framework@boot-com.google.vr.platform.art
-70ebd40000-70ebd41000 r--p 00005000 103:1d 639553 /data/dalvik-cache/arm64/system@framework@boot-android.test.base.art
-70ebd41000-70ebd42000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebd42000-70ebd43000 r--p 00001000 103:1d 639550 /data/dalvik-cache/arm64/system@framework@boot-framework-oahl-backward-compatibility.art
-70ebd43000-70ebd44000 r--p 00005000 103:1d 639547 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.manager-V1.0-java.art
-70ebd44000-70ebd45000 r--p 00003000 103:1d 639544 /data/dalvik-cache/arm64/system@framework@boot-android.hidl.base-V1.0-java.art
-70ebd45000-70ebd46000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebd46000-70ebd47000 r--p 0000f000 103:1d 639541 /data/dalvik-cache/arm64/system@framework@boot-ims-common.art
-70ebd47000-70ebd48000 r--p 0000d000 103:1d 639538 /data/dalvik-cache/arm64/system@framework@boot-voip-common.art
-70ebd48000-70ebd4a000 r--p 0005e000 103:1d 639535 /data/dalvik-cache/arm64/system@framework@boot-telephony-common.art
-70ebd4a000-70ebd4b000 r--p 00040000 103:1d 639529 /data/dalvik-cache/arm64/system@framework@boot-ext.art
-70ebd4b000-70ebd4c000 r--p 0004a000 103:1d 639526 /data/dalvik-cache/arm64/system@framework@boot-apache-xml.art
-70ebd4c000-70ebd4d000 r--p 00046000 103:1d 639523 /data/dalvik-cache/arm64/system@framework@boot-bouncycastle.art
-70ebd4d000-70ebd4e000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebd4e000-70ebd53000 r--p 00225000 103:1d 639511 /data/dalvik-cache/arm64/system@framework@boot.art
-70ebd53000-70ebd5a000 rw-p 00000000 fc:00 583 /system/etc/event-log-tags
-70ebd5a000-70ebd5b000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebd5b000-70ebd5c000 r--p 0002e000 103:1d 639520 /data/dalvik-cache/arm64/system@framework@boot-okhttp.art
-70ebd5c000-70ebd5d000 r--p 00035000 103:1d 639517 /data/dalvik-cache/arm64/system@framework@boot-conscrypt.art
-70ebd5d000-70ebd5f000 r--p 000d0000 103:1d 639514 /data/dalvik-cache/arm64/system@framework@boot-core-libart.art
-70ebd5f000-70ebd62000 r--p 00000000 00:00 0 [anon:atexit handlers]
-70ebd62000-70ebd63000 rw-p 00000000 00:00 0
-70ebd63000-70ebd83000 r--s 00000000 00:10 16590 /dev/__properties__/u:object_r:exported2_default_prop:s0
-70ebd83000-70ebd84000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebd84000-70ebd89000 rw-p 00000000 00:00 0
-70ebd89000-70ebda9000 r--s 00000000 00:10 16669 /dev/__properties__/properties_serial
-70ebda9000-70ebdb3000 r--s 00000000 00:10 16560 /dev/__properties__/property_info
-70ebdb3000-70ebdb4000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
-70ebdb4000-70ebdb5000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebdb5000-70ebdb7000 rw-p 00000000 00:00 0 [anon:System property context nodes]
-70ebdb7000-70ebdb8000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
-70ebdb8000-70ebdba000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebdba000-70ebdbb000 rw-p 00000000 00:00 0 [anon:linker_alloc]
-70ebdbb000-70ebdbd000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebdbd000-70ebdbe000 r--p 00000000 00:00 0 [anon:atexit handlers]
-70ebdbe000-70ebdbf000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebdbf000-70ebdc0000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebdc0000-70ebdc1000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
-70ebdc1000-70ebdc2000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebdc2000-70ebdc3000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
-70ebdc3000-70ebdc5000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebdc5000-70ebde5000 r--s 00000000 00:10 16600 /dev/__properties__/u:object_r:exported_default_prop:s0
-70ebde5000-70ebde6000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebde6000-70ebde8000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebde8000-70ebe08000 r--s 00000000 00:10 16582 /dev/__properties__/u:object_r:debug_prop:s0
-70ebe08000-70ebe09000 ---p 00000000 00:00 0
-70ebe09000-70ebe0a000 rw-p 00000000 00:00 0
-70ebe0a000-70ebe0b000 ---p 00000000 00:00 0
-70ebe0b000-70ebe2b000 r--s 00000000 00:10 16669 /dev/__properties__/properties_serial
-70ebe2b000-70ebe2d000 rw-p 00000000 00:00 0 [anon:System property context nodes]
-70ebe2d000-70ebf55000 r-xp 00000000 fc:00 3184 /system/bin/linker64
-70ebf55000-70ebf5f000 r--s 00000000 00:10 16560 /dev/__properties__/property_info
-70ebf5f000-70ebf60000 r--p 00000000 00:00 0 [anon:linker_alloc]
-70ebf60000-70ebf61000 rw-p 00000000 00:00 0 [anon:linker_alloc_vector]
-70ebf61000-70ebf62000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebf62000-70ebf63000 rw-p 00000000 00:00 0 [anon:arc4random data]
-70ebf63000-70ebf64000 rw-p 00000000 00:00 0 [anon:linker_alloc_small_objects]
-70ebf64000-70ebf65000 r--p 00000000 00:00 0 [anon:atexit handlers]
-70ebf65000-70ebf66000 ---p 00000000 00:00 0 [anon:thread signal stack guard]
-70ebf66000-70ebf6a000 rw-p 00000000 00:00 0 [anon:thread signal stack]
-70ebf6a000-70ebf6b000 rw-p 00000000 00:00 0 [anon:arc4random data]
-70ebf6b000-70ebf6c000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70ebf6c000-70ebf6f000 rw-p 00000000 00:00 0 [anon:bionic TLS]
-70ebf6f000-70ebf70000 ---p 00000000 00:00 0 [anon:bionic TLS guard]
-70ebf70000-70ebf71000 r--p 00000000 00:00 0 [vvar]
-70ebf71000-70ebf72000 r-xp 00000000 00:00 0 [vdso]
-70ebf72000-70ebf7d000 r--p 00135000 fc:00 3184 /system/bin/linker64
-70ebf7d000-70ebf7e000 rw-p 00140000 fc:00 3184 /system/bin/linker64
-70ebf7e000-70ebf81000 rw-p 00000000 00:00 0
-70ebf81000-70ebf82000 r--p 00000000 00:00 0
-70ebf82000-70ebf89000 rw-p 00000000 00:00 0
-7fc7df1000-7fc7df2000 ---p 00000000 00:00 0
-7fc7df2000-7fc85f1000 rw-p 00000000 00:00 0 [stack]
diff --git a/libsparse/Android.bp b/libsparse/Android.bp
index 135904b..bf06bbc 100644
--- a/libsparse/Android.bp
+++ b/libsparse/Android.bp
@@ -6,6 +6,7 @@
ramdisk_available: true,
recovery_available: true,
unique_host_soname: true,
+ vendor_available: true,
srcs: [
"backed_block.cpp",
"output_file.cpp",
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
new file mode 100644
index 0000000..a8b4a4f
--- /dev/null
+++ b/libstats/pull/Android.bp
@@ -0,0 +1,110 @@
+//
+// 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.
+//
+
+// ==========================================================
+// Native library to register a pull atom callback with statsd
+// ==========================================================
+cc_defaults {
+ name: "libstatspull_defaults",
+ srcs: [
+ "stats_pull_atom_callback.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ export_include_dirs: ["include"],
+ shared_libs: [
+ "libbinder_ndk",
+ "liblog",
+ "libstatssocket",
+ ],
+ static_libs: [
+ "libutils",
+ "statsd-aidl-ndk_platform",
+ ],
+}
+cc_library_shared {
+ name: "libstatspull",
+ defaults: [
+ "libstatspull_defaults"
+ ],
+ // enumerate stable entry points for APEX use
+ stubs: {
+ symbol_file: "libstatspull.map.txt",
+ versions: [
+ "30",
+ ],
+ },
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
+
+ stl: "libc++_static",
+
+ // TODO(b/151102177): Enable it when the build error is fixed.
+ header_abi_checker: {
+ enabled: false,
+ },
+}
+
+// ONLY USE IN TESTS.
+cc_library_static {
+ name: "libstatspull_private",
+ defaults: [
+ "libstatspull_defaults",
+ ],
+ visibility: [
+ "//frameworks/base/apex/statsd/tests/libstatspull",
+ ],
+}
+
+// Note: These unit tests only test PullAtomMetadata.
+// For full E2E tests of libstatspull, use LibStatsPullTests
+cc_test {
+ name: "libstatspull_test",
+ srcs: [
+ "tests/pull_atom_metadata_test.cpp",
+ ],
+ shared_libs: [
+ "libstatspull",
+ "libstatssocket",
+ ],
+ test_suites: ["general-tests", "mts"],
+ test_config: "libstatspull_test.xml",
+
+ //TODO(b/153588990): Remove when the build system properly separates
+ //32bit and 64bit architectures.
+ compile_multilib: "both",
+ multilib: {
+ lib64: {
+ suffix: "64",
+ },
+ lib32: {
+ suffix: "32",
+ },
+ },
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wno-unused-function",
+ "-Wno-unused-parameter",
+ ],
+ require_root: true,
+}
diff --git a/libstats/pull/OWNERS b/libstats/pull/OWNERS
new file mode 100644
index 0000000..7855774
--- /dev/null
+++ b/libstats/pull/OWNERS
@@ -0,0 +1,7 @@
+joeo@google.com
+muhammadq@google.com
+ruchirr@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
+yro@google.com
diff --git a/libstats/pull/TEST_MAPPING b/libstats/pull/TEST_MAPPING
new file mode 100644
index 0000000..76f4f02
--- /dev/null
+++ b/libstats/pull/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit" : [
+ {
+ "name" : "libstatspull_test"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libstats/pull/include/stats_pull_atom_callback.h b/libstats/pull/include/stats_pull_atom_callback.h
new file mode 100644
index 0000000..17df584
--- /dev/null
+++ b/libstats/pull/include/stats_pull_atom_callback.h
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <stats_event.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Opaque struct representing the metadata for registering an AStatsManager_PullAtomCallback.
+ */
+struct AStatsManager_PullAtomMetadata;
+typedef struct AStatsManager_PullAtomMetadata AStatsManager_PullAtomMetadata;
+
+/**
+ * Allocate and initialize new PullAtomMetadata.
+ *
+ * Must call AStatsManager_PullAtomMetadata_release to free the memory.
+ */
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain();
+
+/**
+ * Frees the memory held by this PullAtomMetadata
+ *
+ * After calling this, the PullAtomMetadata must not be used or modified in any way.
+ */
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Set the cool down time of the pull in milliseconds. If two successive pulls are issued
+ * within the cool down, a cached version of the first will be used for the second. The minimum
+ * allowed cool down is one second.
+ */
+void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
+ int64_t cool_down_millis);
+
+/**
+ * Get the cool down time of the pull in milliseconds.
+ */
+int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Set the maximum time the pull can take in milliseconds.
+ * The maximum allowed timeout is 10 seconds.
+ */
+void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
+ int64_t timeout_millis);
+
+/**
+ * Get the maximum time the pull can take in milliseconds.
+ */
+int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Set the additive fields of this pulled atom.
+ *
+ * This is only applicable for atoms which have a uid field. When tasks are run in
+ * isolated processes, the data will be attributed to the host uid. Additive fields
+ * will be combined when the non-additive fields are the same.
+ */
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int32_t* additive_fields, int32_t num_fields);
+
+/**
+ * Get the number of additive fields for this pulled atom. This is intended to be called before
+ * AStatsManager_PullAtomMetadata_getAdditiveFields to determine the size of the array.
+ */
+int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
+ AStatsManager_PullAtomMetadata* metadata);
+
+/**
+ * Get the additive fields of this pulled atom.
+ *
+ * \param fields an output parameter containing the additive fields for this PullAtomMetadata.
+ * Fields is an array and it is assumed that it is at least as large as the number of
+ * additive fields, which can be obtained by calling
+ * AStatsManager_PullAtomMetadata_getNumAdditiveFields.
+ */
+void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int32_t* fields);
+
+/**
+ * Return codes for the result of a pull.
+ */
+typedef int32_t AStatsManager_PullAtomCallbackReturn;
+enum {
+ // Value indicating that this pull was successful and that the result should be used.
+ AStatsManager_PULL_SUCCESS = 0,
+ // Value indicating that this pull was unsuccessful and that the result should not be used.
+ AStatsManager_PULL_SKIP = 1,
+};
+
+/**
+ * Opaque struct representing a list of AStatsEvent objects.
+ */
+struct AStatsEventList;
+typedef struct AStatsEventList AStatsEventList;
+
+/**
+ * Appends and returns an AStatsEvent to the end of the AStatsEventList.
+ *
+ * If an AStatsEvent is obtained in this manner, the memory is internally managed and
+ * AStatsEvent_release does not need to be called. The lifetime of the AStatsEvent is that of the
+ * AStatsEventList.
+ *
+ * The AStatsEvent does still need to be built by calling AStatsEvent_build.
+ */
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data);
+
+/**
+ * Callback interface for pulling atoms requested by the stats service.
+ *
+ * \param atom_tag the tag of the atom to pull.
+ * \param data an output parameter in which the caller should fill the results of the pull. This
+ * param cannot be NULL and it's lifetime is as long as the execution of the callback.
+ * It must not be accessed or modified after returning from the callback.
+ * \param cookie the opaque pointer passed in AStatsManager_registerPullAtomCallback.
+ * \return AStatsManager_PULL_SUCCESS if the pull was successful, or AStatsManager_PULL_SKIP if not.
+ */
+typedef AStatsManager_PullAtomCallbackReturn (*AStatsManager_PullAtomCallback)(
+ int32_t atom_tag, AStatsEventList* data, void* cookie);
+/**
+ * Sets a callback for an atom when that atom is to be pulled. The stats service will
+ * invoke the callback when the stats service determines that this atom needs to be
+ * pulled.
+ *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
+ * \param atom_tag The tag of the atom for this pull atom callback.
+ * \param metadata Optional metadata specifying the timeout, cool down time, and
+ * additive fields for mapping isolated to host uids.
+ * This param is nullable, in which case defaults will be used.
+ * \param callback The callback to be invoked when the stats service pulls the atom.
+ * \param cookie A pointer that will be passed back to the callback.
+ * It has no meaning to statsd.
+ */
+void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
+ AStatsManager_PullAtomCallback callback, void* cookie);
+
+/**
+ * Clears a callback for an atom when that atom is to be pulled. Note that any ongoing
+ * pulls will still occur.
+ *
+ * Requires the REGISTER_STATS_PULL_ATOM permission.
+ *
+ * \param atomTag The tag of the atom of which to unregister
+ */
+void AStatsManager_clearPullAtomCallback(int32_t atom_tag);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/libstats/pull/libstatspull.map.txt b/libstats/pull/libstatspull.map.txt
new file mode 100644
index 0000000..e0e851a
--- /dev/null
+++ b/libstats/pull/libstatspull.map.txt
@@ -0,0 +1,17 @@
+LIBSTATSPULL {
+ global:
+ AStatsManager_PullAtomMetadata_obtain; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_release; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setCoolDownMillis; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_getCoolDownMillis; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setTimeoutMillis; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_getTimeoutMillis; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_setAdditiveFields; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_getNumAdditiveFields; # apex # introduced=30
+ AStatsManager_PullAtomMetadata_getAdditiveFields; # apex # introduced=30
+ AStatsEventList_addStatsEvent; # apex # introduced=30
+ AStatsManager_setPullAtomCallback; # apex # introduced=30
+ AStatsManager_clearPullAtomCallback; # apex # introduced=30
+ local:
+ *;
+};
diff --git a/libstats/pull/libstatspull_test.xml b/libstats/pull/libstatspull_test.xml
new file mode 100644
index 0000000..233fc1f
--- /dev/null
+++ b/libstats/pull/libstatspull_test.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="Runs libstatspull_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <option name="test-suite-tag" value="mts" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libstatspull_test->/data/local/tmp/libstatspull_test" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libstatspull_test" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+ </object>
+</configuration>
diff --git a/libstats/pull/stats_pull_atom_callback.cpp b/libstats/pull/stats_pull_atom_callback.cpp
new file mode 100644
index 0000000..478cae7
--- /dev/null
+++ b/libstats/pull/stats_pull_atom_callback.cpp
@@ -0,0 +1,260 @@
+/*
+ * 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 <map>
+#include <thread>
+#include <vector>
+
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+
+#include <aidl/android/os/BnPullAtomCallback.h>
+#include <aidl/android/os/IPullAtomResultReceiver.h>
+#include <aidl/android/os/IStatsd.h>
+#include <aidl/android/util/StatsEventParcel.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+
+using Status = ::ndk::ScopedAStatus;
+using aidl::android::os::BnPullAtomCallback;
+using aidl::android::os::IPullAtomResultReceiver;
+using aidl::android::os::IStatsd;
+using aidl::android::util::StatsEventParcel;
+using ::ndk::SharedRefBase;
+
+struct AStatsEventList {
+ std::vector<AStatsEvent*> data;
+};
+
+AStatsEvent* AStatsEventList_addStatsEvent(AStatsEventList* pull_data) {
+ AStatsEvent* event = AStatsEvent_obtain();
+ pull_data->data.push_back(event);
+ return event;
+}
+
+static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second.
+static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds.
+
+struct AStatsManager_PullAtomMetadata {
+ int64_t cool_down_millis;
+ int64_t timeout_millis;
+ std::vector<int32_t> additive_fields;
+};
+
+AStatsManager_PullAtomMetadata* AStatsManager_PullAtomMetadata_obtain() {
+ AStatsManager_PullAtomMetadata* metadata = new AStatsManager_PullAtomMetadata();
+ metadata->cool_down_millis = DEFAULT_COOL_DOWN_MILLIS;
+ metadata->timeout_millis = DEFAULT_TIMEOUT_MILLIS;
+ metadata->additive_fields = std::vector<int32_t>();
+ return metadata;
+}
+
+void AStatsManager_PullAtomMetadata_release(AStatsManager_PullAtomMetadata* metadata) {
+ delete metadata;
+}
+
+void AStatsManager_PullAtomMetadata_setCoolDownMillis(AStatsManager_PullAtomMetadata* metadata,
+ int64_t cool_down_millis) {
+ metadata->cool_down_millis = cool_down_millis;
+}
+
+int64_t AStatsManager_PullAtomMetadata_getCoolDownMillis(AStatsManager_PullAtomMetadata* metadata) {
+ return metadata->cool_down_millis;
+}
+
+void AStatsManager_PullAtomMetadata_setTimeoutMillis(AStatsManager_PullAtomMetadata* metadata,
+ int64_t timeout_millis) {
+ metadata->timeout_millis = timeout_millis;
+}
+
+int64_t AStatsManager_PullAtomMetadata_getTimeoutMillis(AStatsManager_PullAtomMetadata* metadata) {
+ return metadata->timeout_millis;
+}
+
+void AStatsManager_PullAtomMetadata_setAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int32_t* additive_fields,
+ int32_t num_fields) {
+ metadata->additive_fields.assign(additive_fields, additive_fields + num_fields);
+}
+
+int32_t AStatsManager_PullAtomMetadata_getNumAdditiveFields(
+ AStatsManager_PullAtomMetadata* metadata) {
+ return metadata->additive_fields.size();
+}
+
+void AStatsManager_PullAtomMetadata_getAdditiveFields(AStatsManager_PullAtomMetadata* metadata,
+ int32_t* fields) {
+ std::copy(metadata->additive_fields.begin(), metadata->additive_fields.end(), fields);
+}
+
+class StatsPullAtomCallbackInternal : public BnPullAtomCallback {
+ public:
+ StatsPullAtomCallbackInternal(const AStatsManager_PullAtomCallback callback, void* cookie,
+ const int64_t coolDownMillis, const int64_t timeoutMillis,
+ const std::vector<int32_t> additiveFields)
+ : mCallback(callback),
+ mCookie(cookie),
+ mCoolDownMillis(coolDownMillis),
+ mTimeoutMillis(timeoutMillis),
+ mAdditiveFields(additiveFields) {}
+
+ Status onPullAtom(int32_t atomTag,
+ const std::shared_ptr<IPullAtomResultReceiver>& resultReceiver) override {
+ AStatsEventList statsEventList;
+ int successInt = mCallback(atomTag, &statsEventList, mCookie);
+ bool success = successInt == AStatsManager_PULL_SUCCESS;
+
+ // Convert stats_events into StatsEventParcels.
+ std::vector<StatsEventParcel> parcels;
+ for (int i = 0; i < statsEventList.data.size(); i++) {
+ size_t size;
+ uint8_t* buffer = AStatsEvent_getBuffer(statsEventList.data[i], &size);
+
+ StatsEventParcel p;
+ // vector.assign() creates a copy, but this is inevitable unless
+ // stats_event.h/c uses a vector as opposed to a buffer.
+ p.buffer.assign(buffer, buffer + size);
+ parcels.push_back(std::move(p));
+ }
+
+ Status status = resultReceiver->pullFinished(atomTag, success, parcels);
+ if (!status.isOk()) {
+ std::vector<StatsEventParcel> emptyParcels;
+ resultReceiver->pullFinished(atomTag, /*success=*/false, emptyParcels);
+ }
+ for (int i = 0; i < statsEventList.data.size(); i++) {
+ AStatsEvent_release(statsEventList.data[i]);
+ }
+ return Status::ok();
+ }
+
+ int64_t getCoolDownMillis() const { return mCoolDownMillis; }
+ int64_t getTimeoutMillis() const { return mTimeoutMillis; }
+ const std::vector<int32_t>& getAdditiveFields() const { return mAdditiveFields; }
+
+ private:
+ const AStatsManager_PullAtomCallback mCallback;
+ void* mCookie;
+ const int64_t mCoolDownMillis;
+ const int64_t mTimeoutMillis;
+ const std::vector<int32_t> mAdditiveFields;
+};
+
+static std::mutex pullAtomMutex;
+static std::shared_ptr<IStatsd> sStatsd = nullptr;
+
+static std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> mPullers;
+static std::shared_ptr<IStatsd> getStatsService();
+
+static void binderDied(void* /*cookie*/) {
+ {
+ std::lock_guard<std::mutex> lock(pullAtomMutex);
+ sStatsd = nullptr;
+ }
+
+ std::shared_ptr<IStatsd> statsService = getStatsService();
+ if (statsService == nullptr) {
+ return;
+ }
+
+ // Since we do not want to make an IPC with the lock held, we first create a
+ // copy of the data with the lock held before iterating through the map.
+ std::map<int32_t, std::shared_ptr<StatsPullAtomCallbackInternal>> pullersCopy;
+ {
+ std::lock_guard<std::mutex> lock(pullAtomMutex);
+ pullersCopy = mPullers;
+ }
+ for (const auto& it : pullersCopy) {
+ statsService->registerNativePullAtomCallback(it.first, it.second->getCoolDownMillis(),
+ it.second->getTimeoutMillis(),
+ it.second->getAdditiveFields(), it.second);
+ }
+}
+
+static ::ndk::ScopedAIBinder_DeathRecipient sDeathRecipient(
+ AIBinder_DeathRecipient_new(binderDied));
+
+static std::shared_ptr<IStatsd> getStatsService() {
+ std::lock_guard<std::mutex> lock(pullAtomMutex);
+ if (!sStatsd) {
+ // Fetch statsd
+ ::ndk::SpAIBinder binder(AServiceManager_getService("stats"));
+ sStatsd = IStatsd::fromBinder(binder);
+ if (sStatsd) {
+ AIBinder_linkToDeath(binder.get(), sDeathRecipient.get(), /*cookie=*/nullptr);
+ }
+ }
+ return sStatsd;
+}
+
+void registerStatsPullAtomCallbackBlocking(int32_t atomTag,
+ std::shared_ptr<StatsPullAtomCallbackInternal> cb) {
+ const std::shared_ptr<IStatsd> statsService = getStatsService();
+ if (statsService == nullptr) {
+ // Statsd not available
+ return;
+ }
+
+ statsService->registerNativePullAtomCallback(
+ atomTag, cb->getCoolDownMillis(), cb->getTimeoutMillis(), cb->getAdditiveFields(), cb);
+}
+
+void unregisterStatsPullAtomCallbackBlocking(int32_t atomTag) {
+ const std::shared_ptr<IStatsd> statsService = getStatsService();
+ if (statsService == nullptr) {
+ // Statsd not available
+ return;
+ }
+
+ statsService->unregisterNativePullAtomCallback(atomTag);
+}
+
+void AStatsManager_setPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata* metadata,
+ AStatsManager_PullAtomCallback callback, void* cookie) {
+ int64_t coolDownMillis =
+ metadata == nullptr ? DEFAULT_COOL_DOWN_MILLIS : metadata->cool_down_millis;
+ int64_t timeoutMillis = metadata == nullptr ? DEFAULT_TIMEOUT_MILLIS : metadata->timeout_millis;
+
+ std::vector<int32_t> additiveFields;
+ if (metadata != nullptr) {
+ additiveFields = metadata->additive_fields;
+ }
+
+ std::shared_ptr<StatsPullAtomCallbackInternal> callbackBinder =
+ SharedRefBase::make<StatsPullAtomCallbackInternal>(callback, cookie, coolDownMillis,
+ timeoutMillis, additiveFields);
+
+ {
+ std::lock_guard<std::mutex> lg(pullAtomMutex);
+ // Always add to the map. If statsd is dead, we will add them when it comes back.
+ mPullers[atom_tag] = callbackBinder;
+ }
+
+ std::thread registerThread(registerStatsPullAtomCallbackBlocking, atom_tag, callbackBinder);
+ registerThread.detach();
+}
+
+void AStatsManager_clearPullAtomCallback(int32_t atom_tag) {
+ {
+ std::lock_guard<std::mutex> lg(pullAtomMutex);
+ // Always remove the puller from our map.
+ // If statsd is down, we will not register it when it comes back.
+ mPullers.erase(atom_tag);
+ }
+ std::thread unregisterThread(unregisterStatsPullAtomCallbackBlocking, atom_tag);
+ unregisterThread.detach();
+}
diff --git a/libstats/pull/tests/pull_atom_metadata_test.cpp b/libstats/pull/tests/pull_atom_metadata_test.cpp
new file mode 100644
index 0000000..abc8e47
--- /dev/null
+++ b/libstats/pull/tests/pull_atom_metadata_test.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020, 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 <gtest/gtest.h>
+
+#include <stats_pull_atom_callback.h>
+
+namespace {
+
+static const int64_t DEFAULT_COOL_DOWN_MILLIS = 1000LL; // 1 second.
+static const int64_t DEFAULT_TIMEOUT_MILLIS = 2000LL; // 2 seconds.
+
+} // anonymous namespace
+
+TEST(AStatsManager_PullAtomMetadataTest, TestEmpty) {
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetTimeoutMillis) {
+ int64_t timeoutMillis = 500;
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, timeoutMillis);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), timeoutMillis);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetCoolDownMillis) {
+ int64_t coolDownMillis = 10000;
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, coolDownMillis);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), coolDownMillis);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), 0);
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetAdditiveFields) {
+ const int numFields = 3;
+ int inputFields[numFields] = {2, 4, 6};
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ AStatsManager_PullAtomMetadata_setAdditiveFields(metadata, inputFields, numFields);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), DEFAULT_COOL_DOWN_MILLIS);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), DEFAULT_TIMEOUT_MILLIS);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), numFields);
+ int outputFields[numFields];
+ AStatsManager_PullAtomMetadata_getAdditiveFields(metadata, outputFields);
+ for (int i = 0; i < numFields; i++) {
+ EXPECT_EQ(inputFields[i], outputFields[i]);
+ }
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+TEST(AStatsManager_PullAtomMetadataTest, TestSetAllElements) {
+ int64_t timeoutMillis = 500;
+ int64_t coolDownMillis = 10000;
+ const int numFields = 3;
+ int inputFields[numFields] = {2, 4, 6};
+
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ AStatsManager_PullAtomMetadata_setTimeoutMillis(metadata, timeoutMillis);
+ AStatsManager_PullAtomMetadata_setCoolDownMillis(metadata, coolDownMillis);
+ AStatsManager_PullAtomMetadata_setAdditiveFields(metadata, inputFields, numFields);
+
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getCoolDownMillis(metadata), coolDownMillis);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getTimeoutMillis(metadata), timeoutMillis);
+ EXPECT_EQ(AStatsManager_PullAtomMetadata_getNumAdditiveFields(metadata), numFields);
+ int outputFields[numFields];
+ AStatsManager_PullAtomMetadata_getAdditiveFields(metadata, outputFields);
+ for (int i = 0; i < numFields; i++) {
+ EXPECT_EQ(inputFields[i], outputFields[i]);
+ }
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
diff --git a/libstats/push_compat/Android.bp b/libstats/push_compat/Android.bp
index cbc65ff..43ae69d 100644
--- a/libstats/push_compat/Android.bp
+++ b/libstats/push_compat/Android.bp
@@ -32,13 +32,15 @@
"-DWRITE_TO_STATSD=1",
"-DWRITE_TO_LOGD=0",
],
- header_libs: ["libstatssocket_headers"],
+ header_libs: [
+ "libcutils_headers",
+ "libstatssocket_headers",
+ ],
static_libs: [
"libbase",
],
shared_libs: [
"liblog",
- "libutils",
],
}
@@ -46,6 +48,9 @@
name: "libstatspush_compat",
defaults: ["libstatspush_compat_defaults"],
export_include_dirs: ["include"],
+ export_header_lib_headers: [
+ "libstatssocket_headers",
+ ],
static_libs: ["libgtest_prod"],
apex_available: ["com.android.resolv"],
min_sdk_version: "29",
diff --git a/libstats/push_compat/StatsEventCompat.cpp b/libstats/push_compat/StatsEventCompat.cpp
index edfa070..12a5dd4 100644
--- a/libstats/push_compat/StatsEventCompat.cpp
+++ b/libstats/push_compat/StatsEventCompat.cpp
@@ -15,41 +15,42 @@
*/
#include "include/StatsEventCompat.h"
+
+#include <chrono>
+
+#include <android-base/chrono_utils.h>
#include <android-base/properties.h>
#include <android/api-level.h>
#include <android/log.h>
#include <dlfcn.h>
-#include <utils/SystemClock.h>
+using android::base::boot_clock;
using android::base::GetProperty;
const static int kStatsEventTag = 1937006964;
-
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
const bool StatsEventCompat::mPlatformAtLeastR =
- GetProperty("ro.build.version.codename", "") == "R" ||
- android_get_device_api_level() > __ANDROID_API_Q__;
+ android_get_device_api_level() >= __ANDROID_API_R__;
-// definitions of static class variables
+// initializations of static class variables
bool StatsEventCompat::mAttemptedLoad = false;
-struct stats_event_api_table* StatsEventCompat::mStatsEventApi = nullptr;
std::mutex StatsEventCompat::mLoadLock;
+AStatsEventApi StatsEventCompat::mAStatsEventApi;
+
+static int64_t elapsedRealtimeNano() {
+ return std::chrono::time_point_cast<std::chrono::nanoseconds>(boot_clock::now())
+ .time_since_epoch()
+ .count();
+}
StatsEventCompat::StatsEventCompat() : mEventQ(kStatsEventTag) {
// guard loading because StatsEventCompat might be called from multithreaded
// environment
{
std::lock_guard<std::mutex> lg(mLoadLock);
- if (!mAttemptedLoad) {
+ if (!mAttemptedLoad && mPlatformAtLeastR) {
void* handle = dlopen("libstatssocket.so", RTLD_NOW);
if (handle) {
- mStatsEventApi = (struct stats_event_api_table*)dlsym(handle, "table");
+ initializeApiTableLocked(handle);
} else {
ALOGE("dlopen failed: %s\n", dlerror());
}
@@ -57,61 +58,93 @@
mAttemptedLoad = true;
}
- if (mStatsEventApi) {
- mEventR = mStatsEventApi->obtain();
- } else if (!mPlatformAtLeastR) {
- mEventQ << android::elapsedRealtimeNano();
+ if (useRSchema()) {
+ mEventR = mAStatsEventApi.obtain();
+ } else if (useQSchema()) {
+ mEventQ << elapsedRealtimeNano();
}
}
StatsEventCompat::~StatsEventCompat() {
- if (mStatsEventApi) mStatsEventApi->release(mEventR);
+ if (useRSchema()) mAStatsEventApi.release(mEventR);
+}
+
+// Populates the AStatsEventApi struct by calling dlsym to find the address of
+// each API function.
+void StatsEventCompat::initializeApiTableLocked(void* handle) {
+ mAStatsEventApi.obtain = (AStatsEvent* (*)())dlsym(handle, "AStatsEvent_obtain");
+ mAStatsEventApi.build = (void (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_build");
+ mAStatsEventApi.write = (int (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_write");
+ mAStatsEventApi.release = (void (*)(AStatsEvent*))dlsym(handle, "AStatsEvent_release");
+ mAStatsEventApi.setAtomId =
+ (void (*)(AStatsEvent*, uint32_t))dlsym(handle, "AStatsEvent_setAtomId");
+ mAStatsEventApi.writeInt32 =
+ (void (*)(AStatsEvent*, int32_t))dlsym(handle, "AStatsEvent_writeInt32");
+ mAStatsEventApi.writeInt64 =
+ (void (*)(AStatsEvent*, int64_t))dlsym(handle, "AStatsEvent_writeInt64");
+ mAStatsEventApi.writeFloat =
+ (void (*)(AStatsEvent*, float))dlsym(handle, "AStatsEvent_writeFloat");
+ mAStatsEventApi.writeBool =
+ (void (*)(AStatsEvent*, bool))dlsym(handle, "AStatsEvent_writeBool");
+ mAStatsEventApi.writeByteArray = (void (*)(AStatsEvent*, const uint8_t*, size_t))dlsym(
+ handle, "AStatsEvent_writeByteArray");
+ mAStatsEventApi.writeString =
+ (void (*)(AStatsEvent*, const char*))dlsym(handle, "AStatsEvent_writeString");
+ mAStatsEventApi.writeAttributionChain =
+ (void (*)(AStatsEvent*, const uint32_t*, const char* const*, uint8_t))dlsym(
+ handle, "AStatsEvent_writeAttributionChain");
+ mAStatsEventApi.addBoolAnnotation =
+ (void (*)(AStatsEvent*, uint8_t, bool))dlsym(handle, "AStatsEvent_addBoolAnnotation");
+ mAStatsEventApi.addInt32Annotation = (void (*)(AStatsEvent*, uint8_t, int32_t))dlsym(
+ handle, "AStatsEvent_addInt32Annotation");
+
+ mAStatsEventApi.initialized = true;
}
void StatsEventCompat::setAtomId(int32_t atomId) {
- if (mStatsEventApi) {
- mStatsEventApi->set_atom_id(mEventR, (uint32_t)atomId);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.setAtomId(mEventR, (uint32_t)atomId);
+ } else if (useQSchema()) {
mEventQ << atomId;
}
}
void StatsEventCompat::writeInt32(int32_t value) {
- if (mStatsEventApi) {
- mStatsEventApi->write_int32(mEventR, value);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.writeInt32(mEventR, value);
+ } else if (useQSchema()) {
mEventQ << value;
}
}
void StatsEventCompat::writeInt64(int64_t value) {
- if (mStatsEventApi) {
- mStatsEventApi->write_int64(mEventR, value);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.writeInt64(mEventR, value);
+ } else if (useQSchema()) {
mEventQ << value;
}
}
void StatsEventCompat::writeFloat(float value) {
- if (mStatsEventApi) {
- mStatsEventApi->write_float(mEventR, value);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.writeFloat(mEventR, value);
+ } else if (useQSchema()) {
mEventQ << value;
}
}
void StatsEventCompat::writeBool(bool value) {
- if (mStatsEventApi) {
- mStatsEventApi->write_bool(mEventR, value);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.writeBool(mEventR, value);
+ } else if (useQSchema()) {
mEventQ << value;
}
}
void StatsEventCompat::writeByteArray(const char* buffer, size_t length) {
- if (mStatsEventApi) {
- mStatsEventApi->write_byte_array(mEventR, (const uint8_t*)buffer, length);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.writeByteArray(mEventR, reinterpret_cast<const uint8_t*>(buffer), length);
+ } else if (useQSchema()) {
mEventQ.AppendCharArray(buffer, length);
}
}
@@ -119,19 +152,19 @@
void StatsEventCompat::writeString(const char* value) {
if (value == nullptr) value = "";
- if (mStatsEventApi) {
- mStatsEventApi->write_string8(mEventR, value);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.writeString(mEventR, value);
+ } else if (useQSchema()) {
mEventQ << value;
}
}
void StatsEventCompat::writeAttributionChain(const int32_t* uids, size_t numUids,
const vector<const char*>& tags) {
- if (mStatsEventApi) {
- mStatsEventApi->write_attribution_chain(mEventR, (const uint32_t*)uids, tags.data(),
- (uint8_t)numUids);
- } else if (!mPlatformAtLeastR) {
+ if (useRSchema()) {
+ mAStatsEventApi.writeAttributionChain(mEventR, (const uint32_t*)uids, tags.data(),
+ (uint8_t)numUids);
+ } else if (useQSchema()) {
mEventQ.begin();
for (size_t i = 0; i < numUids; i++) {
mEventQ.begin();
@@ -148,26 +181,8 @@
const map<int, int64_t>& int64Map,
const map<int, const char*>& stringMap,
const map<int, float>& floatMap) {
- if (mStatsEventApi) {
- vector<struct key_value_pair> pairs;
-
- for (const auto& it : int32Map) {
- pairs.push_back({.key = it.first, .valueType = INT32_TYPE, .int32Value = it.second});
- }
- for (const auto& it : int64Map) {
- pairs.push_back({.key = it.first, .valueType = INT64_TYPE, .int64Value = it.second});
- }
- for (const auto& it : stringMap) {
- pairs.push_back({.key = it.first, .valueType = STRING_TYPE, .stringValue = it.second});
- }
- for (const auto& it : floatMap) {
- pairs.push_back({.key = it.first, .valueType = FLOAT_TYPE, .floatValue = it.second});
- }
-
- mStatsEventApi->write_key_value_pairs(mEventR, pairs.data(), (uint8_t)pairs.size());
- }
-
- else if (!mPlatformAtLeastR) {
+ // AStatsEvent does not support key value pairs.
+ if (useQSchema()) {
mEventQ.begin();
writeKeyValuePairMap(int32Map);
writeKeyValuePairMap(int64Map);
@@ -194,28 +209,35 @@
template void StatsEventCompat::writeKeyValuePairMap<const char*>(const map<int, const char*>&);
void StatsEventCompat::addBoolAnnotation(uint8_t annotationId, bool value) {
- if (mStatsEventApi) mStatsEventApi->add_bool_annotation(mEventR, annotationId, value);
+ if (useRSchema()) {
+ mAStatsEventApi.addBoolAnnotation(mEventR, annotationId, value);
+ }
// Don't do anything if on Q.
}
void StatsEventCompat::addInt32Annotation(uint8_t annotationId, int32_t value) {
- if (mStatsEventApi) mStatsEventApi->add_int32_annotation(mEventR, annotationId, value);
+ if (useRSchema()) {
+ mAStatsEventApi.addInt32Annotation(mEventR, annotationId, value);
+ }
// Don't do anything if on Q.
}
int StatsEventCompat::writeToSocket() {
- if (mStatsEventApi) {
- mStatsEventApi->build(mEventR);
- return mStatsEventApi->write(mEventR);
+ if (useRSchema()) {
+ return mAStatsEventApi.write(mEventR);
}
- if (!mPlatformAtLeastR) return mEventQ.write(LOG_ID_STATS);
+ if (useQSchema()) return mEventQ.write(LOG_ID_STATS);
- // We reach here only if we're on R, but libstatspush_compat was unable to
+ // We reach here only if we're on R, but libstatssocket was unable to
// be loaded using dlopen.
return -ENOLINK;
}
-bool StatsEventCompat::usesNewSchema() {
- return mStatsEventApi != nullptr;
+bool StatsEventCompat::useRSchema() {
+ return mPlatformAtLeastR && mAStatsEventApi.initialized;
+}
+
+bool StatsEventCompat::useQSchema() {
+ return !mPlatformAtLeastR;
}
diff --git a/libstats/push_compat/include/StatsEventCompat.h b/libstats/push_compat/include/StatsEventCompat.h
index a8cde68..00bf48b 100644
--- a/libstats/push_compat/include/StatsEventCompat.h
+++ b/libstats/push_compat/include/StatsEventCompat.h
@@ -26,6 +26,26 @@
using std::map;
using std::vector;
+struct AStatsEventApi {
+ // Indicates whether the below function pointers have been set using dlsym.
+ bool initialized = false;
+
+ AStatsEvent* (*obtain)(void);
+ void (*build)(AStatsEvent*);
+ int (*write)(AStatsEvent*);
+ void (*release)(AStatsEvent*);
+ void (*setAtomId)(AStatsEvent*, uint32_t);
+ void (*writeInt32)(AStatsEvent*, int32_t);
+ void (*writeInt64)(AStatsEvent*, int64_t);
+ void (*writeFloat)(AStatsEvent*, float);
+ void (*writeBool)(AStatsEvent*, bool);
+ void (*writeByteArray)(AStatsEvent*, const uint8_t*, size_t);
+ void (*writeString)(AStatsEvent*, const char*);
+ void (*writeAttributionChain)(AStatsEvent*, const uint32_t*, const char* const*, uint8_t);
+ void (*addBoolAnnotation)(AStatsEvent*, uint8_t, bool);
+ void (*addInt32Annotation)(AStatsEvent*, uint8_t, int32_t);
+};
+
class StatsEventCompat {
public:
StatsEventCompat();
@@ -57,15 +77,18 @@
const static bool mPlatformAtLeastR;
static bool mAttemptedLoad;
static std::mutex mLoadLock;
- static struct stats_event_api_table* mStatsEventApi;
+ static AStatsEventApi mAStatsEventApi;
// non-static member variables
- struct stats_event* mEventR = nullptr;
+ AStatsEvent* mEventR = nullptr;
stats_event_list mEventQ;
template <class T>
void writeKeyValuePairMap(const map<int, T>& keyValuePairMap);
- bool usesNewSchema();
+ void initializeApiTableLocked(void* handle);
+ bool useRSchema();
+ bool useQSchema();
+
FRIEND_TEST(StatsEventCompatTest, TestDynamicLoading);
};
diff --git a/libstats/push_compat/tests/StatsEventCompat_test.cpp b/libstats/push_compat/tests/StatsEventCompat_test.cpp
index 2be24ec..2a70db5 100644
--- a/libstats/push_compat/tests/StatsEventCompat_test.cpp
+++ b/libstats/push_compat/tests/StatsEventCompat_test.cpp
@@ -21,18 +21,9 @@
using android::base::GetProperty;
-/* Checking ro.build.version.release is fragile, as the release field is
- * an opaque string without structural guarantees. However, testing confirms
- * that on Q devices, the property is "10," and on R, it is "R." Until
- * android_get_device_api_level() is updated, this is the only solution.
- *
- *
- * TODO(b/146019024): migrate to android_get_device_api_level()
- */
-const static bool mPlatformAtLeastR = GetProperty("ro.build.version.release", "") == "R" ||
- android_get_device_api_level() > __ANDROID_API_Q__;
+const static bool mPlatformAtLeastR = android_get_device_api_level() >= __ANDROID_API_R__;
TEST(StatsEventCompatTest, TestDynamicLoading) {
StatsEventCompat event;
- EXPECT_EQ(mPlatformAtLeastR, event.usesNewSchema());
+ EXPECT_EQ(mPlatformAtLeastR, event.useRSchema());
}
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index 6882ab2..89cdfe5 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -17,37 +17,69 @@
// =========================================================================
// Native library to write stats log to statsd socket on Android R and later
// =========================================================================
-cc_library {
- name: "libstatssocket",
+cc_defaults {
+ name: "libstatssocket_defaults",
srcs: [
"stats_buffer_writer.c",
"stats_event.c",
- // TODO(b/145573568): Remove stats_event_list once stats_event
- // migration is complete.
- "stats_event_list.c",
+ "stats_socket.c",
"statsd_writer.c",
],
- host_supported: true,
+ export_include_dirs: ["include"],
+ static_libs: [
+ "libcutils", // does not expose a stable C API
+ ],
+ header_libs: ["liblog_headers"],
cflags: [
"-Wall",
"-Werror",
- "-DLIBLOG_LOG_TAG=1006",
- "-DWRITE_TO_STATSD=1",
- "-DWRITE_TO_LOGD=0",
],
- export_include_dirs: ["include"],
- shared_libs: [
- "libcutils",
- "liblog",
+}
+
+cc_library {
+ name: "libstatssocket",
+ defaults: [
+ "libstatssocket_defaults",
],
+ host_supported: true,
+ target: {
+ // On android, libstatssocket should only be linked as a shared lib
+ android: {
+ static: {
+ enabled: false,
+ },
+ },
+ host: {
+ shared: {
+ enabled: false,
+ },
+ },
+ },
+ stl: "libc++_static",
// enumerate stable entry points for APEX use
stubs: {
symbol_file: "libstatssocket.map.txt",
versions: [
- "1",
+ "30",
],
- }
+ },
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
+}
+
+//TODO (b/149842105): Figure out if there is a better solution for this.
+cc_test_library {
+ name: "libstatssocket_private",
+ defaults: [
+ "libstatssocket_defaults",
+ ],
+ visibility: [
+ "//frameworks/base/apex/statsd/tests/libstatspull",
+ "//frameworks/base/cmds/statsd",
+ ],
}
cc_library_headers {
@@ -58,41 +90,36 @@
min_sdk_version: "29",
}
-cc_benchmark {
- name: "libstatssocket_benchmark",
- srcs: [
- "benchmark/main.cpp",
- "benchmark/stats_event_benchmark.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- static_libs: [
- "libstatssocket",
- ],
- shared_libs: [
- "libcutils",
- "liblog",
- "libgtest_prod",
- ],
-}
-
cc_test {
name: "libstatssocket_test",
- srcs: ["tests/stats_event_test.cpp"],
+ srcs: [
+ "tests/stats_event_test.cpp",
+ "tests/stats_writer_test.cpp",
+ ],
cflags: [
"-Wall",
"-Werror",
],
static_libs: [
"libgmock",
- "libstatssocket",
+ "libstatssocket_private",
],
shared_libs: [
"libcutils",
- "liblog",
"libutils",
],
- test_suites: ["device_tests"],
+ test_suites: ["device-tests", "mts"],
+ test_config: "libstatssocket_test.xml",
+ //TODO(b/153588990): Remove when the build system properly separates.
+ //32bit and 64bit architectures.
+ compile_multilib: "both",
+ multilib: {
+ lib64: {
+ suffix: "64",
+ },
+ lib32: {
+ suffix: "32",
+ },
+ },
+ require_root: true,
}
diff --git a/libstats/socket/TEST_MAPPING b/libstats/socket/TEST_MAPPING
new file mode 100644
index 0000000..0224998
--- /dev/null
+++ b/libstats/socket/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit" : [
+ {
+ "name" : "libstatssocket_test"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/libstats/socket/benchmark/main.cpp b/libstats/socket/benchmark/main.cpp
deleted file mode 100644
index 5ebdf6e..0000000
--- a/libstats/socket/benchmark/main.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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 <benchmark/benchmark.h>
-
-BENCHMARK_MAIN();
diff --git a/libstats/socket/benchmark/stats_event_benchmark.cpp b/libstats/socket/benchmark/stats_event_benchmark.cpp
deleted file mode 100644
index 9488168..0000000
--- a/libstats/socket/benchmark/stats_event_benchmark.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 "benchmark/benchmark.h"
-#include "stats_event.h"
-
-static struct stats_event* constructStatsEvent() {
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
-
- // randomly sample atom size
- int numElements = rand() % 800;
- for (int i = 0; i < numElements; i++) {
- stats_event_write_int32(event, i);
- }
-
- return event;
-}
-
-static void BM_stats_event_truncate_buffer(benchmark::State& state) {
- while (state.KeepRunning()) {
- struct stats_event* event = constructStatsEvent();
- stats_event_build(event);
- stats_event_write(event);
- stats_event_release(event);
- }
-}
-
-BENCHMARK(BM_stats_event_truncate_buffer);
-
-static void BM_stats_event_full_buffer(benchmark::State& state) {
- while (state.KeepRunning()) {
- struct stats_event* event = constructStatsEvent();
- stats_event_truncate_buffer(event, false);
- stats_event_build(event);
- stats_event_write(event);
- stats_event_release(event);
- }
-}
-
-BENCHMARK(BM_stats_event_full_buffer);
diff --git a/libstats/socket/include/stats_buffer_writer.h b/libstats/socket/include/stats_buffer_writer.h
index de4a5e2..5b41f0e 100644
--- a/libstats/socket/include/stats_buffer_writer.h
+++ b/libstats/socket/include/stats_buffer_writer.h
@@ -23,6 +23,7 @@
extern "C" {
#endif // __CPLUSPLUS
void stats_log_close();
+int stats_log_is_closed();
int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId);
#ifdef __cplusplus
}
diff --git a/libstats/socket/include/stats_event.h b/libstats/socket/include/stats_event.h
index 080e957..3d3baf9 100644
--- a/libstats/socket/include/stats_event.h
+++ b/libstats/socket/include/stats_event.h
@@ -26,136 +26,136 @@
* This code defines and encapsulates the socket protocol.
*
* Usage:
- * struct stats_event* event = stats_event_obtain();
+ * AStatsEvent* event = AStatsEvent_obtain();
*
- * stats_event_set_atom_id(event, atomId);
- * stats_event_write_int32(event, 24);
- * stats_event_add_bool_annotation(event, 1, true); // annotations apply to the previous field
- * stats_event_add_int32_annotation(event, 2, 128);
- * stats_event_write_float(event, 2.0);
+ * AStatsEvent_setAtomId(event, atomId);
+ * AStatsEvent_addBoolAnnotation(event, 5, false); // atom-level annotation
+ * AStatsEvent_writeInt32(event, 24);
+ * AStatsEvent_addBoolAnnotation(event, 1, true); // annotation for preceding atom field
+ * AStatsEvent_addInt32Annotation(event, 2, 128);
+ * AStatsEvent_writeFloat(event, 2.0);
*
- * stats_event_build(event);
- * stats_event_write(event);
- * stats_event_release(event);
+ * AStatsEvent_write(event);
+ * AStatsEvent_release(event);
*
- * Notes:
- * (a) write_<type>() and add_<type>_annotation() should be called in the order that fields
- * and annotations are defined in the atom.
- * (b) set_atom_id() can be called anytime before stats_event_write().
- * (c) add_<type>_annotation() calls apply to the previous field.
- * (d) If errors occur, stats_event_write() will write a bitmask of the errors to the socket.
- * (e) All strings should be encoded using UTF8.
+ * Note that calls to add atom fields and annotations should be made in the
+ * order that they are defined in the atom.
*/
-/* ERRORS */
-#define ERROR_NO_TIMESTAMP 0x1
-#define ERROR_NO_ATOM_ID 0x2
-#define ERROR_OVERFLOW 0x4
-#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
-#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
-#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
-#define ERROR_INVALID_ANNOTATION_ID 0x40
-#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
-#define ERROR_TOO_MANY_ANNOTATIONS 0x100
-#define ERROR_TOO_MANY_FIELDS 0x200
-#define ERROR_INVALID_VALUE_TYPE 0x400
-#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
-
-/* TYPE IDS */
-#define INT32_TYPE 0x00
-#define INT64_TYPE 0x01
-#define STRING_TYPE 0x02
-#define LIST_TYPE 0x03
-#define FLOAT_TYPE 0x04
-#define BOOL_TYPE 0x05
-#define BYTE_ARRAY_TYPE 0x06
-#define OBJECT_TYPE 0x07
-#define KEY_VALUE_PAIRS_TYPE 0x08
-#define ATTRIBUTION_CHAIN_TYPE 0x09
-#define ERROR_TYPE 0x0F
-
#ifdef __cplusplus
extern "C" {
#endif // __CPLUSPLUS
-struct stats_event;
-
-/* SYSTEM API */
-struct stats_event* stats_event_obtain();
-// The build function can be called multiple times without error. If the event
-// has been built before, this function is a no-op.
-void stats_event_build(struct stats_event* event);
-int stats_event_write(struct stats_event* event);
-void stats_event_release(struct stats_event* event);
-
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId);
-
-void stats_event_write_int32(struct stats_event* event, int32_t value);
-void stats_event_write_int64(struct stats_event* event, int64_t value);
-void stats_event_write_float(struct stats_event* event, float value);
-void stats_event_write_bool(struct stats_event* event, bool value);
-
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes);
-
-// Buf must be null-terminated.
-void stats_event_write_string8(struct stats_event* event, const char* value);
-
-// Tags must be null-terminated.
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes);
-
-/* key_value_pair struct can be constructed as follows:
- * struct key_value_pair pair = {.key = key, .valueType = STRING_TYPE,
- * .stringValue = buf};
+/**
+ * Opaque struct use to represent a StatsEvent. It builds and stores the data that is sent to
+ * statsd.
*/
-struct key_value_pair {
- int32_t key;
- uint8_t valueType; // expected to be INT32_TYPE, INT64_TYPE, FLOAT_TYPE, or STRING_TYPE
- union {
- int32_t int32Value;
- int64_t int64Value;
- float floatValue;
- const char* stringValue; // must be null terminated
- };
-};
+struct AStatsEvent;
+typedef struct AStatsEvent AStatsEvent;
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
- uint8_t numPairs);
+/**
+ * Returns a new AStatsEvent. If you call this function, you must call AStatsEvent_release to free
+ * the allocated memory.
+ */
+AStatsEvent* AStatsEvent_obtain();
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value);
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
- int32_t value);
+/**
+ * Builds and finalizes the AStatsEvent for a pulled event.
+ * This should only be called for pulled AStatsEvents.
+ *
+ * After this function, the StatsEvent must not be modified in any way other than calling release or
+ * write.
+ *
+ * Build can be called multiple times without error.
+ * If the event has been built before, this function is a no-op.
+ */
+void AStatsEvent_build(AStatsEvent* event);
-uint32_t stats_event_get_atom_id(struct stats_event* event);
+/**
+ * Writes the StatsEvent to the stats log.
+ *
+ * After calling this, AStatsEvent_release must be called,
+ * and is the only function that can be safely called.
+ */
+int AStatsEvent_write(AStatsEvent* event);
+
+/**
+ * Frees the memory held by this StatsEvent.
+ *
+ * After calling this, the StatsEvent must not be used or modified in any way.
+ */
+void AStatsEvent_release(AStatsEvent* event);
+
+/**
+ * Sets the atom id for this StatsEvent.
+ *
+ * This function should be called immediately after AStatsEvent_obtain. It may
+ * be called additional times as well, but subsequent calls will have no effect.
+ **/
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId);
+
+/**
+ * Writes an int32_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value);
+
+/**
+ * Writes an int64_t field to this StatsEvent.
+ **/
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value);
+
+/**
+ * Writes a float field to this StatsEvent.
+ **/
+void AStatsEvent_writeFloat(AStatsEvent* event, float value);
+
+/**
+ * Write a bool field to this StatsEvent.
+ **/
+void AStatsEvent_writeBool(AStatsEvent* event, bool value);
+
+/**
+ * Write a byte array field to this StatsEvent.
+ **/
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes);
+
+/**
+ * Write a string field to this StatsEvent.
+ *
+ * The string must be null-terminated.
+ **/
+void AStatsEvent_writeString(AStatsEvent* event, const char* value);
+
+/**
+ * Write an attribution chain field to this StatsEvent.
+ *
+ * The sizes of uids and tags must be equal. The AttributionNode at position i is
+ * made up of uids[i] and tags[i].
+ *
+ * \param uids array of uids in the attribution chain.
+ * \param tags array of tags in the attribution chain. Each tag must be null-terminated.
+ * \param numNodes the number of AttributionNodes in the attribution chain. This is the length of
+ * the uids and the tags.
+ **/
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes);
+
+/**
+ * Write a bool annotation for the previous field written.
+ **/
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value);
+
+/**
+ * Write an integer annotation for the previous field written.
+ **/
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value);
+
+// Internal/test APIs. Should not be exposed outside of the APEX.
+void AStatsEvent_overwriteTimestamp(AStatsEvent* event, uint64_t timestampNs);
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event);
// Size is an output parameter.
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size);
-uint32_t stats_event_get_errors(struct stats_event* event);
-
-// This table is used by StatsEventCompat to access the stats_event API.
-struct stats_event_api_table {
- struct stats_event* (*obtain)(void);
- void (*build)(struct stats_event*);
- int (*write)(struct stats_event*);
- void (*release)(struct stats_event*);
- void (*set_atom_id)(struct stats_event*, uint32_t);
- void (*write_int32)(struct stats_event*, int32_t);
- void (*write_int64)(struct stats_event*, int64_t);
- void (*write_float)(struct stats_event*, float);
- void (*write_bool)(struct stats_event*, bool);
- void (*write_byte_array)(struct stats_event*, const uint8_t*, size_t);
- void (*write_string8)(struct stats_event*, const char*);
- void (*write_attribution_chain)(struct stats_event*, const uint32_t*, const char* const*,
- uint8_t);
- void (*write_key_value_pairs)(struct stats_event*, struct key_value_pair*, uint8_t);
- void (*add_bool_annotation)(struct stats_event*, uint8_t, bool);
- void (*add_int32_annotation)(struct stats_event*, uint8_t, int32_t);
- uint32_t (*get_atom_id)(struct stats_event*);
- uint8_t* (*get_buffer)(struct stats_event*, size_t*);
- uint32_t (*get_errors)(struct stats_event*);
-};
-
-// exposed for benchmarking only
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate);
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size);
+uint32_t AStatsEvent_getErrors(AStatsEvent* event);
#ifdef __cplusplus
}
diff --git a/libstats/socket/include/stats_event_list.h b/libstats/socket/include/stats_event_list.h
deleted file mode 100644
index 7a26536..0000000
--- a/libstats/socket/include/stats_event_list.h
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <log/log_event_list.h>
-#include <sys/uio.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-void reset_log_context(android_log_context ctx);
-int write_to_logger(android_log_context context, log_id_t id);
-void note_log_drop(int error, int atomId);
-void stats_log_close();
-int android_log_write_char_array(android_log_context ctx, const char* value, size_t len);
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __cplusplus
-/**
- * A copy of android_log_event_list class.
- *
- * android_log_event_list is going to be deprecated soon, so copy it here to
- * avoid creating dependency on upstream code. TODO(b/78304629): Rewrite this
- * code.
- */
-class stats_event_list {
- private:
- android_log_context ctx;
- int ret;
-
- stats_event_list(const stats_event_list&) = delete;
- void operator=(const stats_event_list&) = delete;
-
- public:
- explicit stats_event_list(int tag) : ret(0) {
- ctx = create_android_logger(static_cast<uint32_t>(tag));
- }
- ~stats_event_list() { android_log_destroy(&ctx); }
-
- int close() {
- int retval = android_log_destroy(&ctx);
- if (retval < 0) {
- ret = retval;
- }
- return retval;
- }
-
- /* To allow above C calls to use this class as parameter */
- operator android_log_context() const { return ctx; }
-
- /* return errors or transmit status */
- int status() const { return ret; }
-
- int begin() {
- int retval = android_log_write_list_begin(ctx);
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
- int end() {
- int retval = android_log_write_list_end(ctx);
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
-
- stats_event_list& operator<<(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(uint32_t value) {
- int retval = android_log_write_int32(ctx, static_cast<int32_t>(value));
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(bool value) {
- int retval = android_log_write_int32(ctx, value ? 1 : 0);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(uint64_t value) {
- int retval = android_log_write_int64(ctx, static_cast<int64_t>(value));
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(const std::string& value) {
- int retval = android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- stats_event_list& operator<<(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return *this;
- }
-
- int write(log_id_t id = LOG_ID_EVENTS) {
- /* facilitate -EBUSY retry */
- if ((ret == -EBUSY) || (ret > 0)) {
- ret = 0;
- }
- int retval = write_to_logger(ctx, id);
- /* existing errors trump transmission errors */
- if (!ret) {
- ret = retval;
- }
- return ret;
- }
-
- /*
- * Append<Type> methods removes any integer promotion
- * confusion, and adds access to string with length.
- * Append methods are also added for all types for
- * convenience.
- */
-
- bool AppendInt(int32_t value) {
- int retval = android_log_write_int32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendLong(int64_t value) {
- int retval = android_log_write_int64(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendString(const char* value) {
- int retval = android_log_write_string8(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendString(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendString(const std::string& value) {
- int retval = android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
-
- bool Append(const std::string& value) {
- int retval = android_log_write_string8_len(ctx, value.data(), value.length());
- if (retval < 0) {
- ret = retval;
- }
- return ret;
- }
-
- bool AppendFloat(float value) {
- int retval = android_log_write_float32(ctx, value);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- template <typename Tvalue>
- bool Append(Tvalue value) {
- *this << value;
- return ret >= 0;
- }
-
- bool Append(const char* value, size_t len) {
- int retval = android_log_write_string8_len(ctx, value, len);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-
- bool AppendCharArray(const char* value, size_t len) {
- int retval = android_log_write_char_array(ctx, value, len);
- if (retval < 0) {
- ret = retval;
- }
- return ret >= 0;
- }
-};
-
-#endif
diff --git a/libstats/socket/include/stats_socket.h b/libstats/socket/include/stats_socket.h
new file mode 100644
index 0000000..5a75fc0
--- /dev/null
+++ b/libstats/socket/include/stats_socket.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+/**
+ * Helpers to manage the statsd socket.
+ **/
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __CPLUSPLUS
+
+/**
+ * Closes the statsd socket file descriptor.
+ **/
+void AStatsSocket_close();
+#ifdef __cplusplus
+}
+#endif // __CPLUSPLUS
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
index 55bfbda..5c13904 100644
--- a/libstats/socket/libstatssocket.map.txt
+++ b/libstats/socket/libstatssocket.map.txt
@@ -1,23 +1,20 @@
LIBSTATSSOCKET {
global:
- stats_event_obtain; # apex # introduced=1
- stats_event_build; # apex # introduced=1
- stats_event_write; # apex # introduced=1
- stats_event_release; # apex # introduced=1
- stats_event_set_atom_id; # apex # introduced=1
- stats_event_write_int32; # apex # introduced=1
- stats_event_write_int64; # apex # introduced=1
- stats_event_write_float; # apex # introduced=1
- stats_event_write_bool; # apex # introduced=1
- stats_event_write_byte_array; # apex # introduced=1
- stats_event_write_string8; # apex # introduced=1
- stats_event_write_attribution_chain; # apex # introduced=1
- stats_event_write_key_value_pairs; # apex # introduced=1
- stats_event_add_bool_annotation; # apex # introduced=1
- stats_event_add_int32_annotation; # apex # introduced=1
- stats_event_get_atom_id; # apex # introduced=1
- stats_event_get_buffer; # apex # introduced=1
- stats_event_get_errors; # apex # introduced=1
+ AStatsEvent_obtain; # apex # introduced=30
+ AStatsEvent_build; # apex # introduced=30
+ AStatsEvent_write; # apex # introduced=30
+ AStatsEvent_release; # apex # introduced=30
+ AStatsEvent_setAtomId; # apex # introduced=30
+ AStatsEvent_writeInt32; # apex # introduced=30
+ AStatsEvent_writeInt64; # apex # introduced=30
+ AStatsEvent_writeFloat; # apex # introduced=30
+ AStatsEvent_writeBool; # apex # introduced=30
+ AStatsEvent_writeByteArray; # apex # introduced=30
+ AStatsEvent_writeString; # apex # introduced=30
+ AStatsEvent_writeAttributionChain; # apex # introduced=30
+ AStatsEvent_addBoolAnnotation; # apex # introduced=30
+ AStatsEvent_addInt32Annotation; # apex # introduced=30
+ AStatsSocket_close; # apex # introduced=30
local:
*;
};
diff --git a/libstats/socket/libstatssocket_test.xml b/libstats/socket/libstatssocket_test.xml
new file mode 100644
index 0000000..d2694d1
--- /dev/null
+++ b/libstats/socket/libstatssocket_test.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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="Runs libstatssocket_test.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+ <option name="test-suite-tag" value="mts" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libstatssocket_test->/data/local/tmp/libstatssocket_test" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libstatssocket_test" />
+ </test>
+
+ <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.os.statsd" />
+ </object>
+</configuration>
+
diff --git a/libstats/socket/stats_buffer_writer.c b/libstats/socket/stats_buffer_writer.c
index c5c591d..549acdc 100644
--- a/libstats/socket/stats_buffer_writer.c
+++ b/libstats/socket/stats_buffer_writer.c
@@ -43,27 +43,23 @@
statsd_writer_init_unlock();
}
+int stats_log_is_closed() {
+ return statsdLoggerWrite.isClosed && (*statsdLoggerWrite.isClosed)();
+}
+
int write_buffer_to_statsd(void* buffer, size_t size, uint32_t atomId) {
int ret = 1;
-#ifdef __ANDROID__
- bool statsdEnabled = property_get_bool("ro.statsd.enable", true);
-#else
- bool statsdEnabled = false;
-#endif
+ struct iovec vecs[2];
+ vecs[0].iov_base = (void*)&kStatsEventTag;
+ vecs[0].iov_len = sizeof(kStatsEventTag);
+ vecs[1].iov_base = buffer;
+ vecs[1].iov_len = size;
- if (statsdEnabled) {
- struct iovec vecs[2];
- vecs[0].iov_base = (void*)&kStatsEventTag;
- vecs[0].iov_len = sizeof(kStatsEventTag);
- vecs[1].iov_base = buffer;
- vecs[1].iov_len = size;
+ ret = __write_to_statsd(vecs, 2);
- ret = __write_to_statsd(vecs, 2);
-
- if (ret < 0) {
- note_log_drop(ret, atomId);
- }
+ if (ret < 0) {
+ note_log_drop(ret, atomId);
}
return ret;
diff --git a/libstats/socket/stats_event.c b/libstats/socket/stats_event.c
index 15039c6..f3e8087 100644
--- a/libstats/socket/stats_event.c
+++ b/libstats/socket/stats_event.c
@@ -23,29 +23,61 @@
#define LOGGER_ENTRY_MAX_PAYLOAD 4068
// Max payload size is 4 bytes less as 4 bytes are reserved for stats_eventTag.
// See android_util_Stats_Log.cpp
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - 4)
+#define MAX_PUSH_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - 4)
+
+#define MAX_PULL_EVENT_PAYLOAD (50 * 1024) // 50 KB
/* POSITIONS */
#define POS_NUM_ELEMENTS 1
#define POS_TIMESTAMP (POS_NUM_ELEMENTS + sizeof(uint8_t))
#define POS_ATOM_ID (POS_TIMESTAMP + sizeof(uint8_t) + sizeof(uint64_t))
-#define POS_FIRST_FIELD (POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t))
/* LIMITS */
#define MAX_ANNOTATION_COUNT 15
#define MAX_BYTE_VALUE 127 // parsing side requires that lengths fit in 7 bits
-// The stats_event struct holds the serialized encoding of an event
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+#define ERROR_ATOM_ID_INVALID_POSITION 0x2000
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
+// The AStatsEvent struct holds the serialized encoding of an event
// within a buf. Also includes other required fields.
-struct stats_event {
+struct AStatsEvent {
uint8_t* buf;
- size_t lastFieldPos; // location of last field within the buf
- size_t size; // number of valid bytes within buffer
+ // Location of last field within the buf. Here, field denotes either a
+ // metadata field (e.g. timestamp) or an atom field.
+ size_t lastFieldPos;
+ // Number of valid bytes within the buffer.
+ size_t numBytesWritten;
uint32_t numElements;
uint32_t atomId;
uint32_t errors;
- bool truncate;
bool built;
+ size_t bufSize;
};
static int64_t get_elapsed_realtime_ns() {
@@ -55,93 +87,115 @@
return (int64_t)t.tv_sec * 1000000000LL + t.tv_nsec;
}
-struct stats_event* stats_event_obtain() {
- struct stats_event* event = malloc(sizeof(struct stats_event));
- event->buf = (uint8_t*)calloc(MAX_EVENT_PAYLOAD, 1);
- event->buf[0] = OBJECT_TYPE;
+AStatsEvent* AStatsEvent_obtain() {
+ AStatsEvent* event = malloc(sizeof(AStatsEvent));
+ event->lastFieldPos = 0;
+ event->numBytesWritten = 2; // reserve first 2 bytes for root event type and number of elements
+ event->numElements = 0;
event->atomId = 0;
event->errors = 0;
- event->truncate = true; // truncate for both pulled and pushed atoms
event->built = false;
+ event->bufSize = MAX_PUSH_EVENT_PAYLOAD;
+ event->buf = (uint8_t*)calloc(event->bufSize, 1);
- // place the timestamp
- uint64_t timestampNs = get_elapsed_realtime_ns();
- event->buf[POS_TIMESTAMP] = INT64_TYPE;
- memcpy(&event->buf[POS_TIMESTAMP + sizeof(uint8_t)], ×tampNs, sizeof(timestampNs));
-
- event->numElements = 1;
- event->lastFieldPos = 0; // 0 since we haven't written a field yet
- event->size = POS_FIRST_FIELD;
+ event->buf[0] = OBJECT_TYPE;
+ AStatsEvent_writeInt64(event, get_elapsed_realtime_ns()); // write the timestamp
return event;
}
-void stats_event_release(struct stats_event* event) {
+void AStatsEvent_release(AStatsEvent* event) {
free(event->buf);
free(event);
}
-void stats_event_set_atom_id(struct stats_event* event, uint32_t atomId) {
+void AStatsEvent_setAtomId(AStatsEvent* event, uint32_t atomId) {
+ if (event->atomId != 0) return;
+ if (event->numElements != 1) {
+ event->errors |= ERROR_ATOM_ID_INVALID_POSITION;
+ return;
+ }
+
event->atomId = atomId;
- event->buf[POS_ATOM_ID] = INT32_TYPE;
- memcpy(&event->buf[POS_ATOM_ID + sizeof(uint8_t)], &atomId, sizeof(atomId));
- event->numElements++;
+ AStatsEvent_writeInt32(event, atomId);
+}
+
+// Overwrites the timestamp populated in AStatsEvent_obtain with a custom
+// timestamp. Should only be called from test code.
+void AStatsEvent_overwriteTimestamp(AStatsEvent* event, uint64_t timestampNs) {
+ memcpy(&event->buf[POS_TIMESTAMP + sizeof(uint8_t)], ×tampNs, sizeof(timestampNs));
+ // Do not increment numElements because we already accounted for the timestamp
+ // within AStatsEvent_obtain.
}
// Side-effect: modifies event->errors if the buffer would overflow
-static bool overflows(struct stats_event* event, size_t size) {
- if (event->size + size > MAX_EVENT_PAYLOAD) {
+static bool overflows(AStatsEvent* event, size_t size) {
+ const size_t totalBytesNeeded = event->numBytesWritten + size;
+ if (totalBytesNeeded > MAX_PULL_EVENT_PAYLOAD) {
event->errors |= ERROR_OVERFLOW;
return true;
}
+
+ // Expand buffer if needed.
+ if (event->bufSize < MAX_PULL_EVENT_PAYLOAD && totalBytesNeeded > event->bufSize) {
+ do {
+ event->bufSize *= 2;
+ } while (event->bufSize <= totalBytesNeeded);
+
+ if (event->bufSize > MAX_PULL_EVENT_PAYLOAD) {
+ event->bufSize = MAX_PULL_EVENT_PAYLOAD;
+ }
+
+ event->buf = (uint8_t*)realloc(event->buf, event->bufSize);
+ }
return false;
}
-// Side-effect: all append functions increment event->size if there is
+// Side-effect: all append functions increment event->numBytesWritten if there is
// sufficient space within the buffer to place the value
-static void append_byte(struct stats_event* event, uint8_t value) {
+static void append_byte(AStatsEvent* event, uint8_t value) {
if (!overflows(event, sizeof(value))) {
- event->buf[event->size] = value;
- event->size += sizeof(value);
+ event->buf[event->numBytesWritten] = value;
+ event->numBytesWritten += sizeof(value);
}
}
-static void append_bool(struct stats_event* event, bool value) {
+static void append_bool(AStatsEvent* event, bool value) {
append_byte(event, (uint8_t)value);
}
-static void append_int32(struct stats_event* event, int32_t value) {
+static void append_int32(AStatsEvent* event, int32_t value) {
if (!overflows(event, sizeof(value))) {
- memcpy(&event->buf[event->size], &value, sizeof(value));
- event->size += sizeof(value);
+ memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
+ event->numBytesWritten += sizeof(value);
}
}
-static void append_int64(struct stats_event* event, int64_t value) {
+static void append_int64(AStatsEvent* event, int64_t value) {
if (!overflows(event, sizeof(value))) {
- memcpy(&event->buf[event->size], &value, sizeof(value));
- event->size += sizeof(value);
+ memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
+ event->numBytesWritten += sizeof(value);
}
}
-static void append_float(struct stats_event* event, float value) {
+static void append_float(AStatsEvent* event, float value) {
if (!overflows(event, sizeof(value))) {
- memcpy(&event->buf[event->size], &value, sizeof(value));
- event->size += sizeof(float);
+ memcpy(&event->buf[event->numBytesWritten], &value, sizeof(value));
+ event->numBytesWritten += sizeof(float);
}
}
-static void append_byte_array(struct stats_event* event, const uint8_t* buf, size_t size) {
+static void append_byte_array(AStatsEvent* event, const uint8_t* buf, size_t size) {
if (!overflows(event, size)) {
- memcpy(&event->buf[event->size], buf, size);
- event->size += size;
+ memcpy(&event->buf[event->numBytesWritten], buf, size);
+ event->numBytesWritten += size;
}
}
// Side-effect: modifies event->errors if buf is not properly null-terminated
-static void append_string(struct stats_event* event, const char* buf) {
- size_t size = strnlen(buf, MAX_EVENT_PAYLOAD);
- if (size == MAX_EVENT_PAYLOAD) {
+static void append_string(AStatsEvent* event, const char* buf) {
+ size_t size = strnlen(buf, MAX_PULL_EVENT_PAYLOAD);
+ if (size == MAX_PULL_EVENT_PAYLOAD) {
event->errors |= ERROR_STRING_NOT_NULL_TERMINATED;
return;
}
@@ -150,61 +204,51 @@
append_byte_array(event, (uint8_t*)buf, size);
}
-static void start_field(struct stats_event* event, uint8_t typeId) {
- event->lastFieldPos = event->size;
+static void start_field(AStatsEvent* event, uint8_t typeId) {
+ event->lastFieldPos = event->numBytesWritten;
append_byte(event, typeId);
event->numElements++;
}
-void stats_event_write_int32(struct stats_event* event, int32_t value) {
- if (event->errors) return;
-
+void AStatsEvent_writeInt32(AStatsEvent* event, int32_t value) {
start_field(event, INT32_TYPE);
append_int32(event, value);
}
-void stats_event_write_int64(struct stats_event* event, int64_t value) {
- if (event->errors) return;
-
+void AStatsEvent_writeInt64(AStatsEvent* event, int64_t value) {
start_field(event, INT64_TYPE);
append_int64(event, value);
}
-void stats_event_write_float(struct stats_event* event, float value) {
- if (event->errors) return;
-
+void AStatsEvent_writeFloat(AStatsEvent* event, float value) {
start_field(event, FLOAT_TYPE);
append_float(event, value);
}
-void stats_event_write_bool(struct stats_event* event, bool value) {
- if (event->errors) return;
-
+void AStatsEvent_writeBool(AStatsEvent* event, bool value) {
start_field(event, BOOL_TYPE);
append_bool(event, value);
}
-void stats_event_write_byte_array(struct stats_event* event, const uint8_t* buf, size_t numBytes) {
- if (event->errors) return;
-
+void AStatsEvent_writeByteArray(AStatsEvent* event, const uint8_t* buf, size_t numBytes) {
start_field(event, BYTE_ARRAY_TYPE);
append_int32(event, numBytes);
append_byte_array(event, buf, numBytes);
}
// Value is assumed to be encoded using UTF8
-void stats_event_write_string8(struct stats_event* event, const char* value) {
- if (event->errors) return;
-
+void AStatsEvent_writeString(AStatsEvent* event, const char* value) {
start_field(event, STRING_TYPE);
append_string(event, value);
}
// Tags are assumed to be encoded using UTF8
-void stats_event_write_attribution_chain(struct stats_event* event, const uint32_t* uids,
- const char* const* tags, uint8_t numNodes) {
- if (numNodes > MAX_BYTE_VALUE) event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
- if (event->errors) return;
+void AStatsEvent_writeAttributionChain(AStatsEvent* event, const uint32_t* uids,
+ const char* const* tags, uint8_t numNodes) {
+ if (numNodes > MAX_BYTE_VALUE) {
+ event->errors |= ERROR_ATTRIBUTION_CHAIN_TOO_LONG;
+ return;
+ }
start_field(event, ATTRIBUTION_CHAIN_TYPE);
append_byte(event, numNodes);
@@ -215,39 +259,8 @@
}
}
-void stats_event_write_key_value_pairs(struct stats_event* event, struct key_value_pair* pairs,
- uint8_t numPairs) {
- if (numPairs > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_KEY_VALUE_PAIRS;
- if (event->errors) return;
-
- start_field(event, KEY_VALUE_PAIRS_TYPE);
- append_byte(event, numPairs);
-
- for (uint8_t i = 0; i < numPairs; i++) {
- append_int32(event, pairs[i].key);
- append_byte(event, pairs[i].valueType);
- switch (pairs[i].valueType) {
- case INT32_TYPE:
- append_int32(event, pairs[i].int32Value);
- break;
- case INT64_TYPE:
- append_int64(event, pairs[i].int64Value);
- break;
- case FLOAT_TYPE:
- append_float(event, pairs[i].floatValue);
- break;
- case STRING_TYPE:
- append_string(event, pairs[i].stringValue);
- break;
- default:
- event->errors |= ERROR_INVALID_VALUE_TYPE;
- return;
- }
- }
-}
-
// Side-effect: modifies event->errors if field has too many annotations
-static void increment_annotation_count(struct stats_event* event) {
+static void increment_annotation_count(AStatsEvent* event) {
uint8_t fieldType = event->buf[event->lastFieldPos] & 0x0F;
uint32_t oldAnnotationCount = (event->buf[event->lastFieldPos] & 0xF0) >> 4;
uint32_t newAnnotationCount = oldAnnotationCount + 1;
@@ -260,10 +273,14 @@
event->buf[event->lastFieldPos] = (((uint8_t)newAnnotationCount << 4) & 0xF0) | fieldType;
}
-void stats_event_add_bool_annotation(struct stats_event* event, uint8_t annotationId, bool value) {
- if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
- if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
- if (event->errors) return;
+void AStatsEvent_addBoolAnnotation(AStatsEvent* event, uint8_t annotationId, bool value) {
+ if (event->numElements < 2) {
+ event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+ return;
+ } else if (annotationId > MAX_BYTE_VALUE) {
+ event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
+ return;
+ }
append_byte(event, annotationId);
append_byte(event, BOOL_TYPE);
@@ -271,11 +288,14 @@
increment_annotation_count(event);
}
-void stats_event_add_int32_annotation(struct stats_event* event, uint8_t annotationId,
- int32_t value) {
- if (event->lastFieldPos == 0) event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
- if (annotationId > MAX_BYTE_VALUE) event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
- if (event->errors) return;
+void AStatsEvent_addInt32Annotation(AStatsEvent* event, uint8_t annotationId, int32_t value) {
+ if (event->numElements < 2) {
+ event->errors |= ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD;
+ return;
+ } else if (annotationId > MAX_BYTE_VALUE) {
+ event->errors |= ERROR_ANNOTATION_ID_TOO_LARGE;
+ return;
+ }
append_byte(event, annotationId);
append_byte(event, INT32_TYPE);
@@ -283,72 +303,49 @@
increment_annotation_count(event);
}
-uint32_t stats_event_get_atom_id(struct stats_event* event) {
+uint32_t AStatsEvent_getAtomId(AStatsEvent* event) {
return event->atomId;
}
-uint8_t* stats_event_get_buffer(struct stats_event* event, size_t* size) {
- if (size) *size = event->size;
+uint8_t* AStatsEvent_getBuffer(AStatsEvent* event, size_t* size) {
+ if (size) *size = event->numBytesWritten;
return event->buf;
}
-uint32_t stats_event_get_errors(struct stats_event* event) {
+uint32_t AStatsEvent_getErrors(AStatsEvent* event) {
return event->errors;
}
-void stats_event_truncate_buffer(struct stats_event* event, bool truncate) {
- event->truncate = truncate;
-}
-
-void stats_event_build(struct stats_event* event) {
- if (event->built) return;
-
- if (event->atomId == 0) event->errors |= ERROR_NO_ATOM_ID;
-
- if (event->numElements > MAX_BYTE_VALUE) {
- event->errors |= ERROR_TOO_MANY_FIELDS;
- } else {
- event->buf[POS_NUM_ELEMENTS] = event->numElements;
- }
+static void build_internal(AStatsEvent* event, const bool push) {
+ if (event->numElements > MAX_BYTE_VALUE) event->errors |= ERROR_TOO_MANY_FIELDS;
+ if (0 == event->atomId) event->errors |= ERROR_NO_ATOM_ID;
+ if (push && event->numBytesWritten > MAX_PUSH_EVENT_PAYLOAD) event->errors |= ERROR_OVERFLOW;
// If there are errors, rewrite buffer.
if (event->errors) {
- event->buf[POS_NUM_ELEMENTS] = 3;
- event->buf[POS_FIRST_FIELD] = ERROR_TYPE;
- memcpy(&event->buf[POS_FIRST_FIELD + sizeof(uint8_t)], &event->errors,
- sizeof(event->errors));
- event->size = POS_FIRST_FIELD + sizeof(uint8_t) + sizeof(uint32_t);
+ // Discard everything after the atom id (including atom-level
+ // annotations). This leaves only two elements (timestamp and atom id).
+ event->numElements = 2;
+ // Reset number of atom-level annotations to 0.
+ event->buf[POS_ATOM_ID] = INT32_TYPE;
+ // Now, write errors to the buffer immediately after the atom id.
+ event->numBytesWritten = POS_ATOM_ID + sizeof(uint8_t) + sizeof(uint32_t);
+ start_field(event, ERROR_TYPE);
+ append_int32(event, event->errors);
}
- // Truncate the buffer to the appropriate length in order to limit our
- // memory usage.
- if (event->truncate) event->buf = (uint8_t*)realloc(event->buf, event->size);
+ event->buf[POS_NUM_ELEMENTS] = event->numElements;
+}
+
+void AStatsEvent_build(AStatsEvent* event) {
+ if (event->built) return;
+
+ build_internal(event, false /* push */);
event->built = true;
}
-int stats_event_write(struct stats_event* event) {
- stats_event_build(event);
- return write_buffer_to_statsd(&event->buf, event->size, event->atomId);
+int AStatsEvent_write(AStatsEvent* event) {
+ build_internal(event, true /* push */);
+ return write_buffer_to_statsd(event->buf, event->numBytesWritten, event->atomId);
}
-
-struct stats_event_api_table table = {
- stats_event_obtain,
- stats_event_build,
- stats_event_write,
- stats_event_release,
- stats_event_set_atom_id,
- stats_event_write_int32,
- stats_event_write_int64,
- stats_event_write_float,
- stats_event_write_bool,
- stats_event_write_byte_array,
- stats_event_write_string8,
- stats_event_write_attribution_chain,
- stats_event_write_key_value_pairs,
- stats_event_add_bool_annotation,
- stats_event_add_int32_annotation,
- stats_event_get_atom_id,
- stats_event_get_buffer,
- stats_event_get_errors,
-};
diff --git a/libstats/socket/stats_event_list.c b/libstats/socket/stats_event_list.c
deleted file mode 100644
index 661a223..0000000
--- a/libstats/socket/stats_event_list.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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 "include/stats_event_list.h"
-
-#include <string.h>
-#include <sys/time.h>
-#include "stats_buffer_writer.h"
-
-#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
-
-typedef struct {
- uint32_t tag;
- unsigned pos; /* Read/write position into buffer */
- unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
- unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
- unsigned list_nest_depth;
- unsigned len; /* Length or raw buffer. */
- bool overflow;
- bool list_stop; /* next call decrement list_nest_depth and issue a stop */
- enum {
- kAndroidLoggerRead = 1,
- kAndroidLoggerWrite = 2,
- } read_write_flag;
- uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
-} android_log_context_internal;
-
-// Similar to create_android_logger(), but instead of allocation a new buffer,
-// this function resets the buffer for resuse.
-void reset_log_context(android_log_context ctx) {
- if (!ctx) {
- return;
- }
- android_log_context_internal* context = (android_log_context_internal*)(ctx);
- uint32_t tag = context->tag;
- memset(context, 0, sizeof(android_log_context_internal));
-
- context->tag = tag;
- context->read_write_flag = kAndroidLoggerWrite;
- size_t needed = sizeof(uint8_t) + sizeof(uint8_t);
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- context->overflow = true;
- }
- /* Everything is a list */
- context->storage[context->pos + 0] = EVENT_TYPE_LIST;
- context->list[0] = context->pos + 1;
- context->pos += needed;
-}
-
-int stats_write_list(android_log_context ctx) {
- android_log_context_internal* context;
- const char* msg;
- ssize_t len;
-
- context = (android_log_context_internal*)(ctx);
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
-
- if (context->list_nest_depth) {
- return -EIO;
- }
-
- /* NB: if there was overflow, then log is truncated. Nothing reported */
- context->storage[1] = context->count[0];
- len = context->len = context->pos;
- msg = (const char*)context->storage;
- /* it's not a list */
- if (context->count[0] <= 1) {
- len -= sizeof(uint8_t) + sizeof(uint8_t);
- if (len < 0) {
- len = 0;
- }
- msg += sizeof(uint8_t) + sizeof(uint8_t);
- }
-
- return write_buffer_to_statsd((void*)msg, len, 0);
-}
-
-int write_to_logger(android_log_context ctx, log_id_t id) {
- int retValue = 0;
-
- if (WRITE_TO_LOGD) {
- retValue = android_log_write_list(ctx, id);
- }
-
- if (WRITE_TO_STATSD) {
- // log_event_list's cast operator is overloaded.
- int ret = stats_write_list(ctx);
- // In debugging phase, we may write to both logd and statsd. Prefer to
- // return statsd socket write error code here.
- if (ret < 0) {
- retValue = ret;
- }
- }
-
- return retValue;
-}
-
-static inline void copy4LE(uint8_t* buf, uint32_t val) {
- buf[0] = val & 0xFF;
- buf[1] = (val >> 8) & 0xFF;
- buf[2] = (val >> 16) & 0xFF;
- buf[3] = (val >> 24) & 0xFF;
-}
-
-// Note: this function differs from android_log_write_string8_len in that the length passed in
-// should be treated as actual length and not max length.
-int android_log_write_char_array(android_log_context ctx, const char* value, size_t actual_len) {
- size_t needed;
- ssize_t len = actual_len;
- android_log_context_internal* context;
-
- context = (android_log_context_internal*)ctx;
- if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
- return -EBADF;
- }
- if (context->overflow) {
- return -EIO;
- }
- if (!value) {
- value = "";
- len = 0;
- }
- needed = sizeof(uint8_t) + sizeof(int32_t) + len;
- if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
- /* Truncate string for delivery */
- len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(int32_t);
- if (len <= 0) {
- context->overflow = true;
- return -EIO;
- }
- }
- context->count[context->list_nest_depth]++;
- context->storage[context->pos + 0] = EVENT_TYPE_STRING;
- copy4LE(&context->storage[context->pos + 1], len);
- if (len) {
- memcpy(&context->storage[context->pos + 5], value, len);
- }
- context->pos += needed;
- return len;
-}
diff --git a/libstats/socket/stats_socket.c b/libstats/socket/stats_socket.c
new file mode 100644
index 0000000..09f8967
--- /dev/null
+++ b/libstats/socket/stats_socket.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 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 "include/stats_socket.h"
+#include "stats_buffer_writer.h"
+
+void AStatsSocket_close() {
+ stats_log_close();
+}
diff --git a/libstats/socket/statsd_writer.c b/libstats/socket/statsd_writer.c
index 04d3b46..73b7a7e 100644
--- a/libstats/socket/statsd_writer.c
+++ b/libstats/socket/statsd_writer.c
@@ -62,6 +62,7 @@
static void statsdClose();
static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr);
static void statsdNoteDrop();
+static int statsdIsClosed();
struct android_log_transport_write statsdLoggerWrite = {
.name = "statsd",
@@ -71,6 +72,7 @@
.close = statsdClose,
.write = statsdWrite,
.noteDrop = statsdNoteDrop,
+ .isClosed = statsdIsClosed,
};
/* log_init_lock assumed */
@@ -153,6 +155,13 @@
atomic_exchange_explicit(&atom_tag, tag, memory_order_relaxed);
}
+static int statsdIsClosed() {
+ if (atomic_load(&statsdLoggerWrite.sock) < 0) {
+ return 1;
+ }
+ return 0;
+}
+
static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) {
ssize_t ret;
int sock;
diff --git a/libstats/socket/statsd_writer.h b/libstats/socket/statsd_writer.h
index fe2d37c..562bda5 100644
--- a/libstats/socket/statsd_writer.h
+++ b/libstats/socket/statsd_writer.h
@@ -40,6 +40,8 @@
int (*write)(struct timespec* ts, struct iovec* vec, size_t nr);
/* note one log drop */
void (*noteDrop)(int error, int tag);
+ /* checks if the socket is closed */
+ int (*isClosed)();
};
#endif // ANDROID_STATS_LOG_STATS_WRITER_H
diff --git a/libstats/socket/tests/stats_event_test.cpp b/libstats/socket/tests/stats_event_test.cpp
index cf0592c..9a1fac8 100644
--- a/libstats/socket/tests/stats_event_test.cpp
+++ b/libstats/socket/tests/stats_event_test.cpp
@@ -18,13 +18,47 @@
#include <gtest/gtest.h>
#include <utils/SystemClock.h>
+// Keep in sync with stats_event.c. Consider moving to separate header file to avoid duplication.
+/* ERRORS */
+#define ERROR_NO_TIMESTAMP 0x1
+#define ERROR_NO_ATOM_ID 0x2
+#define ERROR_OVERFLOW 0x4
+#define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
+#define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
+#define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
+#define ERROR_INVALID_ANNOTATION_ID 0x40
+#define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
+#define ERROR_TOO_MANY_ANNOTATIONS 0x100
+#define ERROR_TOO_MANY_FIELDS 0x200
+#define ERROR_INVALID_VALUE_TYPE 0x400
+#define ERROR_STRING_NOT_NULL_TERMINATED 0x800
+#define ERROR_ATOM_ID_INVALID_POSITION 0x2000
+
+/* TYPE IDS */
+#define INT32_TYPE 0x00
+#define INT64_TYPE 0x01
+#define STRING_TYPE 0x02
+#define LIST_TYPE 0x03
+#define FLOAT_TYPE 0x04
+#define BOOL_TYPE 0x05
+#define BYTE_ARRAY_TYPE 0x06
+#define OBJECT_TYPE 0x07
+#define KEY_VALUE_PAIRS_TYPE 0x08
+#define ATTRIBUTION_CHAIN_TYPE 0x09
+#define ERROR_TYPE 0x0F
+
using std::string;
using std::vector;
// Side-effect: this function moves the start of the buffer past the read value
template <class T>
T readNext(uint8_t** buffer) {
- T value = *(T*)(*buffer);
+ T value;
+ if ((reinterpret_cast<uintptr_t>(*buffer) % alignof(T)) == 0) {
+ value = *(T*)(*buffer);
+ } else {
+ memcpy(&value, *buffer, sizeof(T));
+ }
*buffer += sizeof(T);
return value;
}
@@ -61,7 +95,7 @@
}
void checkMetadata(uint8_t** buffer, uint8_t numElements, int64_t startTime, int64_t endTime,
- uint32_t atomId) {
+ uint32_t atomId, uint8_t numAtomLevelAnnotations = 0) {
// All events start with OBJECT_TYPE id.
checkTypeHeader(buffer, OBJECT_TYPE);
@@ -76,7 +110,7 @@
EXPECT_LE(timestamp, endTime);
// Check atom id
- checkTypeHeader(buffer, INT32_TYPE);
+ checkTypeHeader(buffer, INT32_TYPE, numAtomLevelAnnotations);
checkScalar(buffer, atomId);
}
@@ -88,17 +122,17 @@
bool boolValue = false;
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_int32(event, int32Value);
- stats_event_write_int64(event, int64Value);
- stats_event_write_float(event, floatValue);
- stats_event_write_bool(event, boolValue);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeInt32(event, int32Value);
+ AStatsEvent_writeInt64(event, int64Value);
+ AStatsEvent_writeFloat(event, floatValue);
+ AStatsEvent_writeBool(event, boolValue);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
@@ -120,8 +154,8 @@
checkScalar(&buffer, boolValue);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestStrings) {
@@ -129,14 +163,14 @@
string str = "test_string";
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_string8(event, str.c_str());
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeString(event, str.c_str());
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -145,8 +179,8 @@
checkString(&buffer, str);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestByteArrays) {
@@ -154,14 +188,14 @@
vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_byte_array(event, message.data(), message.size());
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeByteArray(event, message.data(), message.size());
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -170,8 +204,8 @@
checkByteArray(&buffer, message);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestAttributionChains) {
@@ -188,14 +222,14 @@
}
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_attribution_chain(event, uids, cTags, numNodes);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
@@ -208,63 +242,11 @@
}
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
-TEST(StatsEventTest, TestKeyValuePairs) {
- uint32_t atomId = 100;
-
- uint8_t numPairs = 4;
- struct key_value_pair pairs[numPairs];
- pairs[0] = {.key = 0, .valueType = INT32_TYPE, .int32Value = -1};
- pairs[1] = {.key = 1, .valueType = INT64_TYPE, .int64Value = 0x123456789};
- pairs[2] = {.key = 2, .valueType = FLOAT_TYPE, .floatValue = 5.5};
- string str = "test_key_value_pair_string";
- pairs[3] = {.key = 3, .valueType = STRING_TYPE, .stringValue = str.c_str()};
-
- int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, atomId);
- stats_event_write_key_value_pairs(event, pairs, numPairs);
- stats_event_build(event);
- int64_t endTime = android::elapsedRealtimeNano();
-
- size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
- uint8_t* bufferEnd = buffer + bufferSize;
-
- checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
-
- checkTypeHeader(&buffer, KEY_VALUE_PAIRS_TYPE);
- checkScalar(&buffer, numPairs);
-
- // first pair
- checkScalar(&buffer, pairs[0].key);
- checkTypeHeader(&buffer, pairs[0].valueType);
- checkScalar(&buffer, pairs[0].int32Value);
-
- // second pair
- checkScalar(&buffer, pairs[1].key);
- checkTypeHeader(&buffer, pairs[1].valueType);
- checkScalar(&buffer, pairs[1].int64Value);
-
- // third pair
- checkScalar(&buffer, pairs[2].key);
- checkTypeHeader(&buffer, pairs[2].valueType);
- checkScalar(&buffer, pairs[2].floatValue);
-
- // fourth pair
- checkScalar(&buffer, pairs[3].key);
- checkTypeHeader(&buffer, pairs[3].valueType);
- checkString(&buffer, str);
-
- EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
-}
-
-TEST(StatsEventTest, TestAnnotations) {
+TEST(StatsEventTest, TestFieldAnnotations) {
uint32_t atomId = 100;
// first element information
@@ -282,19 +264,19 @@
bool floatAnnotation2Value = false;
int64_t startTime = android::elapsedRealtimeNano();
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
- stats_event_write_bool(event, boolValue);
- stats_event_add_bool_annotation(event, boolAnnotation1Id, boolAnnotation1Value);
- stats_event_add_int32_annotation(event, boolAnnotation2Id, boolAnnotation2Value);
- stats_event_write_float(event, floatValue);
- stats_event_add_int32_annotation(event, floatAnnotation1Id, floatAnnotation1Value);
- stats_event_add_bool_annotation(event, floatAnnotation2Id, floatAnnotation2Value);
- stats_event_build(event);
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_writeBool(event, boolValue);
+ AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
+ AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
+ AStatsEvent_writeFloat(event, floatValue);
+ AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
+ AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
+ AStatsEvent_build(event);
int64_t endTime = android::elapsedRealtimeNano();
size_t bufferSize;
- uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
uint8_t* bufferEnd = buffer + bufferSize;
checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
@@ -312,33 +294,167 @@
checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
- EXPECT_EQ(stats_event_get_errors(event), 0);
- stats_event_release(event);
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestAtomLevelAnnotations) {
+ uint32_t atomId = 100;
+ // atom-level annotation information
+ uint8_t boolAnnotationId = 1;
+ uint8_t int32AnnotationId = 2;
+ bool boolAnnotationValue = false;
+ int32_t int32AnnotationValue = 5;
+
+ float fieldValue = -3.5;
+
+ int64_t startTime = android::elapsedRealtimeNano();
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_addBoolAnnotation(event, boolAnnotationId, boolAnnotationValue);
+ AStatsEvent_addInt32Annotation(event, int32AnnotationId, int32AnnotationValue);
+ AStatsEvent_writeFloat(event, fieldValue);
+ AStatsEvent_build(event);
+ int64_t endTime = android::elapsedRealtimeNano();
+
+ size_t bufferSize;
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
+ uint8_t* bufferEnd = buffer + bufferSize;
+
+ checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId,
+ /*numAtomLevelAnnotations=*/2);
+
+ // check atom-level annotations
+ checkAnnotation(&buffer, boolAnnotationId, BOOL_TYPE, boolAnnotationValue);
+ checkAnnotation(&buffer, int32AnnotationId, INT32_TYPE, int32AnnotationValue);
+
+ // check first element
+ checkTypeHeader(&buffer, FLOAT_TYPE);
+ checkScalar(&buffer, fieldValue);
+
+ EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
TEST(StatsEventTest, TestNoAtomIdError) {
- struct stats_event* event = stats_event_obtain();
+ AStatsEvent* event = AStatsEvent_obtain();
// Don't set the atom id in order to trigger the error.
- stats_event_build(event);
+ AStatsEvent_build(event);
- uint32_t errors = stats_event_get_errors(event);
- EXPECT_NE(errors | ERROR_NO_ATOM_ID, 0);
+ uint32_t errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors & ERROR_NO_ATOM_ID, ERROR_NO_ATOM_ID);
- stats_event_release(event);
+ AStatsEvent_release(event);
}
-TEST(StatsEventTest, TestOverflowError) {
- struct stats_event* event = stats_event_obtain();
- stats_event_set_atom_id(event, 100);
- // Add 1000 int32s to the event. Each int32 takes 5 bytes so this will
+TEST(StatsEventTest, TestPushOverflowError) {
+ const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ const int writeCount = 120; // Number of times to write str in the event.
+
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
+
+ // Add str to the event 120 times. Each str takes >35 bytes so this will
// overflow the 4068 byte buffer.
- for (int i = 0; i < 1000; i++) {
- stats_event_write_int32(event, 0);
+ // We want to keep writeCount less than 127 to avoid hitting
+ // ERROR_TOO_MANY_FIELDS.
+ for (int i = 0; i < writeCount; i++) {
+ AStatsEvent_writeString(event, str);
}
- stats_event_build(event);
+ AStatsEvent_write(event);
- uint32_t errors = stats_event_get_errors(event);
- EXPECT_NE(errors | ERROR_OVERFLOW, 0);
+ uint32_t errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
- stats_event_release(event);
+ AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestPullOverflowError) {
+ const uint32_t atomId = 10100;
+ const vector<uint8_t> bytes(430 /* number of elements */, 1 /* value of each element */);
+ const int writeCount = 120; // Number of times to write bytes in the event.
+
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+
+ // Add bytes to the event 120 times. Size of bytes is 430 so this will
+ // overflow the 50 KB pulled event buffer.
+ // We want to keep writeCount less than 127 to avoid hitting
+ // ERROR_TOO_MANY_FIELDS.
+ for (int i = 0; i < writeCount; i++) {
+ AStatsEvent_writeByteArray(event, bytes.data(), bytes.size());
+ }
+ AStatsEvent_build(event);
+
+ uint32_t errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
+
+ AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestLargePull) {
+ const uint32_t atomId = 100;
+ const string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ const int writeCount = 120; // Number of times to write str in the event.
+ const int64_t startTime = android::elapsedRealtimeNano();
+
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+
+ // Add str to the event 120 times.
+ // We want to keep writeCount less than 127 to avoid hitting
+ // ERROR_TOO_MANY_FIELDS.
+ for (int i = 0; i < writeCount; i++) {
+ AStatsEvent_writeString(event, str.c_str());
+ }
+ AStatsEvent_build(event);
+ int64_t endTime = android::elapsedRealtimeNano();
+
+ size_t bufferSize;
+ uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
+ uint8_t* bufferEnd = buffer + bufferSize;
+
+ checkMetadata(&buffer, writeCount, startTime, endTime, atomId);
+
+ // Check all instances of str have been written.
+ for (int i = 0; i < writeCount; i++) {
+ checkTypeHeader(&buffer, STRING_TYPE);
+ checkString(&buffer, str);
+ }
+
+ EXPECT_EQ(buffer, bufferEnd); // Ensure that we have read the entire buffer.
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestAtomIdInvalidPositionError) {
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_writeInt32(event, 0);
+ AStatsEvent_setAtomId(event, 100);
+ AStatsEvent_writeBool(event, true);
+ AStatsEvent_build(event);
+
+ uint32_t errors = AStatsEvent_getErrors(event);
+ EXPECT_EQ(errors & ERROR_ATOM_ID_INVALID_POSITION, ERROR_ATOM_ID_INVALID_POSITION);
+
+ AStatsEvent_release(event);
+}
+
+TEST(StatsEventTest, TestOverwriteTimestamp) {
+ uint32_t atomId = 100;
+ int64_t expectedTimestamp = 0x123456789;
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, atomId);
+ AStatsEvent_overwriteTimestamp(event, expectedTimestamp);
+ AStatsEvent_build(event);
+
+ uint8_t* buffer = AStatsEvent_getBuffer(event, NULL);
+
+ // Make sure that the timestamp is being overwritten.
+ checkMetadata(&buffer, /*numElements=*/0, /*startTime=*/expectedTimestamp,
+ /*endTime=*/expectedTimestamp, atomId);
+
+ EXPECT_EQ(AStatsEvent_getErrors(event), 0);
+ AStatsEvent_release(event);
}
diff --git a/libstats/socket/tests/stats_writer_test.cpp b/libstats/socket/tests/stats_writer_test.cpp
new file mode 100644
index 0000000..749599f
--- /dev/null
+++ b/libstats/socket/tests/stats_writer_test.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2020 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 <gtest/gtest.h>
+#include "stats_buffer_writer.h"
+#include "stats_event.h"
+#include "stats_socket.h"
+
+TEST(StatsWriterTest, TestSocketClose) {
+ AStatsEvent* event = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(event, 100);
+ AStatsEvent_writeInt32(event, 5);
+ int successResult = AStatsEvent_write(event);
+ AStatsEvent_release(event);
+
+ // In the case of a successful write, we return the number of bytes written.
+ EXPECT_GT(successResult, 0);
+ EXPECT_FALSE(stats_log_is_closed());
+
+ AStatsSocket_close();
+
+ EXPECT_TRUE(stats_log_is_closed());
+}
diff --git a/libunwindstack b/libunwindstack
new file mode 120000
index 0000000..9a12403
--- /dev/null
+++ b/libunwindstack
@@ -0,0 +1 @@
+../unwinding/libunwindstack
\ No newline at end of file
diff --git a/libunwindstack/.clang-format b/libunwindstack/.clang-format
deleted file mode 120000
index fd0645f..0000000
--- a/libunwindstack/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-2
\ No newline at end of file
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
deleted file mode 100644
index 8cc780a..0000000
--- a/libunwindstack/Android.bp
+++ /dev/null
@@ -1,492 +0,0 @@
-//
-// Copyright (C) 2017 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.
-//
-
-cc_defaults {
- name: "libunwindstack_flags",
-
- host_supported: true,
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- ],
-
- target: {
- darwin: {
- enabled: false,
- },
- linux_bionic: {
- enabled: true,
- },
- },
-}
-
-cc_defaults {
- name: "libunwindstack_defaults",
- defaults: ["libunwindstack_flags"],
- export_include_dirs: ["include"],
-
- srcs: [
- "ArmExidx.cpp",
- "DexFiles.cpp",
- "DwarfCfa.cpp",
- "DwarfEhFrameWithHdr.cpp",
- "DwarfMemory.cpp",
- "DwarfOp.cpp",
- "DwarfSection.cpp",
- "Elf.cpp",
- "ElfInterface.cpp",
- "ElfInterfaceArm.cpp",
- "Global.cpp",
- "JitDebug.cpp",
- "Log.cpp",
- "MapInfo.cpp",
- "Maps.cpp",
- "Memory.cpp",
- "MemoryMte.cpp",
- "LocalUnwinder.cpp",
- "Regs.cpp",
- "RegsArm.cpp",
- "RegsArm64.cpp",
- "RegsX86.cpp",
- "RegsX86_64.cpp",
- "RegsMips.cpp",
- "RegsMips64.cpp",
- "Unwinder.cpp",
- "Symbols.cpp",
- ],
-
- cflags: [
- "-Wexit-time-destructors",
- ],
-
- target: {
- host: {
- // Always disable optimizations for host to make it easier to debug.
- cflags: [
- "-O0",
- "-g",
- ],
- },
- android: {
- header_libs: ["bionic_libc_platform_headers"],
- product_variables: {
- experimental_mte: {
- cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
- },
- },
- },
- linux_bionic: {
- header_libs: ["bionic_libc_platform_headers"],
- product_variables: {
- experimental_mte: {
- cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
- },
- },
- },
- },
-
- arch: {
- x86: {
- srcs: ["AsmGetRegsX86.S"],
- },
- x86_64: {
- srcs: ["AsmGetRegsX86_64.S"],
- },
- },
-
- static_libs: [
- "libprocinfo",
- ],
-
- shared_libs: [
- "libbase",
- "liblog",
- "liblzma",
- ],
-}
-
-cc_library {
- name: "libunwindstack",
- vendor_available: true,
- recovery_available: true,
- // TODO(b/153609531): remove when no longer needed.
- native_bridge_supported: true,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
- defaults: ["libunwindstack_defaults"],
-
- srcs: ["DexFile.cpp"],
- cflags: ["-DDEXFILE_SUPPORT"],
- shared_libs: ["libdexfile_support"],
-
- target: {
- vendor: {
- cflags: ["-UDEXFILE_SUPPORT"],
- exclude_srcs: ["DexFile.cpp"],
- exclude_shared_libs: ["libdexfile_support"],
- },
- recovery: {
- cflags: ["-UDEXFILE_SUPPORT"],
- exclude_srcs: ["DexFile.cpp"],
- exclude_shared_libs: ["libdexfile_support"],
- },
- native_bridge: {
- cflags: ["-UDEXFILE_SUPPORT"],
- exclude_srcs: ["DexFile.cpp"],
- exclude_shared_libs: ["libdexfile_support"],
- },
- },
-
- apex_available: [
- "//apex_available:platform",
- "com.android.art.debug",
- "com.android.art.release",
- ],
-}
-
-// Static library without DEX support to avoid dependencies on the ART APEX.
-cc_library_static {
- name: "libunwindstack_no_dex",
- recovery_available: true,
- defaults: ["libunwindstack_defaults"],
-
- visibility: [
- "//system/core/debuggerd",
- "//system/core/init",
- "//system/core/libbacktrace",
- ],
- apex_available: [
- "//apex_available:platform",
- "com.android.runtime",
- ],
-}
-
-//-------------------------------------------------------------------------
-// Unit Tests
-//-------------------------------------------------------------------------
-cc_test_library {
- name: "libunwindstack_local",
- defaults: ["libunwindstack_flags"],
- srcs: ["tests/TestLocal.cpp"],
-
- cflags: [
- "-O0",
- "-g",
- ],
-
- shared_libs: [
- "libunwindstack",
- ],
- relative_install_path: "libunwindstack_test",
-}
-
-cc_defaults {
- name: "libunwindstack_testlib_flags",
- defaults: ["libunwindstack_flags"],
-
- srcs: [
- "tests/ArmExidxDecodeTest.cpp",
- "tests/ArmExidxExtractTest.cpp",
- "tests/DexFileTest.cpp",
- "tests/DexFilesTest.cpp",
- "tests/DwarfCfaLogTest.cpp",
- "tests/DwarfCfaTest.cpp",
- "tests/DwarfDebugFrameTest.cpp",
- "tests/DwarfEhFrameTest.cpp",
- "tests/DwarfEhFrameWithHdrTest.cpp",
- "tests/DwarfMemoryTest.cpp",
- "tests/DwarfOpLogTest.cpp",
- "tests/DwarfOpTest.cpp",
- "tests/DwarfSectionTest.cpp",
- "tests/DwarfSectionImplTest.cpp",
- "tests/ElfCacheTest.cpp",
- "tests/ElfFake.cpp",
- "tests/ElfInterfaceArmTest.cpp",
- "tests/ElfInterfaceTest.cpp",
- "tests/ElfTest.cpp",
- "tests/ElfTestUtils.cpp",
- "tests/IsolatedSettings.cpp",
- "tests/JitDebugTest.cpp",
- "tests/LocalUpdatableMapsTest.cpp",
- "tests/LogFake.cpp",
- "tests/MapInfoCreateMemoryTest.cpp",
- "tests/MapInfoGetBuildIDTest.cpp",
- "tests/MapInfoGetElfTest.cpp",
- "tests/MapInfoGetLoadBiasTest.cpp",
- "tests/MapInfoTest.cpp",
- "tests/MapsTest.cpp",
- "tests/MemoryBufferTest.cpp",
- "tests/MemoryCacheTest.cpp",
- "tests/MemoryFake.cpp",
- "tests/MemoryFileTest.cpp",
- "tests/MemoryLocalTest.cpp",
- "tests/MemoryOfflineBufferTest.cpp",
- "tests/MemoryOfflineTest.cpp",
- "tests/MemoryRangeTest.cpp",
- "tests/MemoryRangesTest.cpp",
- "tests/MemoryRemoteTest.cpp",
- "tests/MemoryTest.cpp",
- "tests/MemoryMteTest.cpp",
- "tests/RegsInfoTest.cpp",
- "tests/RegsIterateTest.cpp",
- "tests/RegsStepIfSignalHandlerTest.cpp",
- "tests/RegsTest.cpp",
- "tests/SymbolsTest.cpp",
- "tests/TestUtils.cpp",
- "tests/UnwindOfflineTest.cpp",
- "tests/UnwindTest.cpp",
- "tests/UnwinderTest.cpp",
- "tests/VerifyBionicTerminationTest.cpp",
- ],
-
- cflags: [
- "-O0",
- "-g",
- ],
-
- shared_libs: [
- "libbase",
- "liblog",
- "liblzma",
- "libunwindstack",
- "libdexfile_support",
- ],
-
- static_libs: [
- "libgmock",
- ],
-
- test_suites: ["device-tests"],
- data: [
- "tests/files/elf32.xz",
- "tests/files/elf64.xz",
- "tests/files/offline/art_quick_osr_stub_arm/*",
- "tests/files/offline/bad_eh_frame_hdr_arm64/*",
- "tests/files/offline/debug_frame_first_x86/*",
- "tests/files/offline/debug_frame_load_bias_arm/*",
- "tests/files/offline/eh_frame_bias_x86/*",
- "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
- "tests/files/offline/empty_arm64/*",
- "tests/files/offline/invalid_elf_offset_arm/*",
- "tests/files/offline/jit_debug_arm/*",
- "tests/files/offline/jit_debug_x86/*",
- "tests/files/offline/jit_map_arm/*",
- "tests/files/offline/gnu_debugdata_arm/*",
- "tests/files/offline/load_bias_different_section_bias_arm64/*",
- "tests/files/offline/load_bias_ro_rx_x86_64/*",
- "tests/files/offline/offset_arm/*",
- "tests/files/offline/shared_lib_in_apk_arm64/*",
- "tests/files/offline/shared_lib_in_apk_memory_only_arm64/*",
- "tests/files/offline/shared_lib_in_apk_single_map_arm64/*",
- "tests/files/offline/signal_load_bias_arm/*",
- "tests/files/offline/straddle_arm/*",
- "tests/files/offline/straddle_arm64/*",
- ],
-
- target: {
- android: {
- header_libs: ["bionic_libc_platform_headers"],
- product_variables: {
- experimental_mte: {
- cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
- },
- },
- },
- linux_bionic: {
- header_libs: ["bionic_libc_platform_headers"],
- product_variables: {
- experimental_mte: {
- cflags: ["-DANDROID_EXPERIMENTAL_MTE"],
- },
- },
- },
- },
-}
-
-cc_test {
- name: "libunwindstack_test",
- defaults: ["libunwindstack_testlib_flags"],
- isolated: true,
-
- srcs: [
- "tests/LocalUnwinderTest.cpp",
- ],
- required: [
- "libunwindstack_local",
- ],
-}
-
-// Skip LocalUnwinderTest until atest understands required properly.
-cc_test {
- name: "libunwindstack_unit_test",
- defaults: ["libunwindstack_testlib_flags"],
- isolated: true,
-}
-
-//-------------------------------------------------------------------------
-// Fuzzers
-//-------------------------------------------------------------------------
-cc_defaults {
- name: "libunwindstack_fuzz_defaults",
- host_supported: true,
- defaults: ["libunwindstack_flags"],
- cflags: [
- "-Wno-exit-time-destructors",
- "-g",
- ],
- shared_libs: [
- "libbase",
- "liblog",
- "liblzma",
- "libunwindstack",
- "libdexfile_support",
- ],
-}
-
-cc_fuzz {
- name: "libunwindstack_fuzz_unwinder",
- defaults: ["libunwindstack_fuzz_defaults"],
- srcs: [
- "tests/MemoryFake.cpp",
- "tests/ElfFake.cpp",
- "tests/fuzz/UnwinderComponentCreator.cpp",
- "tests/fuzz/UnwinderFuzz.cpp",
- ],
-}
-
-//-------------------------------------------------------------------------
-// Tools
-//-------------------------------------------------------------------------
-cc_defaults {
- name: "libunwindstack_tools",
- defaults: ["libunwindstack_flags"],
-
- shared_libs: [
- "libunwindstack",
- "libbase",
- "liblzma",
- ],
- target: {
- // Always disable optimizations for host to make it easier to debug.
- host: {
- cflags: [
- "-O0",
- "-g",
- ],
- },
- },
-}
-
-cc_binary {
- name: "unwind",
- defaults: ["libunwindstack_tools"],
-
- srcs: [
- "tools/unwind.cpp",
- ],
-}
-
-cc_binary {
- name: "unwind_info",
- defaults: ["libunwindstack_tools"],
-
- srcs: [
- "tools/unwind_info.cpp",
- ],
-}
-
-cc_binary {
- name: "unwind_symbols",
- defaults: ["libunwindstack_tools"],
-
- srcs: [
- "tools/unwind_symbols.cpp",
- ],
-}
-
-cc_binary {
- name: "unwind_for_offline",
- defaults: ["libunwindstack_tools"],
-
- srcs: [
- "tools/unwind_for_offline.cpp",
- ],
-}
-
-cc_binary {
- name: "unwind_reg_info",
- defaults: ["libunwindstack_tools"],
-
- srcs: [
- "tools/unwind_reg_info.cpp",
- ],
-}
-
-//-------------------------------------------------------------------------
-// Benchmarks
-//-------------------------------------------------------------------------
-cc_benchmark {
- name: "unwind_benchmarks",
- host_supported: true,
- defaults: ["libunwindstack_flags"],
-
- // Disable optimizations so that all of the calls are not optimized away.
- cflags: [
- "-O0",
- ],
-
- srcs: [
- "benchmarks/unwind_benchmarks.cpp",
- "benchmarks/ElfBenchmark.cpp",
- "benchmarks/MapsBenchmark.cpp",
- "benchmarks/SymbolBenchmark.cpp",
- "benchmarks/Utils.cpp",
- ],
-
- data: [
- "benchmarks/files/*",
- ],
-
- shared_libs: [
- "libbase",
- "libunwindstack",
- ],
-
- target: {
- android: {
- static_libs: [
- "libmeminfo",
- "libprocinfo",
- ],
- },
- },
-}
-
-// Generates the elf data for use in the tests for .gnu_debugdata frames.
-// Once these files are generated, use the xz command to compress the data.
-cc_binary_host {
- name: "gen_gnudebugdata",
- defaults: ["libunwindstack_flags"],
-
- srcs: [
- "tests/GenGnuDebugdata.cpp",
- ],
-}
-
diff --git a/libunwindstack/AndroidVersions.md b/libunwindstack/AndroidVersions.md
deleted file mode 100644
index 234f639..0000000
--- a/libunwindstack/AndroidVersions.md
+++ /dev/null
@@ -1,116 +0,0 @@
-# Unwinder Support Per Android Release
-This document describes the changes in the way the libunwindstack
-unwinder works on different Android versions. It does not describe
-every change in the code made between different versions, but is
-meant to allow an app developer to know what might be supported
-on different versions. It also describes the different way an unwind
-will display on different versions of Android.
-
-## Android P
-libunwindstack was first introduced in Android P.
-
-* Supports up to and including Dwarf 4 unwinding information.
- See http://dwarfstd.org/ for Dwarf standards.
-* Supports Arm exidx unwinding.
-* Supports the gdb JIT unwinding interface, which is how ART creates unwinding
- information for the JIT'd Java frames.
-* Supports special frames added to represent an ART Java interpreter frame.
- ART has marked the dex pc using cfi information that the unwinder
- understands and handles by adding a new frame in the stacktrace.
-
-## Note
-By default, lld creates two separate maps of the elf in memory, one read-only
-and one read/executable. The libunwindstack on P and the unwinder on older
-versions of Android will not unwind properly in this case. For apps that
-target Android P or older, make sure that `-Wl,--no-rosegment` is
-included in linker arguments when using lld.
-
-## Android Q
-* Fix bug (b/109824792) that handled load bias data incorrectly when
- FDEs use pc relative addressing in the eh\_frame\_hdr.
- Unfortunately, this wasn't fixed correctly in Q since it assumes
- that the bias is coming from the program header for the executable
- load. The real fix was to use the bias from the actual section data and
- is not completely fixed until Android R. For apps targeting Android Q,
- if it is being compiled with the llvm linker lld, it might be necessary
- to add the linker option `-Wl,-zseparate-code` to avoid creating an elf
- created this way.
-* Change the way the exidx section offset is found (b/110704153). Before
- the p\_vaddr value from the program header minus the load bias was used
- to find the start of the exidx data. Changed to use the p\_offset since
- it doesn't require any load bias manipulations.
-* Fix bug handling of dwarf sections without any header (b/110235461).
- Previously, the code assumed that FDEs are non-overlapping, and the FDEs
- are always in sorted order from low pc to high pc. Thus the code would
- read the entire set of CIEs/FDEs and then do a binary search to find
- the appropriate FDE for a given pc. Now the code does a sequential read
- and stops when it finds the FDE for a pc. It also understands the
- overlapping FDEs, so find the first FDE that matches a pc. In practice,
- elf files with this format only ever occurs if the file was generated
- without an eh\_frame/eh\_frame\_hdr section and only a debug\_frame. The
- other way this has been observed is when running simpleperf to unwind since
- sometimes there is not enough information in the eh\_frame for all points
- in the executable. On Android P, this would result in some incorrect
- unwinds coming from simpleperf. Nearly all crashes from Android P should
- be correct since the eh\_frame information was enough to do the unwind
- properly.
-* Be permissive of badly formed elf files. Previously, any detected error
- would result in unwinds stopping even if there is enough valid information
- to do an unwind.
- * The code now allows program header/section header offsets to point
- to unreadable memory. As long as the code can find the unwind tables,
- that is good enough.
- * The code allows program headers/section headers to be missing.
- * Allow a symbol table section header to point to invalid symbol table
- values.
-* Support for the linker read-only segment option (b/109657296).
- This is a feature of lld whereby there are two sections that
- contain elf data. The first is read-only and contains the elf header data,
- and the second is read-execute or execute only that
- contains the executable code from the elf. Before this, the unwinder
- always assumed that there was only a single read-execute section that
- contained the elf header data and the executable code.
-* Build ID information for elf objects added. This will display the
- NT\_GNU\_BUILD\_ID note found in elf files. This information can be used
- to identify the exact version of a shared library to help get symbol
- information when looking at a crash.
-* Add support for displaying the soname from an apk frame. Previously,
- a frame map name would be only the apk, but now if the shared library
- in the apk has set a soname, the map name will be `app.apk!libexample.so`
- instead of only `app.apk`.
-* Minimal support for Dwarf 5. This merely treats a Dwarf 5 version
- elf file as Dwarf 4. It does not support the new dwarf ops in Dwarf 5.
- Since the new ops are not likely to be used very often, this allows
- continuing to unwind even when encountering Dwarf 5 elf files.
-* Fix bug in pc handling of signal frames (b/130302288). In the previous
- version, the pc would be wrong in the signal frame. The rest of the
- unwind was correct, only the frame in the signal handler was incorrect
- in Android P.
-* Detect when an elf file is not readable so that a message can be
- displayed indicating that. This can happen when an app puts the shared
- libraries in non-standard locations that are not readable due to
- security restrictions (selinux rules).
-
-## Android R
-* Display the offsets for Java interpreter frames. If this frame came
- from a non-zero offset map, no offset is printed. Previously, the
- line would look like:
-
- #17 pc 00500d7a GoogleCamera.apk (com.google.camera.AndroidPriorityThread.run+10)
-
- to:
-
- #17 pc 00500d7a GoogleCamera.apk (offset 0x11d0000) (com.google.camera.AndroidPriorityThread.run+10)
-* Fix bug where the load bias was set from the first PT\_LOAD program
- header that has a zero p\_offset value. Now it is set from the first
- executable PT\_LOAD program header. This has only ever been a problem
- for host executables compiled for the x86\_64 architecture.
-* Switched to the libc++ demangler for function names. Previously, the
- demangler used was not complete, so some less common demangled function
- names would not be properly demangled or the function name would not be
- demangled at all.
-* Fix bug in load bias handling. If the unwind information in the eh\_frame
- or eh\_frame\_hdr does not have the same bias as the executable section,
- and uses pc relative FDEs, the unwind will be incorrect. This tends
- to truncate unwinds since the unwinder could not find the correct unwind
- information for a given pc.
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
deleted file mode 100644
index 818f5d1..0000000
--- a/libunwindstack/ArmExidx.cpp
+++ /dev/null
@@ -1,862 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <deque>
-#include <string>
-
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/Log.h>
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsArm.h>
-
-#include "ArmExidx.h"
-#include "Check.h"
-
-namespace unwindstack {
-
-static constexpr uint8_t LOG_CFA_REG = 64;
-
-void ArmExidx::LogRawData() {
- std::string log_str("Raw Data:");
- for (const uint8_t data : data_) {
- log_str += android::base::StringPrintf(" 0x%02x", data);
- }
- log(log_indent_, log_str.c_str());
-}
-
-bool ArmExidx::ExtractEntryData(uint32_t entry_offset) {
- data_.clear();
- status_ = ARM_STATUS_NONE;
-
- if (entry_offset & 1) {
- // The offset needs to be at least two byte aligned.
- status_ = ARM_STATUS_INVALID_ALIGNMENT;
- return false;
- }
-
- // Each entry is a 32 bit prel31 offset followed by 32 bits
- // of unwind information. If bit 31 of the unwind data is zero,
- // then this is a prel31 offset to the start of the unwind data.
- // If the unwind data is 1, then this is a cant unwind entry.
- // Otherwise, this data is the compact form of the unwind information.
- uint32_t data;
- if (!elf_memory_->Read32(entry_offset + 4, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = entry_offset + 4;
- return false;
- }
- if (data == 1) {
- // This is a CANT UNWIND entry.
- status_ = ARM_STATUS_NO_UNWIND;
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "Raw Data: 0x00 0x00 0x00 0x01");
- }
- log(log_indent_, "[cantunwind]");
- }
- return false;
- }
-
- if (data & (1UL << 31)) {
- // This is a compact table entry.
- if ((data >> 24) & 0xf) {
- // This is a non-zero index, this code doesn't support
- // other formats.
- status_ = ARM_STATUS_INVALID_PERSONALITY;
- return false;
- }
- data_.push_back((data >> 16) & 0xff);
- data_.push_back((data >> 8) & 0xff);
- uint8_t last_op = data & 0xff;
- data_.push_back(last_op);
- if (last_op != ARM_OP_FINISH) {
- // If this didn't end with a finish op, add one.
- data_.push_back(ARM_OP_FINISH);
- }
- if (log_type_ == ARM_LOG_FULL) {
- LogRawData();
- }
- return true;
- }
-
- // Get the address of the ops.
- // Sign extend the data value if necessary.
- int32_t signed_data = static_cast<int32_t>(data << 1) >> 1;
- uint32_t addr = (entry_offset + 4) + signed_data;
- if (!elf_memory_->Read32(addr, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = addr;
- return false;
- }
-
- size_t num_table_words;
- if (data & (1UL << 31)) {
- // Compact model.
- switch ((data >> 24) & 0xf) {
- case 0:
- num_table_words = 0;
- data_.push_back((data >> 16) & 0xff);
- break;
- case 1:
- case 2:
- num_table_words = (data >> 16) & 0xff;
- addr += 4;
- break;
- default:
- // Only a personality of 0, 1, 2 is valid.
- status_ = ARM_STATUS_INVALID_PERSONALITY;
- return false;
- }
- data_.push_back((data >> 8) & 0xff);
- data_.push_back(data & 0xff);
- } else {
- // Generic model.
-
- // Skip the personality routine data, it doesn't contain any data
- // needed to decode the unwind information.
- addr += 4;
- if (!elf_memory_->Read32(addr, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = addr;
- return false;
- }
- num_table_words = (data >> 24) & 0xff;
- data_.push_back((data >> 16) & 0xff);
- data_.push_back((data >> 8) & 0xff);
- data_.push_back(data & 0xff);
- addr += 4;
- }
-
- if (num_table_words > 5) {
- status_ = ARM_STATUS_MALFORMED;
- return false;
- }
-
- for (size_t i = 0; i < num_table_words; i++) {
- if (!elf_memory_->Read32(addr, &data)) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = addr;
- return false;
- }
- data_.push_back((data >> 24) & 0xff);
- data_.push_back((data >> 16) & 0xff);
- data_.push_back((data >> 8) & 0xff);
- data_.push_back(data & 0xff);
- addr += 4;
- }
-
- if (data_.back() != ARM_OP_FINISH) {
- // If this didn't end with a finish op, add one.
- data_.push_back(ARM_OP_FINISH);
- }
-
- if (log_type_ == ARM_LOG_FULL) {
- LogRawData();
- }
- return true;
-}
-
-inline bool ArmExidx::GetByte(uint8_t* byte) {
- if (data_.empty()) {
- status_ = ARM_STATUS_TRUNCATED;
- return false;
- }
- *byte = data_.front();
- data_.pop_front();
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_10_00(uint8_t byte) {
- CHECK((byte >> 4) == 0x8);
-
- uint16_t registers = (byte & 0xf) << 8;
- if (!GetByte(&byte)) {
- return false;
- }
-
- registers |= byte;
- if (registers == 0) {
- // 10000000 00000000: Refuse to unwind
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Refuse to unwind");
- }
- status_ = ARM_STATUS_NO_UNWIND;
- return false;
- }
- // 1000iiii iiiiiiii: Pop up to 12 integer registers under masks {r15-r12}, {r11-r4}
- registers <<= 4;
-
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- bool add_comma = false;
- std::string msg = "pop {";
- for (size_t reg = 4; reg < 16; reg++) {
- if (registers & (1 << reg)) {
- if (add_comma) {
- msg += ", ";
- }
- msg += android::base::StringPrintf("r%zu", reg);
- add_comma = true;
- }
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- uint32_t cfa_offset = __builtin_popcount(registers) * 4;
- log_cfa_offset_ += cfa_offset;
- for (size_t reg = 4; reg < 16; reg++) {
- if (registers & (1 << reg)) {
- log_regs_[reg] = cfa_offset;
- cfa_offset -= 4;
- }
- }
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
-
- for (size_t reg = 4; reg < 16; reg++) {
- if (registers & (1 << reg)) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- }
-
- // If the sp register is modified, change the cfa value.
- if (registers & (1 << ARM_REG_SP)) {
- cfa_ = (*regs_)[ARM_REG_SP];
- }
-
- // Indicate if the pc register was set.
- if (registers & (1 << ARM_REG_PC)) {
- pc_set_ = true;
- }
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_10_01(uint8_t byte) {
- CHECK((byte >> 4) == 0x9);
-
- uint8_t bits = byte & 0xf;
- if (bits == 13 || bits == 15) {
- // 10011101: Reserved as prefix for ARM register to register moves
- // 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "[Reserved]");
- }
- status_ = ARM_STATUS_RESERVED;
- return false;
- }
- // 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = r%d", bits);
- } else {
- log_regs_[LOG_CFA_REG] = bits;
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- // It is impossible for bits to be larger than the total number of
- // arm registers, so don't bother checking if bits is a valid register.
- cfa_ = (*regs_)[bits];
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_10_10(uint8_t byte) {
- CHECK((byte >> 4) == 0xa);
-
- // 10100nnn: Pop r4-r[4+nnn]
- // 10101nnn: Pop r4-r[4+nnn], r14
- if (log_type_ != ARM_LOG_NONE) {
- uint8_t end_reg = byte & 0x7;
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = "pop {r4";
- if (end_reg) {
- msg += android::base::StringPrintf("-r%d", 4 + end_reg);
- }
- if (byte & 0x8) {
- log(log_indent_, "%s, r14}", msg.c_str());
- } else {
- log(log_indent_, "%s}", msg.c_str());
- }
- } else {
- end_reg += 4;
- uint32_t cfa_offset = (end_reg - 3) * 4;
- if (byte & 0x8) {
- cfa_offset += 4;
- }
- log_cfa_offset_ += cfa_offset;
-
- for (uint8_t reg = 4; reg <= end_reg; reg++) {
- log_regs_[reg] = cfa_offset;
- cfa_offset -= 4;
- }
-
- if (byte & 0x8) {
- log_regs_[14] = cfa_offset;
- }
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
-
- for (size_t i = 4; i <= 4 + (byte & 0x7); i++) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[i])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- if (byte & 0x8) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[ARM_REG_R14])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_10_11_0000() {
- // 10110000: Finish
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "finish");
- }
-
- if (log_skip_execution_) {
- status_ = ARM_STATUS_FINISH;
- return false;
- }
- }
- status_ = ARM_STATUS_FINISH;
- return false;
-}
-
-inline bool ArmExidx::DecodePrefix_10_11_0001() {
- uint8_t byte;
- if (!GetByte(&byte)) {
- return false;
- }
-
- if (byte == 0) {
- // 10110001 00000000: Spare
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- if (byte >> 4) {
- // 10110001 xxxxyyyy: Spare (xxxx != 0000)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
-
- // 10110001 0000iiii: Pop integer registers under mask {r3, r2, r1, r0}
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- bool add_comma = false;
- std::string msg = "pop {";
- for (size_t i = 0; i < 4; i++) {
- if (byte & (1 << i)) {
- if (add_comma) {
- msg += ", ";
- }
- msg += android::base::StringPrintf("r%zu", i);
- add_comma = true;
- }
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- byte &= 0xf;
- uint32_t cfa_offset = __builtin_popcount(byte) * 4;
- log_cfa_offset_ += cfa_offset;
- for (size_t reg = 0; reg < 4; reg++) {
- if (byte & (1 << reg)) {
- log_regs_[reg] = cfa_offset;
- cfa_offset -= 4;
- }
- }
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
-
- for (size_t reg = 0; reg < 4; reg++) {
- if (byte & (1 << reg)) {
- if (!process_memory_->Read32(cfa_, &(*regs_)[reg])) {
- status_ = ARM_STATUS_READ_FAILED;
- status_address_ = cfa_;
- return false;
- }
- cfa_ += 4;
- }
- }
- return true;
-}
-
-inline void ArmExidx::AdjustRegisters(int32_t offset) {
- for (auto& entry : log_regs_) {
- if (entry.first >= LOG_CFA_REG) {
- break;
- }
- entry.second += offset;
- }
-}
-
-inline bool ArmExidx::DecodePrefix_10_11_0010() {
- // 10110010 uleb128: vsp = vsp + 0x204 + (uleb128 << 2)
- uint32_t result = 0;
- uint32_t shift = 0;
- uint8_t byte;
- do {
- if (!GetByte(&byte)) {
- return false;
- }
-
- result |= (byte & 0x7f) << shift;
- shift += 7;
- } while (byte & 0x80);
- result <<= 2;
- if (log_type_ != ARM_LOG_NONE) {
- int32_t cfa_offset = 0x204 + result;
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = vsp + %d", cfa_offset);
- } else {
- log_cfa_offset_ += cfa_offset;
- }
- AdjustRegisters(cfa_offset);
-
- if (log_skip_execution_) {
- return true;
- }
- }
- cfa_ += 0x204 + result;
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_10_11_0011() {
- // 10110011 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX
- uint8_t byte;
- if (!GetByte(&byte)) {
- return false;
- }
-
- if (log_type_ != ARM_LOG_NONE) {
- uint8_t start_reg = byte >> 4;
- uint8_t end_reg = start_reg + (byte & 0xf);
-
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- cfa_ += (byte & 0xf) * 8 + 12;
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_10_11_01nn() {
- // 101101nn: Spare
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
-}
-
-inline bool ArmExidx::DecodePrefix_10_11_1nnn(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xb8);
-
- // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t last_reg = (byte & 0x7);
- std::string msg = "pop {d8";
- if (last_reg) {
- msg += android::base::StringPrintf("-d%d", last_reg + 8);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0x7) * 8 + 12;
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_10(uint8_t byte) {
- CHECK((byte >> 6) == 0x2);
-
- switch ((byte >> 4) & 0x3) {
- case 0:
- return DecodePrefix_10_00(byte);
- case 1:
- return DecodePrefix_10_01(byte);
- case 2:
- return DecodePrefix_10_10(byte);
- default:
- switch (byte & 0xf) {
- case 0:
- return DecodePrefix_10_11_0000();
- case 1:
- return DecodePrefix_10_11_0001();
- case 2:
- return DecodePrefix_10_11_0010();
- case 3:
- return DecodePrefix_10_11_0011();
- default:
- if (byte & 0x8) {
- return DecodePrefix_10_11_1nnn(byte);
- } else {
- return DecodePrefix_10_11_01nn();
- }
- }
- }
-}
-
-inline bool ArmExidx::DecodePrefix_11_000(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xc0);
-
- uint8_t bits = byte & 0x7;
- if (bits == 6) {
- if (!GetByte(&byte)) {
- return false;
- }
-
- // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t start_reg = byte >> 4;
- std::string msg = android::base::StringPrintf("pop {wR%d", start_reg);
- uint8_t end_reg = byte & 0xf;
- if (end_reg) {
- msg += android::base::StringPrintf("-wR%d", start_reg + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported wRX register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0xf) * 8 + 8;
- } else if (bits == 7) {
- if (!GetByte(&byte)) {
- return false;
- }
-
- if (byte == 0) {
- // 11000111 00000000: Spare
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- } else if ((byte >> 4) == 0) {
- // 11000111 0000iiii: Intel Wireless MMX pop wCGR registers {wCGR0,1,2,3}
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- bool add_comma = false;
- std::string msg = "pop {";
- for (size_t i = 0; i < 4; i++) {
- if (byte & (1 << i)) {
- if (add_comma) {
- msg += ", ";
- }
- msg += android::base::StringPrintf("wCGR%zu", i);
- add_comma = true;
- }
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported wCGR register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += __builtin_popcount(byte) * 4;
- } else {
- // 11000111 xxxxyyyy: Spare (xxxx != 0000)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- } else {
- // 11000nnn: Intel Wireless MMX pop wR[10]-wR[10+nnn] (nnn != 6, 7)
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = "pop {wR10";
- uint8_t nnn = byte & 0x7;
- if (nnn) {
- msg += android::base::StringPrintf("-wR%d", 10 + nnn);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported wRX register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0x7) * 8 + 8;
- }
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_11_001(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xc8);
-
- uint8_t bits = byte & 0x7;
- if (bits == 0) {
- // 11001000 sssscccc: Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] by VPUSH
- if (!GetByte(&byte)) {
- return false;
- }
-
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t start_reg = byte >> 4;
- std::string msg = android::base::StringPrintf("pop {d%d", 16 + start_reg);
- uint8_t end_reg = byte & 0xf;
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", 16 + start_reg + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0xf) * 8 + 8;
- } else if (bits == 1) {
- // 11001001 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by VPUSH
- if (!GetByte(&byte)) {
- return false;
- }
-
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- uint8_t start_reg = byte >> 4;
- std::string msg = android::base::StringPrintf("pop {d%d", start_reg);
- uint8_t end_reg = byte & 0xf;
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", start_reg + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- // Only update the cfa.
- cfa_ += (byte & 0xf) * 8 + 8;
- } else {
- // 11001yyy: Spare (yyy != 000, 001)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_11_010(uint8_t byte) {
- CHECK((byte & ~0x07) == 0xd0);
-
- // 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
- if (log_type_ != ARM_LOG_NONE) {
- if (log_type_ == ARM_LOG_FULL) {
- std::string msg = "pop {d8";
- uint8_t end_reg = byte & 0x7;
- if (end_reg) {
- msg += android::base::StringPrintf("-d%d", 8 + end_reg);
- }
- log(log_indent_, "%s}", msg.c_str());
- } else {
- log(log_indent_, "Unsupported DX register display");
- }
-
- if (log_skip_execution_) {
- return true;
- }
- }
- cfa_ += (byte & 0x7) * 8 + 8;
- return true;
-}
-
-inline bool ArmExidx::DecodePrefix_11(uint8_t byte) {
- CHECK((byte >> 6) == 0x3);
-
- switch ((byte >> 3) & 0x7) {
- case 0:
- return DecodePrefix_11_000(byte);
- case 1:
- return DecodePrefix_11_001(byte);
- case 2:
- return DecodePrefix_11_010(byte);
- default:
- // 11xxxyyy: Spare (xxx != 000, 001, 010)
- if (log_type_ != ARM_LOG_NONE) {
- log(log_indent_, "Spare");
- }
- status_ = ARM_STATUS_SPARE;
- return false;
- }
-}
-
-bool ArmExidx::Decode() {
- status_ = ARM_STATUS_NONE;
- uint8_t byte;
- if (!GetByte(&byte)) {
- return false;
- }
-
- switch (byte >> 6) {
- case 0:
- // 00xxxxxx: vsp = vsp + (xxxxxxx << 2) + 4
- if (log_type_ != ARM_LOG_NONE) {
- int32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = vsp + %d", cfa_offset);
- } else {
- log_cfa_offset_ += cfa_offset;
- }
- AdjustRegisters(cfa_offset);
-
- if (log_skip_execution_) {
- break;
- }
- }
- cfa_ += ((byte & 0x3f) << 2) + 4;
- break;
- case 1:
- // 01xxxxxx: vsp = vsp - (xxxxxxx << 2) + 4
- if (log_type_ != ARM_LOG_NONE) {
- uint32_t cfa_offset = ((byte & 0x3f) << 2) + 4;
- if (log_type_ == ARM_LOG_FULL) {
- log(log_indent_, "vsp = vsp - %d", cfa_offset);
- } else {
- log_cfa_offset_ -= cfa_offset;
- }
- AdjustRegisters(-cfa_offset);
-
- if (log_skip_execution_) {
- break;
- }
- }
- cfa_ -= ((byte & 0x3f) << 2) + 4;
- break;
- case 2:
- return DecodePrefix_10(byte);
- default:
- return DecodePrefix_11(byte);
- }
- return true;
-}
-
-bool ArmExidx::Eval() {
- pc_set_ = false;
- while (Decode());
- return status_ == ARM_STATUS_FINISH;
-}
-
-void ArmExidx::LogByReg() {
- if (log_type_ != ARM_LOG_BY_REG) {
- return;
- }
-
- uint8_t cfa_reg;
- if (log_regs_.count(LOG_CFA_REG) == 0) {
- cfa_reg = 13;
- } else {
- cfa_reg = log_regs_[LOG_CFA_REG];
- }
-
- if (log_cfa_offset_ != 0) {
- char sign = (log_cfa_offset_ > 0) ? '+' : '-';
- log(log_indent_, "cfa = r%zu %c %d", cfa_reg, sign, abs(log_cfa_offset_));
- } else {
- log(log_indent_, "cfa = r%zu", cfa_reg);
- }
-
- for (const auto& entry : log_regs_) {
- if (entry.first >= LOG_CFA_REG) {
- break;
- }
- if (entry.second == 0) {
- log(log_indent_, "r%zu = [cfa]", entry.first);
- } else {
- char sign = (entry.second > 0) ? '-' : '+';
- log(log_indent_, "r%zu = [cfa %c %d]", entry.first, sign, abs(entry.second));
- }
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/ArmExidx.h b/libunwindstack/ArmExidx.h
deleted file mode 100644
index d9fc371..0000000
--- a/libunwindstack/ArmExidx.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_ARM_EXIDX_H
-#define _LIBUNWINDSTACK_ARM_EXIDX_H
-
-#include <stdint.h>
-
-#include <deque>
-#include <map>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-class RegsArm;
-
-enum ArmStatus : size_t {
- ARM_STATUS_NONE = 0,
- ARM_STATUS_NO_UNWIND,
- ARM_STATUS_FINISH,
- ARM_STATUS_RESERVED,
- ARM_STATUS_SPARE,
- ARM_STATUS_TRUNCATED,
- ARM_STATUS_READ_FAILED,
- ARM_STATUS_MALFORMED,
- ARM_STATUS_INVALID_ALIGNMENT,
- ARM_STATUS_INVALID_PERSONALITY,
-};
-
-enum ArmOp : uint8_t {
- ARM_OP_FINISH = 0xb0,
-};
-
-enum ArmLogType : uint8_t {
- ARM_LOG_NONE,
- ARM_LOG_FULL,
- ARM_LOG_BY_REG,
-};
-
-class ArmExidx {
- public:
- ArmExidx(RegsArm* regs, Memory* elf_memory, Memory* process_memory)
- : regs_(regs), elf_memory_(elf_memory), process_memory_(process_memory) {}
- virtual ~ArmExidx() {}
-
- void LogRawData();
-
- void LogByReg();
-
- bool ExtractEntryData(uint32_t entry_offset);
-
- bool Eval();
-
- bool Decode();
-
- std::deque<uint8_t>* data() { return &data_; }
-
- ArmStatus status() { return status_; }
- uint64_t status_address() { return status_address_; }
-
- RegsArm* regs() { return regs_; }
-
- uint32_t cfa() { return cfa_; }
- void set_cfa(uint32_t cfa) { cfa_ = cfa; }
-
- bool pc_set() { return pc_set_; }
- void set_pc_set(bool pc_set) { pc_set_ = pc_set; }
-
- void set_log(ArmLogType log_type) { log_type_ = log_type; }
- void set_log_skip_execution(bool skip_execution) { log_skip_execution_ = skip_execution; }
- void set_log_indent(uint8_t indent) { log_indent_ = indent; }
-
- private:
- bool GetByte(uint8_t* byte);
- void AdjustRegisters(int32_t offset);
-
- bool DecodePrefix_10_00(uint8_t byte);
- bool DecodePrefix_10_01(uint8_t byte);
- bool DecodePrefix_10_10(uint8_t byte);
- bool DecodePrefix_10_11_0000();
- bool DecodePrefix_10_11_0001();
- bool DecodePrefix_10_11_0010();
- bool DecodePrefix_10_11_0011();
- bool DecodePrefix_10_11_01nn();
- bool DecodePrefix_10_11_1nnn(uint8_t byte);
- bool DecodePrefix_10(uint8_t byte);
-
- bool DecodePrefix_11_000(uint8_t byte);
- bool DecodePrefix_11_001(uint8_t byte);
- bool DecodePrefix_11_010(uint8_t byte);
- bool DecodePrefix_11(uint8_t byte);
-
- RegsArm* regs_ = nullptr;
- uint32_t cfa_ = 0;
- std::deque<uint8_t> data_;
- ArmStatus status_ = ARM_STATUS_NONE;
- uint64_t status_address_ = 0;
-
- Memory* elf_memory_;
- Memory* process_memory_;
-
- ArmLogType log_type_ = ARM_LOG_NONE;
- uint8_t log_indent_ = 0;
- bool log_skip_execution_ = false;
- bool pc_set_ = false;
- int32_t log_cfa_offset_ = 0;
- std::map<uint8_t, int32_t> log_regs_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ARM_EXIDX_H
diff --git a/libunwindstack/AsmGetRegsX86.S b/libunwindstack/AsmGetRegsX86.S
deleted file mode 100644
index 021e628..0000000
--- a/libunwindstack/AsmGetRegsX86.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- .text
- .global AsmGetRegs
- .balign 16
- .type AsmGetRegs, @function
-AsmGetRegs:
- .cfi_startproc
- mov 4(%esp), %eax
- movl $0, (%eax)
- movl %ecx, 4(%eax)
- movl %edx, 8(%eax)
- movl %ebx, 12(%eax)
-
- /* ESP */
- leal 4(%esp), %ecx
- movl %ecx, 16(%eax)
-
- movl %ebp, 20(%eax)
- movl %esi, 24(%eax)
- movl %edi, 28(%eax)
-
- /* EIP */
- movl (%esp), %ecx
- movl %ecx, 32(%eax)
-
- mov %cs, 36(%eax)
- mov %ss, 40(%eax)
- mov %ds, 44(%eax)
- mov %es, 48(%eax)
- mov %fs, 52(%eax)
- mov %gs, 56(%eax)
- ret
-
- .cfi_endproc
- .size AsmGetRegs, .-AsmGetRegs
diff --git a/libunwindstack/AsmGetRegsX86_64.S b/libunwindstack/AsmGetRegsX86_64.S
deleted file mode 100644
index 4cd3b6f..0000000
--- a/libunwindstack/AsmGetRegsX86_64.S
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
- .text
- .global AsmGetRegs
- .balign 16
- .type AsmGetRegs, @function
-AsmGetRegs:
- .cfi_startproc
- movq %rax, (%rdi)
- movq %rdx, 8(%rdi)
- movq %rcx, 16(%rdi)
- movq %rbx, 24(%rdi)
- movq %rsi, 32(%rdi)
- movq %rdi, 40(%rdi)
- movq %rbp, 48(%rdi)
-
- /* RSP */
- lea 8(%rsp), %rax
- movq %rax, 56(%rdi)
-
- movq %r8, 64(%rdi)
- movq %r9, 72(%rdi)
- movq %r10, 80(%rdi)
- movq %r11, 88(%rdi)
- movq %r12, 96(%rdi)
- movq %r13, 104(%rdi)
- movq %r14, 112(%rdi)
- movq %r15, 120(%rdi)
-
- /* RIP */
- movq (%rsp), %rax
- movq %rax, 128(%rdi)
- ret
-
- .cfi_endproc
- .size AsmGetRegs, .-AsmGetRegs
diff --git a/libunwindstack/Check.h b/libunwindstack/Check.h
deleted file mode 100644
index 9643d76..0000000
--- a/libunwindstack/Check.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2017 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_CHECK_H
-#define _LIBUNWINDSTACK_CHECK_H
-
-#include <stdlib.h>
-
-#include <unwindstack/Log.h>
-
-namespace unwindstack {
-
-#define CHECK(assertion) \
- if (__builtin_expect(!(assertion), false)) { \
- log(0, "%s:%d: %s\n", __FILE__, __LINE__, #assertion); \
- abort(); \
- }
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_CHECK_H
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
deleted file mode 100644
index 8fc3d23..0000000
--- a/libunwindstack/DexFile.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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>
-
-#define LOG_TAG "unwind"
-#include <log/log.h>
-
-#include <android-base/unique_fd.h>
-#include <art_api/dex_file_support.h>
-
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-
-#include "DexFile.h"
-
-namespace unwindstack {
-
-static bool CheckDexSupport() {
- if (std::string err_msg; !art_api::dex::TryLoadLibdexfileExternal(&err_msg)) {
- ALOGW("Failed to initialize DEX file support: %s", err_msg.c_str());
- return false;
- }
- return true;
-}
-
-static bool HasDexSupport() {
- static bool has_dex_support = CheckDexSupport();
- return has_dex_support;
-}
-
-std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
- MapInfo* info) {
- if (UNLIKELY(!HasDexSupport())) {
- return nullptr;
- }
-
- size_t max_size = info->end - dex_file_offset_in_memory;
- if (memory->IsLocal()) {
- size_t size = max_size;
-
- std::string err_msg;
- std::unique_ptr<art_api::dex::DexFile> art_dex_file = DexFile::OpenFromMemory(
- reinterpret_cast<void const*>(dex_file_offset_in_memory), &size, info->name, &err_msg);
- if (art_dex_file != nullptr && size <= max_size) {
- return std::unique_ptr<DexFile>(new DexFile(art_dex_file));
- }
- }
-
- if (!info->name.empty()) {
- std::unique_ptr<DexFile> dex_file =
- DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
- if (dex_file) {
- return dex_file;
- }
- }
- return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name, max_size);
-}
-
-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;
- }
- *method_name = method_info.name;
- *method_offset = dex_offset - method_info.offset;
- return true;
-}
-
-std::unique_ptr<DexFileFromFile> DexFileFromFile::Create(uint64_t dex_file_offset_in_file,
- const std::string& file) {
- if (UNLIKELY(!HasDexSupport())) {
- return nullptr;
- }
-
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd == -1) {
- return nullptr;
- }
-
- std::string error_msg;
- std::unique_ptr<art_api::dex::DexFile> art_dex_file =
- OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg);
- if (art_dex_file == nullptr) {
- return nullptr;
- }
-
- return std::unique_ptr<DexFileFromFile>(new DexFileFromFile(art_dex_file));
-}
-
-std::unique_ptr<DexFileFromMemory> DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory,
- Memory* memory,
- const std::string& name,
- size_t max_size) {
- if (UNLIKELY(!HasDexSupport())) {
- return nullptr;
- }
-
- std::vector<uint8_t> backing_memory;
-
- for (size_t size = 0;;) {
- std::string error_msg;
- std::unique_ptr<art_api::dex::DexFile> art_dex_file =
- OpenFromMemory(backing_memory.data(), &size, name, &error_msg);
- if (size > max_size) {
- return nullptr;
- }
-
- if (art_dex_file != nullptr) {
- return std::unique_ptr<DexFileFromMemory>(
- new DexFileFromMemory(art_dex_file, std::move(backing_memory)));
- }
-
- if (!error_msg.empty()) {
- return nullptr;
- }
-
- backing_memory.resize(size);
- if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(),
- backing_memory.size())) {
- return nullptr;
- }
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
deleted file mode 100644
index fe185da..0000000
--- a/libunwindstack/DexFile.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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_FILE_H
-#define _LIBUNWINDSTACK_DEX_FILE_H
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <art_api/dex_file_support.h>
-
-namespace unwindstack {
-
-class DexFile : protected art_api::dex::DexFile {
- public:
- virtual ~DexFile() = default;
-
- 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(std::unique_ptr<art_api::dex::DexFile>& art_dex_file)
- : art_api::dex::DexFile(art_dex_file) {}
-};
-
-class DexFileFromFile : public DexFile {
- public:
- static std::unique_ptr<DexFileFromFile> Create(uint64_t dex_file_offset_in_file,
- const std::string& file);
-
- private:
- DexFileFromFile(std::unique_ptr<art_api::dex::DexFile>& art_dex_file) : DexFile(art_dex_file) {}
-};
-
-class DexFileFromMemory : public DexFile {
- public:
- static std::unique_ptr<DexFileFromMemory> Create(uint64_t dex_file_offset_in_memory,
- Memory* memory, const std::string& name,
- size_t max_size);
-
- private:
- DexFileFromMemory(std::unique_ptr<art_api::dex::DexFile>& art_dex_file,
- std::vector<uint8_t>&& memory)
- : DexFile(art_dex_file), memory_(std::move(memory)) {}
-
- std::vector<uint8_t> memory_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DEX_FILE_H
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
deleted file mode 100644
index 2057fad..0000000
--- a/libunwindstack/DexFiles.cpp
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * 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>
-
-#if defined(DEXFILE_SUPPORT)
-#include "DexFile.h"
-#endif
-
-namespace unwindstack {
-
-#if !defined(DEXFILE_SUPPORT)
-// Empty class definition.
-class DexFile {
- public:
- DexFile() = default;
- virtual ~DexFile() = default;
-};
-#endif
-
-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");
-}
-
-#if defined(DEXFILE_SUPPORT)
-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;
-}
-#else
-DexFile* DexFiles::GetDexFile(uint64_t, MapInfo*) {
- return nullptr;
-}
-#endif
-
-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;
-}
-
-#if defined(DEXFILE_SUPPORT)
-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;
- }
- }
-}
-#else
-void DexFiles::GetMethodInformation(Maps*, MapInfo*, uint64_t, std::string*, uint64_t*) {}
-#endif
-
-} // namespace unwindstack
diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp
deleted file mode 100644
index c6db209..0000000
--- a/libunwindstack/DwarfCfa.cpp
+++ /dev/null
@@ -1,768 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <stdint.h>
-
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/MachineArm64.h>
-
-#include "DwarfCfa.h"
-#include "DwarfEncoding.h"
-#include "DwarfOp.h"
-
-namespace unwindstack {
-
-template <typename AddressType>
-constexpr typename DwarfCfa<AddressType>::process_func DwarfCfa<AddressType>::kCallbackTable[64];
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
- dwarf_loc_regs_t* loc_regs) {
- if (cie_loc_regs_ != nullptr) {
- for (const auto& entry : *cie_loc_regs_) {
- (*loc_regs)[entry.first] = entry.second;
- }
- }
- last_error_.code = DWARF_ERROR_NONE;
- last_error_.address = 0;
-
- memory_->set_cur_offset(start_offset);
- uint64_t cfa_offset;
- cur_pc_ = fde_->pc_start;
- loc_regs->pc_start = cur_pc_;
- while (true) {
- if (cur_pc_ > pc) {
- loc_regs->pc_end = cur_pc_;
- return true;
- }
- if ((cfa_offset = memory_->cur_offset()) >= end_offset) {
- loc_regs->pc_end = fde_->pc_end;
- return true;
- }
- loc_regs->pc_start = cur_pc_;
- operands_.clear();
- // Read the cfa information.
- uint8_t cfa_value;
- if (!memory_->ReadBytes(&cfa_value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_->cur_offset();
- return false;
- }
- uint8_t cfa_low = cfa_value & 0x3f;
- // Check the 2 high bits.
- switch (cfa_value >> 6) {
- case 1:
- cur_pc_ += cfa_low * fde_->cie->code_alignment_factor;
- break;
- case 2: {
- uint64_t offset;
- if (!memory_->ReadULEB128(&offset)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_->cur_offset();
- return false;
- }
- SignedType signed_offset =
- static_cast<SignedType>(offset) * fde_->cie->data_alignment_factor;
- (*loc_regs)[cfa_low] = {.type = DWARF_LOCATION_OFFSET,
- .values = {static_cast<uint64_t>(signed_offset)}};
- break;
- }
- case 3: {
- if (cie_loc_regs_ == nullptr) {
- log(0, "restore while processing cie");
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
-
- auto reg_entry = cie_loc_regs_->find(cfa_low);
- if (reg_entry == cie_loc_regs_->end()) {
- loc_regs->erase(cfa_low);
- } else {
- (*loc_regs)[cfa_low] = reg_entry->second;
- }
- break;
- }
- case 0: {
- const auto handle_func = DwarfCfa<AddressType>::kCallbackTable[cfa_low];
- if (handle_func == nullptr) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- const auto cfa = &DwarfCfaInfo::kTable[cfa_low];
- for (size_t i = 0; i < cfa->num_operands; i++) {
- if (cfa->operands[i] == DW_EH_PE_block) {
- uint64_t block_length;
- if (!memory_->ReadULEB128(&block_length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_->cur_offset();
- return false;
- }
- operands_.push_back(block_length);
- memory_->set_cur_offset(memory_->cur_offset() + block_length);
- continue;
- }
- uint64_t value;
- if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_->cur_offset();
- return false;
- }
- operands_.push_back(value);
- }
-
- if (!(this->*handle_func)(loc_regs)) {
- return false;
- }
- break;
- }
- }
- }
-}
-
-template <typename AddressType>
-std::string DwarfCfa<AddressType>::GetOperandString(uint8_t operand, uint64_t value,
- uint64_t* cur_pc) {
- std::string string;
- switch (operand) {
- case DwarfCfaInfo::DWARF_DISPLAY_REGISTER:
- string = " register(" + std::to_string(value) + ")";
- break;
- case DwarfCfaInfo::DWARF_DISPLAY_SIGNED_NUMBER:
- string += " " + std::to_string(static_cast<SignedType>(value));
- break;
- case DwarfCfaInfo::DWARF_DISPLAY_ADVANCE_LOC:
- *cur_pc += value;
- FALLTHROUGH_INTENDED;
- // Fall through to log the value.
- case DwarfCfaInfo::DWARF_DISPLAY_NUMBER:
- string += " " + std::to_string(value);
- break;
- case DwarfCfaInfo::DWARF_DISPLAY_SET_LOC:
- *cur_pc = value;
- FALLTHROUGH_INTENDED;
- // Fall through to log the value.
- case DwarfCfaInfo::DWARF_DISPLAY_ADDRESS:
- if (std::is_same<AddressType, uint32_t>::value) {
- string += android::base::StringPrintf(" 0x%" PRIx32, static_cast<uint32_t>(value));
- } else {
- string += android::base::StringPrintf(" 0x%" PRIx64, static_cast<uint64_t>(value));
- }
- break;
- default:
- string = " unknown";
- }
- return string;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::LogOffsetRegisterString(uint32_t indent, uint64_t cfa_offset,
- uint8_t reg) {
- uint64_t offset;
- if (!memory_->ReadULEB128(&offset)) {
- return false;
- }
- uint64_t end_offset = memory_->cur_offset();
- memory_->set_cur_offset(cfa_offset);
-
- std::string raw_data = "Raw Data:";
- for (uint64_t i = cfa_offset; i < end_offset; i++) {
- uint8_t value;
- if (!memory_->ReadBytes(&value, 1)) {
- return false;
- }
- raw_data += android::base::StringPrintf(" 0x%02x", value);
- }
- log(indent, "DW_CFA_offset register(%d) %" PRId64, reg, offset);
- log(indent, "%s", raw_data.c_str());
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op,
- uint64_t* cur_pc) {
- const auto* cfa = &DwarfCfaInfo::kTable[op];
- if (cfa->name[0] == '\0' || (arch_ != ARCH_ARM64 && op == 0x2d)) {
- if (op == 0x2d) {
- log(indent, "Illegal (Only valid on aarch64)");
- } else {
- log(indent, "Illegal");
- }
- log(indent, "Raw Data: 0x%02x", op);
- return true;
- }
-
- std::string log_string(cfa->name);
- std::vector<std::string> expression_lines;
- for (size_t i = 0; i < cfa->num_operands; i++) {
- if (cfa->operands[i] == DW_EH_PE_block) {
- // This is a Dwarf Expression.
- uint64_t end_offset;
- if (!memory_->ReadULEB128(&end_offset)) {
- return false;
- }
- log_string += " " + std::to_string(end_offset);
- end_offset += memory_->cur_offset();
-
- DwarfOp<AddressType> op(memory_, nullptr);
- op.GetLogInfo(memory_->cur_offset(), end_offset, &expression_lines);
- memory_->set_cur_offset(end_offset);
- } else {
- uint64_t value;
- if (!memory_->ReadEncodedValue<AddressType>(cfa->operands[i], &value)) {
- return false;
- }
- log_string += GetOperandString(cfa->display_operands[i], value, cur_pc);
- }
- }
- log(indent, "%s", log_string.c_str());
-
- // Get the raw bytes of the data.
- uint64_t end_offset = memory_->cur_offset();
- memory_->set_cur_offset(cfa_offset);
- std::string raw_data("Raw Data:");
- for (uint64_t i = 0; i < end_offset - cfa_offset; i++) {
- uint8_t value;
- if (!memory_->ReadBytes(&value, 1)) {
- return false;
- }
-
- // Only show 10 raw bytes per line.
- if ((i % 10) == 0 && i != 0) {
- log(indent, "%s", raw_data.c_str());
- raw_data.clear();
- }
- if (raw_data.empty()) {
- raw_data = "Raw Data:";
- }
- raw_data += android::base::StringPrintf(" 0x%02x", value);
- }
- if (!raw_data.empty()) {
- log(indent, "%s", raw_data.c_str());
- }
-
- // Log any of the expression data.
- for (const auto& line : expression_lines) {
- log(indent + 1, "%s", line.c_str());
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::Log(uint32_t indent, uint64_t pc, uint64_t start_offset,
- uint64_t end_offset) {
- memory_->set_cur_offset(start_offset);
- uint64_t cfa_offset;
- uint64_t cur_pc = fde_->pc_start;
- uint64_t old_pc = cur_pc;
- while ((cfa_offset = memory_->cur_offset()) < end_offset && cur_pc <= pc) {
- // Read the cfa information.
- uint8_t cfa_value;
- if (!memory_->ReadBytes(&cfa_value, 1)) {
- return false;
- }
-
- // Check the 2 high bits.
- uint8_t cfa_low = cfa_value & 0x3f;
- switch (cfa_value >> 6) {
- case 0:
- if (!LogInstruction(indent, cfa_offset, cfa_low, &cur_pc)) {
- return false;
- }
- break;
- case 1:
- log(indent, "DW_CFA_advance_loc %d", cfa_low);
- log(indent, "Raw Data: 0x%02x", cfa_value);
- cur_pc += cfa_low * fde_->cie->code_alignment_factor;
- break;
- case 2:
- if (!LogOffsetRegisterString(indent, cfa_offset, cfa_low)) {
- return false;
- }
- break;
- case 3:
- log(indent, "DW_CFA_restore register(%d)", cfa_low);
- log(indent, "Raw Data: 0x%02x", cfa_value);
- break;
- }
- if (cur_pc != old_pc) {
- log(0, "");
- log(indent, "PC 0x%" PRIx64, cur_pc);
- }
- old_pc = cur_pc;
- }
- return true;
-}
-
-// Static data.
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_nop(dwarf_loc_regs_t*) {
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_set_loc(dwarf_loc_regs_t*) {
- AddressType cur_pc = cur_pc_;
- AddressType new_pc = operands_[0];
- if (new_pc < cur_pc) {
- if (std::is_same<AddressType, uint32_t>::value) {
- log(0, "Warning: PC is moving backwards: old 0x%" PRIx32 " new 0x%" PRIx32, cur_pc, new_pc);
- } else {
- log(0, "Warning: PC is moving backwards: old 0x%" PRIx64 " new 0x%" PRIx64, cur_pc, new_pc);
- }
- }
- cur_pc_ = new_pc;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_advance_loc(dwarf_loc_regs_t*) {
- cur_pc_ += operands_[0] * fde_->cie->code_alignment_factor;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_offset(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {operands_[1]}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_restore(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- if (cie_loc_regs_ == nullptr) {
- log(0, "restore while processing cie");
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
- auto reg_entry = cie_loc_regs_->find(reg);
- if (reg_entry == cie_loc_regs_->end()) {
- loc_regs->erase(reg);
- } else {
- (*loc_regs)[reg] = reg_entry->second;
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_undefined(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_UNDEFINED};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_same_value(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- loc_regs->erase(reg);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_register(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- AddressType reg_dst = operands_[1];
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_REGISTER, .values = {reg_dst}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_remember_state(dwarf_loc_regs_t* loc_regs) {
- loc_reg_state_.push(*loc_regs);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_restore_state(dwarf_loc_regs_t* loc_regs) {
- if (loc_reg_state_.size() == 0) {
- log(0, "Warning: Attempt to restore without remember.");
- return true;
- }
- *loc_regs = loc_reg_state_.top();
- loc_reg_state_.pop();
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_def_cfa(dwarf_loc_regs_t* loc_regs) {
- (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {operands_[0], operands_[1]}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_def_cfa_register(dwarf_loc_regs_t* loc_regs) {
- auto cfa_location = loc_regs->find(CFA_REG);
- if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
- log(0, "Attempt to set new register, but cfa is not already set to a register.");
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
-
- cfa_location->second.values[0] = operands_[0];
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_def_cfa_offset(dwarf_loc_regs_t* loc_regs) {
- // Changing the offset if this is not a register is illegal.
- auto cfa_location = loc_regs->find(CFA_REG);
- if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
- log(0, "Attempt to set offset, but cfa is not set to a register.");
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
- cfa_location->second.values[1] = operands_[0];
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_def_cfa_expression(dwarf_loc_regs_t* loc_regs) {
- // There is only one type of expression for CFA evaluation and the DWARF
- // specification is unclear whether it returns the address or the
- // dereferenced value. GDB expects the value, so will we.
- (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_VAL_EXPRESSION,
- .values = {operands_[0], memory_->cur_offset()}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_expression(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_EXPRESSION,
- .values = {operands_[1], memory_->cur_offset()}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_offset_extended_sf(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- SignedType value = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(value)}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_def_cfa_sf(dwarf_loc_regs_t* loc_regs) {
- SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
- (*loc_regs)[CFA_REG] = {.type = DWARF_LOCATION_REGISTER,
- .values = {operands_[0], static_cast<uint64_t>(offset)}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_def_cfa_offset_sf(dwarf_loc_regs_t* loc_regs) {
- // Changing the offset if this is not a register is illegal.
- auto cfa_location = loc_regs->find(CFA_REG);
- if (cfa_location == loc_regs->end() || cfa_location->second.type != DWARF_LOCATION_REGISTER) {
- log(0, "Attempt to set offset, but cfa is not set to a register.");
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
- SignedType offset = static_cast<SignedType>(operands_[0]) * fde_->cie->data_alignment_factor;
- cfa_location->second.values[1] = static_cast<uint64_t>(offset);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_val_offset(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_OFFSET, .values = {static_cast<uint64_t>(offset)}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_val_offset_sf(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- SignedType offset = static_cast<SignedType>(operands_[1]) * fde_->cie->data_alignment_factor;
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_OFFSET, .values = {static_cast<uint64_t>(offset)}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_val_expression(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_VAL_EXPRESSION,
- .values = {operands_[1], memory_->cur_offset()}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_gnu_negative_offset_extended(dwarf_loc_regs_t* loc_regs) {
- AddressType reg = operands_[0];
- SignedType offset = -static_cast<SignedType>(operands_[1]);
- (*loc_regs)[reg] = {.type = DWARF_LOCATION_OFFSET, .values = {static_cast<uint64_t>(offset)}};
- return true;
-}
-
-template <typename AddressType>
-bool DwarfCfa<AddressType>::cfa_aarch64_negate_ra_state(dwarf_loc_regs_t* loc_regs) {
- // Only supported on aarch64.
- if (arch_ != ARCH_ARM64) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- auto cfa_location = loc_regs->find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
- if (cfa_location == loc_regs->end()) {
- (*loc_regs)[Arm64Reg::ARM64_PREG_RA_SIGN_STATE] = {.type = DWARF_LOCATION_PSEUDO_REGISTER,
- .values = {1}};
- } else {
- cfa_location->second.values[0] ^= 1;
- }
- return true;
-}
-
-const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = {
- {
- // 0x00 DW_CFA_nop
- "DW_CFA_nop",
- 2,
- 0,
- {},
- {},
- },
- {
- "DW_CFA_set_loc", // 0x01 DW_CFA_set_loc
- 2,
- 1,
- {DW_EH_PE_absptr},
- {DWARF_DISPLAY_SET_LOC},
- },
- {
- "DW_CFA_advance_loc1", // 0x02 DW_CFA_advance_loc1
- 2,
- 1,
- {DW_EH_PE_udata1},
- {DWARF_DISPLAY_ADVANCE_LOC},
- },
- {
- "DW_CFA_advance_loc2", // 0x03 DW_CFA_advance_loc2
- 2,
- 1,
- {DW_EH_PE_udata2},
- {DWARF_DISPLAY_ADVANCE_LOC},
- },
- {
- "DW_CFA_advance_loc4", // 0x04 DW_CFA_advance_loc4
- 2,
- 1,
- {DW_EH_PE_udata4},
- {DWARF_DISPLAY_ADVANCE_LOC},
- },
- {
- "DW_CFA_offset_extended", // 0x05 DW_CFA_offset_extended
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
- },
- {
- "DW_CFA_restore_extended", // 0x06 DW_CFA_restore_extended
- 2,
- 1,
- {DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER},
- },
- {
- "DW_CFA_undefined", // 0x07 DW_CFA_undefined
- 2,
- 1,
- {DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER},
- },
- {
- "DW_CFA_same_value", // 0x08 DW_CFA_same_value
- 2,
- 1,
- {DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER},
- },
- {
- "DW_CFA_register", // 0x09 DW_CFA_register
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_REGISTER},
- },
- {
- "DW_CFA_remember_state", // 0x0a DW_CFA_remember_state
- 2,
- 0,
- {},
- {},
- },
- {
- "DW_CFA_restore_state", // 0x0b DW_CFA_restore_state
- 2,
- 0,
- {},
- {},
- },
- {
- "DW_CFA_def_cfa", // 0x0c DW_CFA_def_cfa
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
- },
- {
- "DW_CFA_def_cfa_register", // 0x0d DW_CFA_def_cfa_register
- 2,
- 1,
- {DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER},
- },
- {
- "DW_CFA_def_cfa_offset", // 0x0e DW_CFA_def_cfa_offset
- 2,
- 1,
- {DW_EH_PE_uleb128},
- {DWARF_DISPLAY_NUMBER},
- },
- {
- "DW_CFA_def_cfa_expression", // 0x0f DW_CFA_def_cfa_expression
- 2,
- 1,
- {DW_EH_PE_block},
- {DWARF_DISPLAY_EVAL_BLOCK},
- },
- {
- "DW_CFA_expression", // 0x10 DW_CFA_expression
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_block},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK},
- },
- {
- "DW_CFA_offset_extended_sf", // 0x11 DW_CFA_offset_extend_sf
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
- },
- {
- "DW_CFA_def_cfa_sf", // 0x12 DW_CFA_def_cfa_sf
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
- },
- {
- "DW_CFA_def_cfa_offset_sf", // 0x13 DW_CFA_def_cfa_offset_sf
- 2,
- 1,
- {DW_EH_PE_sleb128},
- {DWARF_DISPLAY_SIGNED_NUMBER},
- },
- {
- "DW_CFA_val_offset", // 0x14 DW_CFA_val_offset
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
- },
- {
- "DW_CFA_val_offset_sf", // 0x15 DW_CFA_val_offset_sf
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_SIGNED_NUMBER},
- },
- {
- "DW_CFA_val_expression", // 0x16 DW_CFA_val_expression
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_block},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_EVAL_BLOCK},
- },
- {"", 0, 0, {}, {}}, // 0x17 illegal cfa
- {"", 0, 0, {}, {}}, // 0x18 illegal cfa
- {"", 0, 0, {}, {}}, // 0x19 illegal cfa
- {"", 0, 0, {}, {}}, // 0x1a illegal cfa
- {"", 0, 0, {}, {}}, // 0x1b illegal cfa
- {"", 0, 0, {}, {}}, // 0x1c DW_CFA_lo_user (Treat as illegal)
- {"", 0, 0, {}, {}}, // 0x1d illegal cfa
- {"", 0, 0, {}, {}}, // 0x1e illegal cfa
- {"", 0, 0, {}, {}}, // 0x1f illegal cfa
- {"", 0, 0, {}, {}}, // 0x20 illegal cfa
- {"", 0, 0, {}, {}}, // 0x21 illegal cfa
- {"", 0, 0, {}, {}}, // 0x22 illegal cfa
- {"", 0, 0, {}, {}}, // 0x23 illegal cfa
- {"", 0, 0, {}, {}}, // 0x24 illegal cfa
- {"", 0, 0, {}, {}}, // 0x25 illegal cfa
- {"", 0, 0, {}, {}}, // 0x26 illegal cfa
- {"", 0, 0, {}, {}}, // 0x27 illegal cfa
- {"", 0, 0, {}, {}}, // 0x28 illegal cfa
- {"", 0, 0, {}, {}}, // 0x29 illegal cfa
- {"", 0, 0, {}, {}}, // 0x2a illegal cfa
- {"", 0, 0, {}, {}}, // 0x2b illegal cfa
- {"", 0, 0, {}, {}}, // 0x2c illegal cfa
- {
- "DW_CFA_AARCH64_negate_ra_state", // 0x2d DW_CFA_AARCH64_negate_ra_state
- 3,
- 0,
- {},
- {},
- },
- {
- "DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size
- 2,
- 1,
- {DW_EH_PE_uleb128},
- {DWARF_DISPLAY_NUMBER},
- },
- {
- "DW_CFA_GNU_negative_offset_extended", // 0x2f DW_CFA_GNU_negative_offset_extended
- 2,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
- {DWARF_DISPLAY_REGISTER, DWARF_DISPLAY_NUMBER},
- },
- {"", 0, 0, {}, {}}, // 0x31 illegal cfa
- {"", 0, 0, {}, {}}, // 0x32 illegal cfa
- {"", 0, 0, {}, {}}, // 0x33 illegal cfa
- {"", 0, 0, {}, {}}, // 0x34 illegal cfa
- {"", 0, 0, {}, {}}, // 0x35 illegal cfa
- {"", 0, 0, {}, {}}, // 0x36 illegal cfa
- {"", 0, 0, {}, {}}, // 0x37 illegal cfa
- {"", 0, 0, {}, {}}, // 0x38 illegal cfa
- {"", 0, 0, {}, {}}, // 0x39 illegal cfa
- {"", 0, 0, {}, {}}, // 0x3a illegal cfa
- {"", 0, 0, {}, {}}, // 0x3b illegal cfa
- {"", 0, 0, {}, {}}, // 0x3c illegal cfa
- {"", 0, 0, {}, {}}, // 0x3d illegal cfa
- {"", 0, 0, {}, {}}, // 0x3e illegal cfa
- {"", 0, 0, {}, {}}, // 0x3f DW_CFA_hi_user (Treat as illegal)
-};
-
-// Explicitly instantiate DwarfCfa.
-template class DwarfCfa<uint32_t>;
-template class DwarfCfa<uint64_t>;
-
-} // namespace unwindstack
diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h
deleted file mode 100644
index d627e15..0000000
--- a/libunwindstack/DwarfCfa.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_CFA_H
-#define _LIBUNWINDSTACK_DWARF_CFA_H
-
-#include <stdint.h>
-
-#include <stack>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/DwarfStructs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-enum ArchEnum : uint8_t;
-
-// DWARF Standard home: http://dwarfstd.org/
-// This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf
-// See section 6.4.2.1 for a description of the DW_CFA_xxx values.
-
-class DwarfCfaInfo {
- public:
- enum DisplayType : uint8_t {
- DWARF_DISPLAY_NONE = 0,
- DWARF_DISPLAY_REGISTER,
- DWARF_DISPLAY_NUMBER,
- DWARF_DISPLAY_SIGNED_NUMBER,
- DWARF_DISPLAY_EVAL_BLOCK,
- DWARF_DISPLAY_ADDRESS,
- DWARF_DISPLAY_SET_LOC,
- DWARF_DISPLAY_ADVANCE_LOC,
- };
-
- struct Info {
- // It may seem cleaner to just change the type of 'name' to 'const char *'.
- // However, having a pointer here would require relocation at runtime,
- // causing 'kTable' to be placed in data.rel.ro section instead of rodata
- // section, adding memory pressure to the system. Note that this is only
- // safe because this is only used in C++ code. C++ standard, unlike C
- // standard, mandates the array size to be large enough to hold the NULL
- // terminator when initialized with a string literal.
- const char name[36];
- uint8_t supported_version;
- uint8_t num_operands;
- uint8_t operands[2];
- uint8_t display_operands[2];
- };
-
- const static Info kTable[64];
-};
-
-template <typename AddressType>
-class DwarfCfa {
- // Signed version of AddressType
- typedef typename std::make_signed<AddressType>::type SignedType;
-
- public:
- DwarfCfa(DwarfMemory* memory, const DwarfFde* fde, ArchEnum arch)
- : memory_(memory), fde_(fde), arch_(arch) {}
- virtual ~DwarfCfa() = default;
-
- bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset,
- dwarf_loc_regs_t* loc_regs);
-
- bool Log(uint32_t indent, uint64_t pc, uint64_t start_offset, uint64_t end_offset);
-
- const DwarfErrorData& last_error() { return last_error_; }
- DwarfErrorCode LastErrorCode() { return last_error_.code; }
- uint64_t LastErrorAddress() { return last_error_.address; }
-
- AddressType cur_pc() { return cur_pc_; }
-
- void set_cie_loc_regs(const dwarf_loc_regs_t* cie_loc_regs) { cie_loc_regs_ = cie_loc_regs; }
-
- protected:
- std::string GetOperandString(uint8_t operand, uint64_t value, uint64_t* cur_pc);
-
- bool LogOffsetRegisterString(uint32_t indent, uint64_t cfa_offset, uint8_t reg);
-
- bool LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc);
-
- private:
- DwarfErrorData last_error_;
- DwarfMemory* memory_;
- const DwarfFde* fde_;
- ArchEnum arch_;
-
- AddressType cur_pc_;
- const dwarf_loc_regs_t* cie_loc_regs_ = nullptr;
- std::vector<AddressType> operands_;
- std::stack<dwarf_loc_regs_t> loc_reg_state_;
-
- // CFA processing functions.
- bool cfa_nop(dwarf_loc_regs_t*);
- bool cfa_set_loc(dwarf_loc_regs_t*);
- bool cfa_advance_loc(dwarf_loc_regs_t*);
- bool cfa_offset(dwarf_loc_regs_t*);
- bool cfa_restore(dwarf_loc_regs_t*);
- bool cfa_undefined(dwarf_loc_regs_t*);
- bool cfa_same_value(dwarf_loc_regs_t*);
- bool cfa_register(dwarf_loc_regs_t*);
- bool cfa_remember_state(dwarf_loc_regs_t*);
- bool cfa_restore_state(dwarf_loc_regs_t*);
- bool cfa_def_cfa(dwarf_loc_regs_t*);
- bool cfa_def_cfa_register(dwarf_loc_regs_t*);
- bool cfa_def_cfa_offset(dwarf_loc_regs_t*);
- bool cfa_def_cfa_expression(dwarf_loc_regs_t*);
- bool cfa_expression(dwarf_loc_regs_t*);
- bool cfa_offset_extended_sf(dwarf_loc_regs_t*);
- bool cfa_def_cfa_sf(dwarf_loc_regs_t*);
- bool cfa_def_cfa_offset_sf(dwarf_loc_regs_t*);
- bool cfa_val_offset(dwarf_loc_regs_t*);
- bool cfa_val_offset_sf(dwarf_loc_regs_t*);
- bool cfa_val_expression(dwarf_loc_regs_t*);
- bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*);
- bool cfa_aarch64_negate_ra_state(dwarf_loc_regs_t*);
-
- using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*);
- constexpr static process_func kCallbackTable[64] = {
- // 0x00 DW_CFA_nop
- &DwarfCfa::cfa_nop,
- // 0x01 DW_CFA_set_loc
- &DwarfCfa::cfa_set_loc,
- // 0x02 DW_CFA_advance_loc1
- &DwarfCfa::cfa_advance_loc,
- // 0x03 DW_CFA_advance_loc2
- &DwarfCfa::cfa_advance_loc,
- // 0x04 DW_CFA_advance_loc4
- &DwarfCfa::cfa_advance_loc,
- // 0x05 DW_CFA_offset_extended
- &DwarfCfa::cfa_offset,
- // 0x06 DW_CFA_restore_extended
- &DwarfCfa::cfa_restore,
- // 0x07 DW_CFA_undefined
- &DwarfCfa::cfa_undefined,
- // 0x08 DW_CFA_same_value
- &DwarfCfa::cfa_same_value,
- // 0x09 DW_CFA_register
- &DwarfCfa::cfa_register,
- // 0x0a DW_CFA_remember_state
- &DwarfCfa::cfa_remember_state,
- // 0x0b DW_CFA_restore_state
- &DwarfCfa::cfa_restore_state,
- // 0x0c DW_CFA_def_cfa
- &DwarfCfa::cfa_def_cfa,
- // 0x0d DW_CFA_def_cfa_register
- &DwarfCfa::cfa_def_cfa_register,
- // 0x0e DW_CFA_def_cfa_offset
- &DwarfCfa::cfa_def_cfa_offset,
- // 0x0f DW_CFA_def_cfa_expression
- &DwarfCfa::cfa_def_cfa_expression,
- // 0x10 DW_CFA_expression
- &DwarfCfa::cfa_expression,
- // 0x11 DW_CFA_offset_extended_sf
- &DwarfCfa::cfa_offset_extended_sf,
- // 0x12 DW_CFA_def_cfa_sf
- &DwarfCfa::cfa_def_cfa_sf,
- // 0x13 DW_CFA_def_cfa_offset_sf
- &DwarfCfa::cfa_def_cfa_offset_sf,
- // 0x14 DW_CFA_val_offset
- &DwarfCfa::cfa_val_offset,
- // 0x15 DW_CFA_val_offset_sf
- &DwarfCfa::cfa_val_offset_sf,
- // 0x16 DW_CFA_val_expression
- &DwarfCfa::cfa_val_expression,
- // 0x17 illegal cfa
- nullptr,
- // 0x18 illegal cfa
- nullptr,
- // 0x19 illegal cfa
- nullptr,
- // 0x1a illegal cfa
- nullptr,
- // 0x1b illegal cfa
- nullptr,
- // 0x1c DW_CFA_lo_user (Treat this as illegal)
- nullptr,
- // 0x1d illegal cfa
- nullptr,
- // 0x1e illegal cfa
- nullptr,
- // 0x1f illegal cfa
- nullptr,
- // 0x20 illegal cfa
- nullptr,
- // 0x21 illegal cfa
- nullptr,
- // 0x22 illegal cfa
- nullptr,
- // 0x23 illegal cfa
- nullptr,
- // 0x24 illegal cfa
- nullptr,
- // 0x25 illegal cfa
- nullptr,
- // 0x26 illegal cfa
- nullptr,
- // 0x27 illegal cfa
- nullptr,
- // 0x28 illegal cfa
- nullptr,
- // 0x29 illegal cfa
- nullptr,
- // 0x2a illegal cfa
- nullptr,
- // 0x2b illegal cfa
- nullptr,
- // 0x2c illegal cfa
- nullptr,
- // 0x2d DW_CFA_AARCH64_negate_ra_state (aarch64 only)
- // DW_CFA_GNU_window_save on other architectures.
- &DwarfCfa::cfa_aarch64_negate_ra_state,
- // 0x2e DW_CFA_GNU_args_size
- &DwarfCfa::cfa_nop,
- // 0x2f DW_CFA_GNU_negative_offset_extended
- &DwarfCfa::cfa_gnu_negative_offset_extended,
- // 0x30 illegal cfa
- nullptr,
- // 0x31 illegal cfa
- nullptr,
- // 0x32 illegal cfa
- nullptr,
- // 0x33 illegal cfa
- nullptr,
- // 0x34 illegal cfa
- nullptr,
- // 0x35 illegal cfa
- nullptr,
- // 0x36 illegal cfa
- nullptr,
- // 0x37 illegal cfa
- nullptr,
- // 0x38 illegal cfa
- nullptr,
- // 0x39 illegal cfa
- nullptr,
- // 0x3a illegal cfa
- nullptr,
- // 0x3b illegal cfa
- nullptr,
- // 0x3c illegal cfa
- nullptr,
- // 0x3d illegal cfa
- nullptr,
- // 0x3e illegal cfa
- nullptr,
- // 0x3f DW_CFA_hi_user (Treat this as illegal)
- nullptr,
- };
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_CFA_H
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
deleted file mode 100644
index 635cefd..0000000
--- a/libunwindstack/DwarfDebugFrame.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 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_DWARF_DEBUG_FRAME_H
-#define _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
-
-#include <stdint.h>
-
-#include <vector>
-
-#include <unwindstack/DwarfSection.h>
-
-namespace unwindstack {
-
-template <typename AddressType>
-class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
- public:
- DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {
- this->cie32_value_ = static_cast<uint32_t>(-1);
- this->cie64_value_ = static_cast<uint64_t>(-1);
- }
- virtual ~DwarfDebugFrame() = default;
-
- uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
- return this->entries_offset_ + pointer;
- }
-
- uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
- return this->entries_offset_ + pointer;
- }
-
- uint64_t AdjustPcFromFde(uint64_t pc) override { return pc; }
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_DEBUG_FRAME_H
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
deleted file mode 100644
index 7a41e45..0000000
--- a/libunwindstack/DwarfEhFrame.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_EH_FRAME_H
-#define _LIBUNWINDSTACK_DWARF_EH_FRAME_H
-
-#include <stdint.h>
-
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-template <typename AddressType>
-class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
- public:
- DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
- virtual ~DwarfEhFrame() = default;
-
- uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
- return this->memory_.cur_offset() - pointer - 4;
- }
-
- uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
- return this->memory_.cur_offset() - pointer - 8;
- }
-
- uint64_t AdjustPcFromFde(uint64_t pc) override {
- // The eh_frame uses relative pcs.
- return pc + this->memory_.cur_offset() - 4;
- }
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
deleted file mode 100644
index 1358e51..0000000
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2017 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 <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfStructs.h>
-#include <unwindstack/Memory.h>
-
-#include "Check.h"
-#include "DwarfEhFrameWithHdr.h"
-#include "DwarfEncoding.h"
-
-namespace unwindstack {
-
-static inline bool IsEncodingRelative(uint8_t encoding) {
- encoding >>= 4;
- return encoding > 0 && encoding <= DW_EH_PE_funcrel;
-}
-
-template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::EhFrameInit(uint64_t offset, uint64_t size,
- int64_t section_bias) {
- return DwarfSectionImpl<AddressType>::Init(offset, size, section_bias);
-}
-
-template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t, int64_t section_bias) {
- memory_.clear_func_offset();
- memory_.clear_text_offset();
- memory_.set_data_offset(offset);
- memory_.set_cur_offset(offset);
-
- hdr_section_bias_ = section_bias;
-
- // Read the first four bytes all at once.
- uint8_t data[4];
- if (!memory_.ReadBytes(data, 4)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- version_ = data[0];
- if (version_ != 1) {
- // Unknown version.
- last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
- return false;
- }
-
- uint8_t ptr_encoding = data[1];
- uint8_t fde_count_encoding = data[2];
- table_encoding_ = data[3];
- table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
-
- // If we can't perform a binary search on the entries, it's not worth
- // using this object. The calling code will fall back to the DwarfEhFrame
- // object in this case.
- if (table_entry_size_ == 0) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- memory_.set_pc_offset(memory_.cur_offset());
- uint64_t ptr_offset;
- if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding, &ptr_offset)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- memory_.set_pc_offset(memory_.cur_offset());
- if (!memory_.template ReadEncodedValue<AddressType>(fde_count_encoding, &fde_count_)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (fde_count_ == 0) {
- last_error_.code = DWARF_ERROR_NO_FDES;
- return false;
- }
-
- hdr_entries_offset_ = memory_.cur_offset();
- hdr_entries_data_offset_ = offset;
-
- return true;
-}
-
-template <typename AddressType>
-const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
- uint64_t fde_offset;
- if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
- return nullptr;
- }
- const DwarfFde* fde = this->GetFdeFromOffset(fde_offset);
- if (fde == nullptr) {
- return nullptr;
- }
-
- // There is a possibility that this entry points to a zero length FDE
- // due to a bug. If this happens, try and find the non-zero length FDE
- // from eh_frame directly. See b/142483624.
- if (fde->pc_start == fde->pc_end) {
- fde = DwarfSectionImpl<AddressType>::GetFdeFromPc(pc);
- if (fde == nullptr) {
- return nullptr;
- }
- }
-
- // Guaranteed pc >= pc_start, need to check pc in the fde range.
- if (pc < fde->pc_end) {
- return fde;
- }
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return nullptr;
-}
-
-template <typename AddressType>
-const typename DwarfEhFrameWithHdr<AddressType>::FdeInfo*
-DwarfEhFrameWithHdr<AddressType>::GetFdeInfoFromIndex(size_t index) {
- auto entry = fde_info_.find(index);
- if (entry != fde_info_.end()) {
- return &fde_info_[index];
- }
- FdeInfo* info = &fde_info_[index];
-
- memory_.set_data_offset(hdr_entries_data_offset_);
- memory_.set_cur_offset(hdr_entries_offset_ + 2 * index * table_entry_size_);
- memory_.set_pc_offset(0);
- uint64_t value;
- if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
- !memory_.template ReadEncodedValue<AddressType>(table_encoding_, &info->offset)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- fde_info_.erase(index);
- return nullptr;
- }
-
- // Relative encodings require adding in the load bias.
- if (IsEncodingRelative(table_encoding_)) {
- value += hdr_section_bias_;
- }
- info->pc = value;
- return info;
-}
-
-template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
- if (fde_count_ == 0) {
- return false;
- }
-
- size_t first = 0;
- size_t last = fde_count_;
- while (first < last) {
- size_t current = (first + last) / 2;
- const FdeInfo* info = GetFdeInfoFromIndex(current);
- if (info == nullptr) {
- return false;
- }
- if (pc == info->pc) {
- *fde_offset = info->offset;
- return true;
- }
- if (pc < info->pc) {
- last = current;
- } else {
- first = current + 1;
- }
- }
- if (last != 0) {
- const FdeInfo* info = GetFdeInfoFromIndex(last - 1);
- if (info == nullptr) {
- return false;
- }
- *fde_offset = info->offset;
- return true;
- }
- return false;
-}
-
-template <typename AddressType>
-void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
- for (size_t i = 0; i < fde_count_; i++) {
- const FdeInfo* info = GetFdeInfoFromIndex(i);
- if (info == nullptr) {
- break;
- }
- const DwarfFde* fde = this->GetFdeFromOffset(info->offset);
- if (fde == nullptr) {
- break;
- }
-
- // There is a possibility that this entry points to a zero length FDE
- // due to a bug. If this happens, try and find the non-zero length FDE
- // from eh_frame directly. See b/142483624.
- if (fde->pc_start == fde->pc_end) {
- const DwarfFde* fde_real = DwarfSectionImpl<AddressType>::GetFdeFromPc(fde->pc_start);
- if (fde_real != nullptr) {
- fde = fde_real;
- }
- }
- fdes->push_back(fde);
- }
-}
-
-// Explicitly instantiate DwarfEhFrameWithHdr
-template class DwarfEhFrameWithHdr<uint32_t>;
-template class DwarfEhFrameWithHdr<uint64_t>;
-
-} // namespace unwindstack
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
deleted file mode 100644
index f7c010c..0000000
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
-#define _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
-
-#include <stdint.h>
-
-#include <unordered_map>
-
-#include <unwindstack/DwarfSection.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-
-template <typename AddressType>
-class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
- public:
- // Add these so that the protected members of DwarfSectionImpl
- // can be accessed without needing a this->.
- using DwarfSectionImpl<AddressType>::memory_;
- using DwarfSectionImpl<AddressType>::last_error_;
-
- struct FdeInfo {
- AddressType pc;
- uint64_t offset;
- };
-
- DwarfEhFrameWithHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
- virtual ~DwarfEhFrameWithHdr() = default;
-
- uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
- return memory_.cur_offset() - pointer - 4;
- }
-
- uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
- return memory_.cur_offset() - pointer - 8;
- }
-
- uint64_t AdjustPcFromFde(uint64_t pc) override {
- // The eh_frame uses relative pcs.
- return pc + memory_.cur_offset() - 4;
- }
-
- bool EhFrameInit(uint64_t offset, uint64_t size, int64_t section_bias);
- bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
-
- const DwarfFde* GetFdeFromPc(uint64_t pc) override;
-
- bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset);
-
- const FdeInfo* GetFdeInfoFromIndex(size_t index);
-
- void GetFdes(std::vector<const DwarfFde*>* fdes) override;
-
- protected:
- uint8_t version_ = 0;
- uint8_t table_encoding_ = 0;
- size_t table_entry_size_ = 0;
-
- uint64_t hdr_entries_offset_ = 0;
- uint64_t hdr_entries_data_offset_ = 0;
- uint64_t hdr_section_bias_ = 0;
-
- uint64_t fde_count_ = 0;
- std::unordered_map<uint64_t, FdeInfo> fde_info_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
diff --git a/libunwindstack/DwarfEncoding.h b/libunwindstack/DwarfEncoding.h
deleted file mode 100644
index 20db222..0000000
--- a/libunwindstack/DwarfEncoding.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_ENCODING_H
-#define _LIBUNWINDSTACK_DWARF_ENCODING_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum DwarfEncoding : uint8_t {
- DW_EH_PE_omit = 0xff,
-
- DW_EH_PE_absptr = 0x00,
- DW_EH_PE_uleb128 = 0x01,
- DW_EH_PE_udata2 = 0x02,
- DW_EH_PE_udata4 = 0x03,
- DW_EH_PE_udata8 = 0x04,
- DW_EH_PE_sleb128 = 0x09,
- DW_EH_PE_sdata2 = 0x0a,
- DW_EH_PE_sdata4 = 0x0b,
- DW_EH_PE_sdata8 = 0x0c,
-
- DW_EH_PE_pcrel = 0x10,
- DW_EH_PE_textrel = 0x20,
- DW_EH_PE_datarel = 0x30,
- DW_EH_PE_funcrel = 0x40,
- DW_EH_PE_aligned = 0x50,
-
- // The following are special values used to encode CFA and OP operands.
- DW_EH_PE_udata1 = 0x0d,
- DW_EH_PE_sdata1 = 0x0e,
- DW_EH_PE_block = 0x0f,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_ENCODING_H
diff --git a/libunwindstack/DwarfMemory.cpp b/libunwindstack/DwarfMemory.cpp
deleted file mode 100644
index 2e388c6..0000000
--- a/libunwindstack/DwarfMemory.cpp
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Copyright (C) 2017 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 <string>
-
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/Memory.h>
-
-#include "Check.h"
-#include "DwarfEncoding.h"
-
-namespace unwindstack {
-
-bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
- if (!memory_->ReadFully(cur_offset_, dst, num_bytes)) {
- return false;
- }
- cur_offset_ += num_bytes;
- return true;
-}
-
-template <typename SignedType>
-bool DwarfMemory::ReadSigned(uint64_t* value) {
- SignedType signed_value;
- if (!ReadBytes(&signed_value, sizeof(SignedType))) {
- return false;
- }
- *value = static_cast<int64_t>(signed_value);
- return true;
-}
-
-bool DwarfMemory::ReadULEB128(uint64_t* value) {
- uint64_t cur_value = 0;
- uint64_t shift = 0;
- uint8_t byte;
- do {
- if (!ReadBytes(&byte, 1)) {
- return false;
- }
- cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
- shift += 7;
- } while (byte & 0x80);
- *value = cur_value;
- return true;
-}
-
-bool DwarfMemory::ReadSLEB128(int64_t* value) {
- uint64_t cur_value = 0;
- uint64_t shift = 0;
- uint8_t byte;
- do {
- if (!ReadBytes(&byte, 1)) {
- return false;
- }
- cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
- shift += 7;
- } while (byte & 0x80);
- if (byte & 0x40) {
- // Negative value, need to sign extend.
- cur_value |= static_cast<uint64_t>(-1) << shift;
- }
- *value = static_cast<int64_t>(cur_value);
- return true;
-}
-
-template <typename AddressType>
-size_t DwarfMemory::GetEncodedSize(uint8_t encoding) {
- switch (encoding & 0x0f) {
- case DW_EH_PE_absptr:
- return sizeof(AddressType);
- case DW_EH_PE_udata1:
- case DW_EH_PE_sdata1:
- return 1;
- case DW_EH_PE_udata2:
- case DW_EH_PE_sdata2:
- return 2;
- case DW_EH_PE_udata4:
- case DW_EH_PE_sdata4:
- return 4;
- case DW_EH_PE_udata8:
- case DW_EH_PE_sdata8:
- return 8;
- case DW_EH_PE_uleb128:
- case DW_EH_PE_sleb128:
- default:
- return 0;
- }
-}
-
-bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
- CHECK((encoding & 0x0f) == 0);
-
- // Handle the encoding.
- switch (encoding) {
- case DW_EH_PE_absptr:
- // Nothing to do.
- break;
- case DW_EH_PE_pcrel:
- if (pc_offset_ == INT64_MAX) {
- // Unsupported encoding.
- return false;
- }
- *value += pc_offset_;
- break;
- case DW_EH_PE_textrel:
- if (text_offset_ == static_cast<uint64_t>(-1)) {
- // Unsupported encoding.
- return false;
- }
- *value += text_offset_;
- break;
- case DW_EH_PE_datarel:
- if (data_offset_ == static_cast<uint64_t>(-1)) {
- // Unsupported encoding.
- return false;
- }
- *value += data_offset_;
- break;
- case DW_EH_PE_funcrel:
- if (func_offset_ == static_cast<uint64_t>(-1)) {
- // Unsupported encoding.
- return false;
- }
- *value += func_offset_;
- break;
- default:
- return false;
- }
-
- return true;
-}
-
-template <typename AddressType>
-bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
- if (encoding == DW_EH_PE_omit) {
- *value = 0;
- return true;
- } else if (encoding == DW_EH_PE_aligned) {
- if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
- return false;
- }
- cur_offset_ &= -sizeof(AddressType);
-
- if (sizeof(AddressType) != sizeof(uint64_t)) {
- *value = 0;
- }
- return ReadBytes(value, sizeof(AddressType));
- }
-
- // Get the data.
- switch (encoding & 0x0f) {
- case DW_EH_PE_absptr:
- if (sizeof(AddressType) != sizeof(uint64_t)) {
- *value = 0;
- }
- if (!ReadBytes(value, sizeof(AddressType))) {
- return false;
- }
- break;
- case DW_EH_PE_uleb128:
- if (!ReadULEB128(value)) {
- return false;
- }
- break;
- case DW_EH_PE_sleb128:
- int64_t signed_value;
- if (!ReadSLEB128(&signed_value)) {
- return false;
- }
- *value = static_cast<uint64_t>(signed_value);
- break;
- case DW_EH_PE_udata1: {
- uint8_t value8;
- if (!ReadBytes(&value8, 1)) {
- return false;
- }
- *value = value8;
- } break;
- case DW_EH_PE_sdata1:
- if (!ReadSigned<int8_t>(value)) {
- return false;
- }
- break;
- case DW_EH_PE_udata2: {
- uint16_t value16;
- if (!ReadBytes(&value16, 2)) {
- return false;
- }
- *value = value16;
- } break;
- case DW_EH_PE_sdata2:
- if (!ReadSigned<int16_t>(value)) {
- return false;
- }
- break;
- case DW_EH_PE_udata4: {
- uint32_t value32;
- if (!ReadBytes(&value32, 4)) {
- return false;
- }
- *value = value32;
- } break;
- case DW_EH_PE_sdata4:
- if (!ReadSigned<int32_t>(value)) {
- return false;
- }
- break;
- case DW_EH_PE_udata8:
- if (!ReadBytes(value, sizeof(uint64_t))) {
- return false;
- }
- break;
- case DW_EH_PE_sdata8:
- if (!ReadSigned<int64_t>(value)) {
- return false;
- }
- break;
- default:
- return false;
- }
-
- return AdjustEncodedValue(encoding & 0x70, value);
-}
-
-// Instantiate all of the needed template functions.
-template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
-template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
-template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
-template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);
-
-template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
-template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);
-
-template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
-template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
-
-} // namespace unwindstack
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
deleted file mode 100644
index 393eb3e..0000000
--- a/libunwindstack/DwarfOp.cpp
+++ /dev/null
@@ -1,1941 +0,0 @@
-/*
- * Copyright (C) 2017 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 <deque>
-#include <string>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-#include "DwarfOp.h"
-
-namespace unwindstack {
-
-enum DwarfOpHandleFunc : uint8_t {
- OP_ILLEGAL = 0,
- OP_DEREF,
- OP_DEREF_SIZE,
- OP_PUSH,
- OP_DUP,
- OP_DROP,
- OP_OVER,
- OP_PICK,
- OP_SWAP,
- OP_ROT,
- OP_ABS,
- OP_AND,
- OP_DIV,
- OP_MINUS,
- OP_MOD,
- OP_MUL,
- OP_NEG,
- OP_NOT,
- OP_OR,
- OP_PLUS,
- OP_PLUS_UCONST,
- OP_SHL,
- OP_SHR,
- OP_SHRA,
- OP_XOR,
- OP_BRA,
- OP_EQ,
- OP_GE,
- OP_GT,
- OP_LE,
- OP_LT,
- OP_NE,
- OP_SKIP,
- OP_LIT,
- OP_REG,
- OP_REGX,
- OP_BREG,
- OP_BREGX,
- OP_NOP,
- OP_NOT_IMPLEMENTED,
-};
-
-struct OpCallback {
- // It may seem tempting to "clean this up" by replacing "const char[26]" with
- // "const char*", but doing so would place the entire callback table in
- // .data.rel.ro section, instead of .rodata section, and thus increase
- // dirty memory usage. Libunwindstack is used by the linker and therefore
- // loaded for every running process, so every bit of memory counts.
- // Unlike C standard, C++ standard guarantees this array is big enough to
- // store the names, or else we would get a compilation error.
- const char name[26];
-
- // Similarily for this field, we do NOT want to directly store function
- // pointers here. Not only would that cause the callback table to be placed
- // in .data.rel.ro section, but it would be duplicated for each AddressType.
- // Instead, we use DwarfOpHandleFunc enum to decouple the callback table from
- // the function pointers.
- DwarfOpHandleFunc handle_func;
-
- uint8_t num_required_stack_values;
- uint8_t num_operands;
- uint8_t operands[2];
-};
-
-constexpr static OpCallback kCallbackTable[256] = {
- {"", OP_ILLEGAL, 0, 0, {}}, // 0x00 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0x01 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0x02 illegal op
- {
- // 0x03 DW_OP_addr
- "DW_OP_addr",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_absptr},
- },
- {"", OP_ILLEGAL, 0, 0, {}}, // 0x04 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0x05 illegal op
- {
- // 0x06 DW_OP_deref
- "DW_OP_deref",
- OP_DEREF,
- 1,
- 0,
- {},
- },
- {"", OP_ILLEGAL, 0, 0, {}}, // 0x07 illegal op
- {
- // 0x08 DW_OP_const1u
- "DW_OP_const1u",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x09 DW_OP_const1s
- "DW_OP_const1s",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_sdata1},
- },
- {
- // 0x0a DW_OP_const2u
- "DW_OP_const2u",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_udata2},
- },
- {
- // 0x0b DW_OP_const2s
- "DW_OP_const2s",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_sdata2},
- },
- {
- // 0x0c DW_OP_const4u
- "DW_OP_const4u",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_udata4},
- },
- {
- // 0x0d DW_OP_const4s
- "DW_OP_const4s",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_sdata4},
- },
- {
- // 0x0e DW_OP_const8u
- "DW_OP_const8u",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_udata8},
- },
- {
- // 0x0f DW_OP_const8s
- "DW_OP_const8s",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_sdata8},
- },
- {
- // 0x10 DW_OP_constu
- "DW_OP_constu",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x11 DW_OP_consts
- "DW_OP_consts",
- OP_PUSH,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x12 DW_OP_dup
- "DW_OP_dup",
- OP_DUP,
- 1,
- 0,
- {},
- },
- {
- // 0x13 DW_OP_drop
- "DW_OP_drop",
- OP_DROP,
- 1,
- 0,
- {},
- },
- {
- // 0x14 DW_OP_over
- "DW_OP_over",
- OP_OVER,
- 2,
- 0,
- {},
- },
- {
- // 0x15 DW_OP_pick
- "DW_OP_pick",
- OP_PICK,
- 0,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x16 DW_OP_swap
- "DW_OP_swap",
- OP_SWAP,
- 2,
- 0,
- {},
- },
- {
- // 0x17 DW_OP_rot
- "DW_OP_rot",
- OP_ROT,
- 3,
- 0,
- {},
- },
- {
- // 0x18 DW_OP_xderef
- "DW_OP_xderef",
- OP_NOT_IMPLEMENTED,
- 2,
- 0,
- {},
- },
- {
- // 0x19 DW_OP_abs
- "DW_OP_abs",
- OP_ABS,
- 1,
- 0,
- {},
- },
- {
- // 0x1a DW_OP_and
- "DW_OP_and",
- OP_AND,
- 2,
- 0,
- {},
- },
- {
- // 0x1b DW_OP_div
- "DW_OP_div",
- OP_DIV,
- 2,
- 0,
- {},
- },
- {
- // 0x1c DW_OP_minus
- "DW_OP_minus",
- OP_MINUS,
- 2,
- 0,
- {},
- },
- {
- // 0x1d DW_OP_mod
- "DW_OP_mod",
- OP_MOD,
- 2,
- 0,
- {},
- },
- {
- // 0x1e DW_OP_mul
- "DW_OP_mul",
- OP_MUL,
- 2,
- 0,
- {},
- },
- {
- // 0x1f DW_OP_neg
- "DW_OP_neg",
- OP_NEG,
- 1,
- 0,
- {},
- },
- {
- // 0x20 DW_OP_not
- "DW_OP_not",
- OP_NOT,
- 1,
- 0,
- {},
- },
- {
- // 0x21 DW_OP_or
- "DW_OP_or",
- OP_OR,
- 2,
- 0,
- {},
- },
- {
- // 0x22 DW_OP_plus
- "DW_OP_plus",
- OP_PLUS,
- 2,
- 0,
- {},
- },
- {
- // 0x23 DW_OP_plus_uconst
- "DW_OP_plus_uconst",
- OP_PLUS_UCONST,
- 1,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x24 DW_OP_shl
- "DW_OP_shl",
- OP_SHL,
- 2,
- 0,
- {},
- },
- {
- // 0x25 DW_OP_shr
- "DW_OP_shr",
- OP_SHR,
- 2,
- 0,
- {},
- },
- {
- // 0x26 DW_OP_shra
- "DW_OP_shra",
- OP_SHRA,
- 2,
- 0,
- {},
- },
- {
- // 0x27 DW_OP_xor
- "DW_OP_xor",
- OP_XOR,
- 2,
- 0,
- {},
- },
- {
- // 0x28 DW_OP_bra
- "DW_OP_bra",
- OP_BRA,
- 1,
- 1,
- {DW_EH_PE_sdata2},
- },
- {
- // 0x29 DW_OP_eq
- "DW_OP_eq",
- OP_EQ,
- 2,
- 0,
- {},
- },
- {
- // 0x2a DW_OP_ge
- "DW_OP_ge",
- OP_GE,
- 2,
- 0,
- {},
- },
- {
- // 0x2b DW_OP_gt
- "DW_OP_gt",
- OP_GT,
- 2,
- 0,
- {},
- },
- {
- // 0x2c DW_OP_le
- "DW_OP_le",
- OP_LE,
- 2,
- 0,
- {},
- },
- {
- // 0x2d DW_OP_lt
- "DW_OP_lt",
- OP_LT,
- 2,
- 0,
- {},
- },
- {
- // 0x2e DW_OP_ne
- "DW_OP_ne",
- OP_NE,
- 2,
- 0,
- {},
- },
- {
- // 0x2f DW_OP_skip
- "DW_OP_skip",
- OP_SKIP,
- 0,
- 1,
- {DW_EH_PE_sdata2},
- },
- {
- // 0x30 DW_OP_lit0
- "DW_OP_lit0",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x31 DW_OP_lit1
- "DW_OP_lit1",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x32 DW_OP_lit2
- "DW_OP_lit2",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x33 DW_OP_lit3
- "DW_OP_lit3",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x34 DW_OP_lit4
- "DW_OP_lit4",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x35 DW_OP_lit5
- "DW_OP_lit5",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x36 DW_OP_lit6
- "DW_OP_lit6",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x37 DW_OP_lit7
- "DW_OP_lit7",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x38 DW_OP_lit8
- "DW_OP_lit8",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x39 DW_OP_lit9
- "DW_OP_lit9",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x3a DW_OP_lit10
- "DW_OP_lit10",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x3b DW_OP_lit11
- "DW_OP_lit11",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x3c DW_OP_lit12
- "DW_OP_lit12",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x3d DW_OP_lit13
- "DW_OP_lit13",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x3e DW_OP_lit14
- "DW_OP_lit14",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x3f DW_OP_lit15
- "DW_OP_lit15",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x40 DW_OP_lit16
- "DW_OP_lit16",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x41 DW_OP_lit17
- "DW_OP_lit17",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x42 DW_OP_lit18
- "DW_OP_lit18",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x43 DW_OP_lit19
- "DW_OP_lit19",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x44 DW_OP_lit20
- "DW_OP_lit20",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x45 DW_OP_lit21
- "DW_OP_lit21",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x46 DW_OP_lit22
- "DW_OP_lit22",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x47 DW_OP_lit23
- "DW_OP_lit23",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x48 DW_OP_lit24
- "DW_OP_lit24",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x49 DW_OP_lit25
- "DW_OP_lit25",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x4a DW_OP_lit26
- "DW_OP_lit26",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x4b DW_OP_lit27
- "DW_OP_lit27",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x4c DW_OP_lit28
- "DW_OP_lit28",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x4d DW_OP_lit29
- "DW_OP_lit29",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x4e DW_OP_lit30
- "DW_OP_lit30",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x4f DW_OP_lit31
- "DW_OP_lit31",
- OP_LIT,
- 0,
- 0,
- {},
- },
- {
- // 0x50 DW_OP_reg0
- "DW_OP_reg0",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x51 DW_OP_reg1
- "DW_OP_reg1",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x52 DW_OP_reg2
- "DW_OP_reg2",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x53 DW_OP_reg3
- "DW_OP_reg3",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x54 DW_OP_reg4
- "DW_OP_reg4",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x55 DW_OP_reg5
- "DW_OP_reg5",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x56 DW_OP_reg6
- "DW_OP_reg6",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x57 DW_OP_reg7
- "DW_OP_reg7",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x58 DW_OP_reg8
- "DW_OP_reg8",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x59 DW_OP_reg9
- "DW_OP_reg9",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x5a DW_OP_reg10
- "DW_OP_reg10",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x5b DW_OP_reg11
- "DW_OP_reg11",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x5c DW_OP_reg12
- "DW_OP_reg12",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x5d DW_OP_reg13
- "DW_OP_reg13",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x5e DW_OP_reg14
- "DW_OP_reg14",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x5f DW_OP_reg15
- "DW_OP_reg15",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x60 DW_OP_reg16
- "DW_OP_reg16",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x61 DW_OP_reg17
- "DW_OP_reg17",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x62 DW_OP_reg18
- "DW_OP_reg18",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x63 DW_OP_reg19
- "DW_OP_reg19",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x64 DW_OP_reg20
- "DW_OP_reg20",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x65 DW_OP_reg21
- "DW_OP_reg21",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x66 DW_OP_reg22
- "DW_OP_reg22",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x67 DW_OP_reg23
- "DW_OP_reg23",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x68 DW_OP_reg24
- "DW_OP_reg24",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x69 DW_OP_reg25
- "DW_OP_reg25",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x6a DW_OP_reg26
- "DW_OP_reg26",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x6b DW_OP_reg27
- "DW_OP_reg27",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x6c DW_OP_reg28
- "DW_OP_reg28",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x6d DW_OP_reg29
- "DW_OP_reg29",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x6e DW_OP_reg30
- "DW_OP_reg30",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x6f DW_OP_reg31
- "DW_OP_reg31",
- OP_REG,
- 0,
- 0,
- {},
- },
- {
- // 0x70 DW_OP_breg0
- "DW_OP_breg0",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x71 DW_OP_breg1
- "DW_OP_breg1",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x72 DW_OP_breg2
- "DW_OP_breg2",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x73 DW_OP_breg3
- "DW_OP_breg3",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x74 DW_OP_breg4
- "DW_OP_breg4",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x75 DW_OP_breg5
- "DW_OP_breg5",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x76 DW_OP_breg6
- "DW_OP_breg6",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x77 DW_OP_breg7
- "DW_OP_breg7",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x78 DW_OP_breg8
- "DW_OP_breg8",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x79 DW_OP_breg9
- "DW_OP_breg9",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7a DW_OP_breg10
- "DW_OP_breg10",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7b DW_OP_breg11
- "DW_OP_breg11",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7c DW_OP_breg12
- "DW_OP_breg12",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7d DW_OP_breg13
- "DW_OP_breg13",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7e DW_OP_breg14
- "DW_OP_breg14",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x7f DW_OP_breg15
- "DW_OP_breg15",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x80 DW_OP_breg16
- "DW_OP_breg16",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x81 DW_OP_breg17
- "DW_OP_breg17",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x82 DW_OP_breg18
- "DW_OP_breg18",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x83 DW_OP_breg19
- "DW_OP_breg19",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x84 DW_OP_breg20
- "DW_OP_breg20",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x85 DW_OP_breg21
- "DW_OP_breg21",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x86 DW_OP_breg22
- "DW_OP_breg22",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x87 DW_OP_breg23
- "DW_OP_breg23",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x88 DW_OP_breg24
- "DW_OP_breg24",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x89 DW_OP_breg25
- "DW_OP_breg25",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8a DW_OP_breg26
- "DW_OP_breg26",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8b DW_OP_breg27
- "DW_OP_breg27",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8c DW_OP_breg28
- "DW_OP_breg28",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8d DW_OP_breg29
- "DW_OP_breg29",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8e DW_OP_breg30
- "DW_OP_breg30",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x8f DW_OP_breg31
- "DW_OP_breg31",
- OP_BREG,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x90 DW_OP_regx
- "DW_OP_regx",
- OP_REGX,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x91 DW_OP_fbreg
- "DW_OP_fbreg",
- OP_NOT_IMPLEMENTED,
- 0,
- 1,
- {DW_EH_PE_sleb128},
- },
- {
- // 0x92 DW_OP_bregx
- "DW_OP_bregx",
- OP_BREGX,
- 0,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_sleb128},
- },
- {
- // 0x93 DW_OP_piece
- "DW_OP_piece",
- OP_NOT_IMPLEMENTED,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x94 DW_OP_deref_size
- "DW_OP_deref_size",
- OP_DEREF_SIZE,
- 1,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x95 DW_OP_xderef_size
- "DW_OP_xderef_size",
- OP_NOT_IMPLEMENTED,
- 0,
- 1,
- {DW_EH_PE_udata1},
- },
- {
- // 0x96 DW_OP_nop
- "DW_OP_nop",
- OP_NOP,
- 0,
- 0,
- {},
- },
- {
- // 0x97 DW_OP_push_object_address
- "DW_OP_push_object_address",
- OP_NOT_IMPLEMENTED,
- 0,
- 0,
- {},
- },
- {
- // 0x98 DW_OP_call2
- "DW_OP_call2",
- OP_NOT_IMPLEMENTED,
- 0,
- 1,
- {DW_EH_PE_udata2},
- },
- {
- // 0x99 DW_OP_call4
- "DW_OP_call4",
- OP_NOT_IMPLEMENTED,
- 0,
- 1,
- {DW_EH_PE_udata4},
- },
- {
- // 0x9a DW_OP_call_ref
- "DW_OP_call_ref",
- OP_NOT_IMPLEMENTED,
- 0,
- 0, // Has a different sized operand (4 bytes or 8 bytes).
- {},
- },
- {
- // 0x9b DW_OP_form_tls_address
- "DW_OP_form_tls_address",
- OP_NOT_IMPLEMENTED,
- 0,
- 0,
- {},
- },
- {
- // 0x9c DW_OP_call_frame_cfa
- "DW_OP_call_frame_cfa",
- OP_NOT_IMPLEMENTED,
- 0,
- 0,
- {},
- },
- {
- // 0x9d DW_OP_bit_piece
- "DW_OP_bit_piece",
- OP_NOT_IMPLEMENTED,
- 0,
- 2,
- {DW_EH_PE_uleb128, DW_EH_PE_uleb128},
- },
- {
- // 0x9e DW_OP_implicit_value
- "DW_OP_implicit_value",
- OP_NOT_IMPLEMENTED,
- 0,
- 1,
- {DW_EH_PE_uleb128},
- },
- {
- // 0x9f DW_OP_stack_value
- "DW_OP_stack_value",
- OP_NOT_IMPLEMENTED,
- 1,
- 0,
- {},
- },
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa0 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa1 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa2 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa3 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa4 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa5 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa6 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa7 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa8 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xa9 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xaa illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xab illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xac illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xad illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xae illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xaf illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb0 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb1 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb2 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb3 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb4 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb5 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb6 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb7 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb8 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xb9 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xba illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xbb illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xbc illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xbd illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xbe illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xbf illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc0 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc1 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc2 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc3 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc4 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc5 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc6 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc7 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc8 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xc9 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xca illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xcb illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xcc illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xcd illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xce illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xcf illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd0 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd1 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd2 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd3 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd4 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd5 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd6 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd7 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd8 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xd9 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xda illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xdb illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xdc illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xdd illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xde illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xdf illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe0 DW_OP_lo_user
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe1 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe2 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe3 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe4 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe5 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe6 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe7 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe8 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xe9 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xea illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xeb illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xec illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xed illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xee illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xef illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf0 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf1 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf2 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf3 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf4 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf5 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf6 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf7 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf8 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xf9 illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xfa illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xfb illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xfc illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xfd illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xfe illegal op
- {"", OP_ILLEGAL, 0, 0, {}}, // 0xff DW_OP_hi_user
-};
-
-template <typename AddressType>
-const typename DwarfOp<AddressType>::OpHandleFuncPtr DwarfOp<AddressType>::kOpHandleFuncList[] = {
- [OP_ILLEGAL] = nullptr,
- [OP_DEREF] = &DwarfOp<AddressType>::op_deref,
- [OP_DEREF_SIZE] = &DwarfOp<AddressType>::op_deref_size,
- [OP_PUSH] = &DwarfOp<AddressType>::op_push,
- [OP_DUP] = &DwarfOp<AddressType>::op_dup,
- [OP_DROP] = &DwarfOp<AddressType>::op_drop,
- [OP_OVER] = &DwarfOp<AddressType>::op_over,
- [OP_PICK] = &DwarfOp<AddressType>::op_pick,
- [OP_SWAP] = &DwarfOp<AddressType>::op_swap,
- [OP_ROT] = &DwarfOp<AddressType>::op_rot,
- [OP_ABS] = &DwarfOp<AddressType>::op_abs,
- [OP_AND] = &DwarfOp<AddressType>::op_and,
- [OP_DIV] = &DwarfOp<AddressType>::op_div,
- [OP_MINUS] = &DwarfOp<AddressType>::op_minus,
- [OP_MOD] = &DwarfOp<AddressType>::op_mod,
- [OP_MUL] = &DwarfOp<AddressType>::op_mul,
- [OP_NEG] = &DwarfOp<AddressType>::op_neg,
- [OP_NOT] = &DwarfOp<AddressType>::op_not,
- [OP_OR] = &DwarfOp<AddressType>::op_or,
- [OP_PLUS] = &DwarfOp<AddressType>::op_plus,
- [OP_PLUS_UCONST] = &DwarfOp<AddressType>::op_plus_uconst,
- [OP_SHL] = &DwarfOp<AddressType>::op_shl,
- [OP_SHR] = &DwarfOp<AddressType>::op_shr,
- [OP_SHRA] = &DwarfOp<AddressType>::op_shra,
- [OP_XOR] = &DwarfOp<AddressType>::op_xor,
- [OP_BRA] = &DwarfOp<AddressType>::op_bra,
- [OP_EQ] = &DwarfOp<AddressType>::op_eq,
- [OP_GE] = &DwarfOp<AddressType>::op_ge,
- [OP_GT] = &DwarfOp<AddressType>::op_gt,
- [OP_LE] = &DwarfOp<AddressType>::op_le,
- [OP_LT] = &DwarfOp<AddressType>::op_lt,
- [OP_NE] = &DwarfOp<AddressType>::op_ne,
- [OP_SKIP] = &DwarfOp<AddressType>::op_skip,
- [OP_LIT] = &DwarfOp<AddressType>::op_lit,
- [OP_REG] = &DwarfOp<AddressType>::op_reg,
- [OP_REGX] = &DwarfOp<AddressType>::op_regx,
- [OP_BREG] = &DwarfOp<AddressType>::op_breg,
- [OP_BREGX] = &DwarfOp<AddressType>::op_bregx,
- [OP_NOP] = &DwarfOp<AddressType>::op_nop,
- [OP_NOT_IMPLEMENTED] = &DwarfOp<AddressType>::op_not_implemented,
-};
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end) {
- is_register_ = false;
- stack_.clear();
- memory_->set_cur_offset(start);
- dex_pc_set_ = false;
-
- // Unroll the first Decode calls to be able to check for a special
- // sequence of ops and values that indicate this is the dex pc.
- // The pattern is:
- // OP_const4u (0x0c) 'D' 'E' 'X' '1'
- // OP_drop (0x13)
- if (memory_->cur_offset() < end) {
- if (!Decode()) {
- return false;
- }
- } else {
- return true;
- }
- bool check_for_drop;
- if (cur_op_ == 0x0c && operands_.back() == 0x31584544) {
- check_for_drop = true;
- } else {
- check_for_drop = false;
- }
- if (memory_->cur_offset() < end) {
- if (!Decode()) {
- return false;
- }
- } else {
- return true;
- }
-
- if (check_for_drop && cur_op_ == 0x13) {
- dex_pc_set_ = true;
- }
-
- uint32_t iterations = 2;
- while (memory_->cur_offset() < end) {
- if (!Decode()) {
- return false;
- }
- // To protect against a branch that creates an infinite loop,
- // terminate if the number of iterations gets too high.
- if (iterations++ == 1000) {
- last_error_.code = DWARF_ERROR_TOO_MANY_ITERATIONS;
- return false;
- }
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::Decode() {
- last_error_.code = DWARF_ERROR_NONE;
- if (!memory_->ReadBytes(&cur_op_, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_->cur_offset();
- return false;
- }
-
- const auto* op = &kCallbackTable[cur_op_];
- if (op->handle_func == OP_ILLEGAL) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- const auto handle_func = kOpHandleFuncList[op->handle_func];
-
- // Make sure that the required number of stack elements is available.
- if (stack_.size() < op->num_required_stack_values) {
- last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
- return false;
- }
-
- operands_.clear();
- for (size_t i = 0; i < op->num_operands; i++) {
- uint64_t value;
- if (!memory_->ReadEncodedValue<AddressType>(op->operands[i], &value)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_->cur_offset();
- return false;
- }
- operands_.push_back(value);
- }
- return (this->*handle_func)();
-}
-
-template <typename AddressType>
-void DwarfOp<AddressType>::GetLogInfo(uint64_t start, uint64_t end,
- std::vector<std::string>* lines) {
- memory_->set_cur_offset(start);
- while (memory_->cur_offset() < end) {
- uint8_t cur_op;
- if (!memory_->ReadBytes(&cur_op, 1)) {
- return;
- }
-
- std::string raw_string(android::base::StringPrintf("Raw Data: 0x%02x", cur_op));
- std::string log_string;
- const auto* op = &kCallbackTable[cur_op];
- if (op->handle_func == OP_ILLEGAL) {
- log_string = "Illegal";
- } else {
- log_string = op->name;
- uint64_t start_offset = memory_->cur_offset();
- for (size_t i = 0; i < op->num_operands; i++) {
- uint64_t value;
- if (!memory_->ReadEncodedValue<AddressType>(op->operands[i], &value)) {
- return;
- }
- log_string += ' ' + std::to_string(value);
- }
- uint64_t end_offset = memory_->cur_offset();
-
- memory_->set_cur_offset(start_offset);
- for (size_t i = start_offset; i < end_offset; i++) {
- uint8_t byte;
- if (!memory_->ReadBytes(&byte, 1)) {
- return;
- }
- raw_string += android::base::StringPrintf(" 0x%02x", byte);
- }
- memory_->set_cur_offset(end_offset);
- }
- lines->push_back(std::move(log_string));
- lines->push_back(std::move(raw_string));
- }
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_deref() {
- // Read the address and dereference it.
- AddressType addr = StackPop();
- AddressType value;
- if (!regular_memory()->ReadFully(addr, &value, sizeof(value))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = addr;
- return false;
- }
- stack_.push_front(value);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_deref_size() {
- AddressType bytes_to_read = OperandAt(0);
- if (bytes_to_read > sizeof(AddressType) || bytes_to_read == 0) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- // Read the address and dereference it.
- AddressType addr = StackPop();
- AddressType value = 0;
- if (!regular_memory()->ReadFully(addr, &value, bytes_to_read)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = addr;
- return false;
- }
- stack_.push_front(value);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_push() {
- // Push all of the operands.
- for (auto operand : operands_) {
- stack_.push_front(operand);
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_dup() {
- stack_.push_front(StackAt(0));
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_drop() {
- StackPop();
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_over() {
- stack_.push_front(StackAt(1));
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_pick() {
- AddressType index = OperandAt(0);
- if (index > StackSize()) {
- last_error_.code = DWARF_ERROR_STACK_INDEX_NOT_VALID;
- return false;
- }
- stack_.push_front(StackAt(index));
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_swap() {
- AddressType old_value = stack_[0];
- stack_[0] = stack_[1];
- stack_[1] = old_value;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_rot() {
- AddressType top = stack_[0];
- stack_[0] = stack_[1];
- stack_[1] = stack_[2];
- stack_[2] = top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_abs() {
- SignedType signed_value = static_cast<SignedType>(stack_[0]);
- if (signed_value < 0) {
- signed_value = -signed_value;
- }
- stack_[0] = static_cast<AddressType>(signed_value);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_and() {
- AddressType top = StackPop();
- stack_[0] &= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_div() {
- AddressType top = StackPop();
- if (top == 0) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- SignedType signed_divisor = static_cast<SignedType>(top);
- SignedType signed_dividend = static_cast<SignedType>(stack_[0]);
- stack_[0] = static_cast<AddressType>(signed_dividend / signed_divisor);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_minus() {
- AddressType top = StackPop();
- stack_[0] -= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_mod() {
- AddressType top = StackPop();
- if (top == 0) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- stack_[0] %= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_mul() {
- AddressType top = StackPop();
- stack_[0] *= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_neg() {
- SignedType signed_value = static_cast<SignedType>(stack_[0]);
- stack_[0] = static_cast<AddressType>(-signed_value);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_not() {
- stack_[0] = ~stack_[0];
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_or() {
- AddressType top = StackPop();
- stack_[0] |= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_plus() {
- AddressType top = StackPop();
- stack_[0] += top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_plus_uconst() {
- stack_[0] += OperandAt(0);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_shl() {
- AddressType top = StackPop();
- stack_[0] <<= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_shr() {
- AddressType top = StackPop();
- stack_[0] >>= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_shra() {
- AddressType top = StackPop();
- SignedType signed_value = static_cast<SignedType>(stack_[0]) >> top;
- stack_[0] = static_cast<AddressType>(signed_value);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_xor() {
- AddressType top = StackPop();
- stack_[0] ^= top;
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_bra() {
- // Requires one stack element.
- AddressType top = StackPop();
- int16_t offset = static_cast<int16_t>(OperandAt(0));
- uint64_t cur_offset;
- if (top != 0) {
- cur_offset = memory_->cur_offset() + offset;
- } else {
- cur_offset = memory_->cur_offset() - offset;
- }
- memory_->set_cur_offset(cur_offset);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_eq() {
- AddressType top = StackPop();
- stack_[0] = bool_to_dwarf_bool(stack_[0] == top);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_ge() {
- AddressType top = StackPop();
- stack_[0] = bool_to_dwarf_bool(stack_[0] >= top);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_gt() {
- AddressType top = StackPop();
- stack_[0] = bool_to_dwarf_bool(stack_[0] > top);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_le() {
- AddressType top = StackPop();
- stack_[0] = bool_to_dwarf_bool(stack_[0] <= top);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_lt() {
- AddressType top = StackPop();
- stack_[0] = bool_to_dwarf_bool(stack_[0] < top);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_ne() {
- AddressType top = StackPop();
- stack_[0] = bool_to_dwarf_bool(stack_[0] != top);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_skip() {
- int16_t offset = static_cast<int16_t>(OperandAt(0));
- uint64_t cur_offset = memory_->cur_offset() + offset;
- memory_->set_cur_offset(cur_offset);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_lit() {
- stack_.push_front(cur_op() - 0x30);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_reg() {
- is_register_ = true;
- stack_.push_front(cur_op() - 0x50);
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_regx() {
- is_register_ = true;
- stack_.push_front(OperandAt(0));
- return true;
-}
-
-// It's not clear for breg/bregx, if this op should read the current
-// value of the register, or where we think that register is located.
-// For simplicity, the code will read the value before doing the unwind.
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_breg() {
- uint16_t reg = cur_op() - 0x70;
- if (reg >= regs_info_->Total()) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- stack_.push_front(regs_info_->Get(reg) + OperandAt(0));
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_bregx() {
- AddressType reg = OperandAt(0);
- if (reg >= regs_info_->Total()) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- stack_.push_front(regs_info_->Get(reg) + OperandAt(1));
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_nop() {
- return true;
-}
-
-template <typename AddressType>
-bool DwarfOp<AddressType>::op_not_implemented() {
- last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
- return false;
-}
-
-// Explicitly instantiate DwarfOp.
-template class DwarfOp<uint32_t>;
-template class DwarfOp<uint64_t>;
-
-} // namespace unwindstack
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
deleted file mode 100644
index ac9fd2d..0000000
--- a/libunwindstack/DwarfOp.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_OP_H
-#define _LIBUNWINDSTACK_DWARF_OP_H
-
-#include <stdint.h>
-
-#include <deque>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-#include <unwindstack/DwarfError.h>
-
-#include "DwarfEncoding.h"
-#include "RegsInfo.h"
-
-namespace unwindstack {
-
-// Forward declarations.
-class DwarfMemory;
-class Memory;
-template <typename AddressType>
-class RegsImpl;
-
-template <typename AddressType>
-class DwarfOp {
- // Signed version of AddressType
- typedef typename std::make_signed<AddressType>::type SignedType;
-
- public:
- DwarfOp(DwarfMemory* memory, Memory* regular_memory)
- : memory_(memory), regular_memory_(regular_memory) {}
- virtual ~DwarfOp() = default;
-
- bool Decode();
-
- bool Eval(uint64_t start, uint64_t end);
-
- void GetLogInfo(uint64_t start, uint64_t end, std::vector<std::string>* lines);
-
- AddressType StackAt(size_t index) { return stack_[index]; }
- size_t StackSize() { return stack_.size(); }
-
- void set_regs_info(RegsInfo<AddressType>* regs_info) { regs_info_ = regs_info; }
-
- const DwarfErrorData& last_error() { return last_error_; }
- DwarfErrorCode LastErrorCode() { return last_error_.code; }
- uint64_t LastErrorAddress() { return last_error_.address; }
-
- bool dex_pc_set() { return dex_pc_set_; }
-
- bool is_register() { return is_register_; }
-
- uint8_t cur_op() { return cur_op_; }
-
- Memory* regular_memory() { return regular_memory_; }
-
- protected:
- AddressType OperandAt(size_t index) { return operands_[index]; }
- size_t OperandsSize() { return operands_.size(); }
-
- AddressType StackPop() {
- AddressType value = stack_.front();
- stack_.pop_front();
- return value;
- }
-
- private:
- DwarfMemory* memory_;
- Memory* regular_memory_;
-
- RegsInfo<AddressType>* regs_info_;
- bool dex_pc_set_ = false;
- bool is_register_ = false;
- DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
- uint8_t cur_op_;
- std::vector<AddressType> operands_;
- std::deque<AddressType> stack_;
-
- inline AddressType bool_to_dwarf_bool(bool value) { return value ? 1 : 0; }
-
- // Op processing functions.
- bool op_deref();
- bool op_deref_size();
- bool op_push();
- bool op_dup();
- bool op_drop();
- bool op_over();
- bool op_pick();
- bool op_swap();
- bool op_rot();
- bool op_abs();
- bool op_and();
- bool op_div();
- bool op_minus();
- bool op_mod();
- bool op_mul();
- bool op_neg();
- bool op_not();
- bool op_or();
- bool op_plus();
- bool op_plus_uconst();
- bool op_shl();
- bool op_shr();
- bool op_shra();
- bool op_xor();
- bool op_bra();
- bool op_eq();
- bool op_ge();
- bool op_gt();
- bool op_le();
- bool op_lt();
- bool op_ne();
- bool op_skip();
- bool op_lit();
- bool op_reg();
- bool op_regx();
- bool op_breg();
- bool op_bregx();
- bool op_nop();
- bool op_not_implemented();
-
- using OpHandleFuncPtr = bool (DwarfOp::*)();
- static const OpHandleFuncPtr kOpHandleFuncList[];
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_OP_H
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
deleted file mode 100644
index bf86e6e..0000000
--- a/libunwindstack/DwarfSection.cpp
+++ /dev/null
@@ -1,822 +0,0 @@
-/*
- * Copyright (C) 2017 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 <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/DwarfStructs.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-#include "DwarfCfa.h"
-#include "DwarfDebugFrame.h"
-#include "DwarfEhFrame.h"
-#include "DwarfEncoding.h"
-#include "DwarfOp.h"
-#include "RegsInfo.h"
-
-namespace unwindstack {
-
-DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
-
-bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- // Lookup the pc in the cache.
- auto it = loc_regs_.upper_bound(pc);
- if (it == loc_regs_.end() || pc < it->second.pc_start) {
- last_error_.code = DWARF_ERROR_NONE;
- const DwarfFde* fde = GetFdeFromPc(pc);
- if (fde == nullptr || fde->cie == nullptr) {
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
-
- // Now get the location information for this pc.
- dwarf_loc_regs_t loc_regs;
- if (!GetCfaLocationInfo(pc, fde, &loc_regs, regs->Arch())) {
- return false;
- }
- loc_regs.cie = fde->cie;
-
- // Store it in the cache.
- it = loc_regs_.emplace(loc_regs.pc_end, std::move(loc_regs)).first;
- }
-
- // Now eval the actual registers.
- return Eval(it->second.cie, process_memory, it->second, regs, finished);
-}
-
-template <typename AddressType>
-const DwarfCie* DwarfSectionImpl<AddressType>::GetCieFromOffset(uint64_t offset) {
- auto cie_entry = cie_entries_.find(offset);
- if (cie_entry != cie_entries_.end()) {
- return &cie_entry->second;
- }
- DwarfCie* cie = &cie_entries_[offset];
- memory_.set_data_offset(entries_offset_);
- memory_.set_cur_offset(offset);
- if (!FillInCieHeader(cie) || !FillInCie(cie)) {
- // Erase the cached entry.
- cie_entries_.erase(offset);
- return nullptr;
- }
- return cie;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInCieHeader(DwarfCie* cie) {
- cie->lsda_encoding = DW_EH_PE_omit;
- uint32_t length32;
- if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (length32 == static_cast<uint32_t>(-1)) {
- // 64 bit Cie
- uint64_t length64;
- if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- cie->cfa_instructions_end = memory_.cur_offset() + length64;
- cie->fde_address_encoding = DW_EH_PE_sdata8;
-
- uint64_t cie_id;
- if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (cie_id != cie64_value_) {
- // This is not a Cie, something has gone horribly wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- } else {
- // 32 bit Cie
- cie->cfa_instructions_end = memory_.cur_offset() + length32;
- cie->fde_address_encoding = DW_EH_PE_sdata4;
-
- uint32_t cie_id;
- if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (cie_id != cie32_value_) {
- // This is not a Cie, something has gone horribly wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
- if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->version != 1 && cie->version != 3 && cie->version != 4 && cie->version != 5) {
- // Unrecognized version.
- last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
- return false;
- }
-
- // Read the augmentation string.
- char aug_value;
- do {
- if (!memory_.ReadBytes(&aug_value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->augmentation_string.push_back(aug_value);
- } while (aug_value != '\0');
-
- if (cie->version == 4 || cie->version == 5) {
- // Skip the Address Size field since we only use it for validation.
- memory_.set_cur_offset(memory_.cur_offset() + 1);
-
- // Segment Size
- if (!memory_.ReadBytes(&cie->segment_size, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- }
-
- // Code Alignment Factor
- if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- // Data Alignment Factor
- if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->version == 1) {
- // Return Address is a single byte.
- uint8_t return_address_register;
- if (!memory_.ReadBytes(&return_address_register, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->return_address_register = return_address_register;
- } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->augmentation_string[0] != 'z') {
- cie->cfa_instructions_offset = memory_.cur_offset();
- return true;
- }
-
- uint64_t aug_length;
- if (!memory_.ReadULEB128(&aug_length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
-
- for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
- switch (cie->augmentation_string[i]) {
- case 'L':
- if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- break;
- case 'P': {
- uint8_t encoding;
- if (!memory_.ReadBytes(&encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } break;
- case 'R':
- if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- break;
- }
- }
- return true;
-}
-
-template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
- auto fde_entry = fde_entries_.find(offset);
- if (fde_entry != fde_entries_.end()) {
- return &fde_entry->second;
- }
- DwarfFde* fde = &fde_entries_[offset];
- memory_.set_data_offset(entries_offset_);
- memory_.set_cur_offset(offset);
- if (!FillInFdeHeader(fde) || !FillInFde(fde)) {
- fde_entries_.erase(offset);
- return nullptr;
- }
- return fde;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInFdeHeader(DwarfFde* fde) {
- uint32_t length32;
- if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (length32 == static_cast<uint32_t>(-1)) {
- // 64 bit Fde.
- uint64_t length64;
- if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- fde->cfa_instructions_end = memory_.cur_offset() + length64;
-
- uint64_t value64;
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (value64 == cie64_value_) {
- // This is a Cie, this means something has gone wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Get the Cie pointer, which is necessary to properly read the rest of
- // of the Fde information.
- fde->cie_offset = GetCieOffsetFromFde64(value64);
- } else {
- // 32 bit Fde.
- fde->cfa_instructions_end = memory_.cur_offset() + length32;
-
- uint32_t value32;
- if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (value32 == cie32_value_) {
- // This is a Cie, this means something has gone wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Get the Cie pointer, which is necessary to properly read the rest of
- // of the Fde information.
- fde->cie_offset = GetCieOffsetFromFde32(value32);
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
- uint64_t cur_offset = memory_.cur_offset();
-
- const DwarfCie* cie = GetCieFromOffset(fde->cie_offset);
- if (cie == nullptr) {
- return false;
- }
- fde->cie = cie;
-
- if (cie->segment_size != 0) {
- // Skip over the segment selector for now.
- cur_offset += cie->segment_size;
- }
- memory_.set_cur_offset(cur_offset);
-
- // The load bias only applies to the start.
- memory_.set_pc_offset(section_bias_);
- bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
- fde->pc_start = AdjustPcFromFde(fde->pc_start);
-
- memory_.set_pc_offset(0);
- if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- fde->pc_end += fde->pc_start;
-
- if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
- // Augmentation Size
- uint64_t aug_length;
- if (!memory_.ReadULEB128(&aug_length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- uint64_t cur_offset = memory_.cur_offset();
-
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- // Set our position to after all of the augmentation data.
- memory_.set_cur_offset(cur_offset + aug_length);
- }
- fde->cfa_instructions_offset = memory_.cur_offset();
-
- return true;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory,
- AddressType* value,
- RegsInfo<AddressType>* regs_info,
- bool* is_dex_pc) {
- DwarfOp<AddressType> op(&memory_, regular_memory);
- op.set_regs_info(regs_info);
-
- // Need to evaluate the op data.
- uint64_t end = loc.values[1];
- uint64_t start = end - loc.values[0];
- if (!op.Eval(start, end)) {
- last_error_ = op.last_error();
- return false;
- }
- if (op.StackSize() == 0) {
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return false;
- }
- // We don't support an expression that evaluates to a register number.
- if (op.is_register()) {
- last_error_.code = DWARF_ERROR_NOT_IMPLEMENTED;
- return false;
- }
- *value = op.StackAt(0);
- if (is_dex_pc != nullptr && op.dex_pc_set()) {
- *is_dex_pc = true;
- }
- return true;
-}
-
-template <typename AddressType>
-struct EvalInfo {
- const dwarf_loc_regs_t* loc_regs;
- const DwarfCie* cie;
- Memory* regular_memory;
- AddressType cfa;
- bool return_address_undefined = false;
- RegsInfo<AddressType> regs_info;
-};
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint32_t reg,
- AddressType* reg_ptr, void* info) {
- EvalInfo<AddressType>* eval_info = reinterpret_cast<EvalInfo<AddressType>*>(info);
- Memory* regular_memory = eval_info->regular_memory;
- switch (loc->type) {
- case DWARF_LOCATION_OFFSET:
- if (!regular_memory->ReadFully(eval_info->cfa + loc->values[0], reg_ptr, sizeof(AddressType))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = eval_info->cfa + loc->values[0];
- return false;
- }
- break;
- case DWARF_LOCATION_VAL_OFFSET:
- *reg_ptr = eval_info->cfa + loc->values[0];
- break;
- case DWARF_LOCATION_REGISTER: {
- uint32_t cur_reg = loc->values[0];
- if (cur_reg >= eval_info->regs_info.Total()) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- *reg_ptr = eval_info->regs_info.Get(cur_reg) + loc->values[1];
- break;
- }
- case DWARF_LOCATION_EXPRESSION:
- case DWARF_LOCATION_VAL_EXPRESSION: {
- AddressType value;
- bool is_dex_pc = false;
- if (!EvalExpression(*loc, regular_memory, &value, &eval_info->regs_info, &is_dex_pc)) {
- return false;
- }
- if (loc->type == DWARF_LOCATION_EXPRESSION) {
- if (!regular_memory->ReadFully(value, reg_ptr, sizeof(AddressType))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = value;
- return false;
- }
- } else {
- *reg_ptr = value;
- if (is_dex_pc) {
- eval_info->regs_info.regs->set_dex_pc(value);
- }
- }
- break;
- }
- case DWARF_LOCATION_UNDEFINED:
- if (reg == eval_info->cie->return_address_register) {
- eval_info->return_address_undefined = true;
- }
- break;
- case DWARF_LOCATION_PSEUDO_REGISTER:
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- default:
- break;
- }
-
- return true;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_memory,
- const dwarf_loc_regs_t& loc_regs, Regs* regs,
- bool* finished) {
- RegsImpl<AddressType>* cur_regs = reinterpret_cast<RegsImpl<AddressType>*>(regs);
- if (cie->return_address_register >= cur_regs->total_regs()) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Get the cfa value;
- auto cfa_entry = loc_regs.find(CFA_REG);
- if (cfa_entry == loc_regs.end()) {
- last_error_.code = DWARF_ERROR_CFA_NOT_DEFINED;
- return false;
- }
-
- // Always set the dex pc to zero when evaluating.
- cur_regs->set_dex_pc(0);
-
- // Reset necessary pseudo registers before evaluation.
- // This is needed for ARM64, for example.
- regs->ResetPseudoRegisters();
-
- EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs,
- .cie = cie,
- .regular_memory = regular_memory,
- .regs_info = RegsInfo<AddressType>(cur_regs)};
- const DwarfLocation* loc = &cfa_entry->second;
- // Only a few location types are valid for the cfa.
- switch (loc->type) {
- case DWARF_LOCATION_REGISTER:
- if (loc->values[0] >= cur_regs->total_regs()) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- eval_info.cfa = (*cur_regs)[loc->values[0]];
- eval_info.cfa += loc->values[1];
- break;
- case DWARF_LOCATION_VAL_EXPRESSION: {
- AddressType value;
- if (!EvalExpression(*loc, regular_memory, &value, &eval_info.regs_info, nullptr)) {
- return false;
- }
- // There is only one type of valid expression for CFA evaluation.
- eval_info.cfa = value;
- break;
- }
- default:
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- for (const auto& entry : loc_regs) {
- uint32_t reg = entry.first;
- // Already handled the CFA register.
- if (reg == CFA_REG) continue;
-
- AddressType* reg_ptr;
- if (reg >= cur_regs->total_regs()) {
- if (entry.second.type != DWARF_LOCATION_PSEUDO_REGISTER) {
- // Skip this unknown register.
- continue;
- }
- if (!eval_info.regs_info.regs->SetPseudoRegister(reg, entry.second.values[0])) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- } else {
- reg_ptr = eval_info.regs_info.Save(reg);
- if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
- return false;
- }
- }
- }
-
- // Find the return address location.
- if (eval_info.return_address_undefined) {
- cur_regs->set_pc(0);
- } else {
- cur_regs->set_pc((*cur_regs)[cie->return_address_register]);
- }
-
- // If the pc was set to zero, consider this the final frame.
- *finished = (cur_regs->pc() == 0) ? true : false;
-
- cur_regs->set_sp(eval_info.cfa);
-
- return true;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
- dwarf_loc_regs_t* loc_regs, ArchEnum arch) {
- DwarfCfa<AddressType> cfa(&memory_, fde, arch);
-
- // Look for the cached copy of the cie data.
- auto reg_entry = cie_loc_regs_.find(fde->cie_offset);
- if (reg_entry == cie_loc_regs_.end()) {
- if (!cfa.GetLocationInfo(pc, fde->cie->cfa_instructions_offset, fde->cie->cfa_instructions_end,
- loc_regs)) {
- last_error_ = cfa.last_error();
- return false;
- }
- cie_loc_regs_[fde->cie_offset] = *loc_regs;
- }
- cfa.set_cie_loc_regs(&cie_loc_regs_[fde->cie_offset]);
- if (!cfa.GetLocationInfo(pc, fde->cfa_instructions_offset, fde->cfa_instructions_end, loc_regs)) {
- last_error_ = cfa.last_error();
- return false;
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde,
- ArchEnum arch) {
- DwarfCfa<AddressType> cfa(&memory_, fde, arch);
-
- // Always print the cie information.
- const DwarfCie* cie = fde->cie;
- if (!cfa.Log(indent, pc, cie->cfa_instructions_offset, cie->cfa_instructions_end)) {
- last_error_ = cfa.last_error();
- return false;
- }
- if (!cfa.Log(indent, pc, fde->cfa_instructions_offset, fde->cfa_instructions_end)) {
- last_error_ = cfa.last_error();
- return false;
- }
- return true;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
- section_bias_ = section_bias;
- entries_offset_ = offset;
- next_entries_offset_ = offset;
- entries_end_ = offset + size;
-
- memory_.clear_func_offset();
- memory_.clear_text_offset();
- memory_.set_cur_offset(offset);
- pc_offset_ = offset;
-
- return true;
-}
-
-// Create a cached version of the fde information such that it is a std::map
-// that is indexed by end pc and contains a pair that represents the start pc
-// followed by the fde object. The fde pointers are owned by fde_entries_
-// and not by the map object.
-// It is possible for an fde to be represented by multiple entries in
-// the map. This can happen if the the start pc and end pc overlap already
-// existing entries. For example, if there is already an entry of 0x400, 0x200,
-// and an fde has a start pc of 0x100 and end pc of 0x500, two new entries
-// will be added: 0x200, 0x100 and 0x500, 0x400.
-template <typename AddressType>
-void DwarfSectionImpl<AddressType>::InsertFde(const DwarfFde* fde) {
- uint64_t start = fde->pc_start;
- uint64_t end = fde->pc_end;
- auto it = fdes_.upper_bound(start);
- while (it != fdes_.end() && start < end && it->second.first < end) {
- if (start < it->second.first) {
- fdes_[it->second.first] = std::make_pair(start, fde);
- }
- start = it->first;
- ++it;
- }
- if (start < end) {
- fdes_[end] = std::make_pair(start, fde);
- }
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::GetNextCieOrFde(const DwarfFde** fde_entry) {
- uint64_t start_offset = next_entries_offset_;
-
- memory_.set_data_offset(entries_offset_);
- memory_.set_cur_offset(next_entries_offset_);
- uint32_t value32;
- if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- uint64_t cie_offset;
- uint8_t cie_fde_encoding;
- bool entry_is_cie = false;
- if (value32 == static_cast<uint32_t>(-1)) {
- // 64 bit entry.
- uint64_t value64;
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- next_entries_offset_ = memory_.cur_offset() + value64;
- // Read the Cie Id of a Cie or the pointer of the Fde.
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (value64 == cie64_value_) {
- entry_is_cie = true;
- cie_fde_encoding = DW_EH_PE_sdata8;
- } else {
- cie_offset = GetCieOffsetFromFde64(value64);
- }
- } else {
- next_entries_offset_ = memory_.cur_offset() + value32;
-
- // 32 bit Cie
- if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (value32 == cie32_value_) {
- entry_is_cie = true;
- cie_fde_encoding = DW_EH_PE_sdata4;
- } else {
- cie_offset = GetCieOffsetFromFde32(value32);
- }
- }
-
- if (entry_is_cie) {
- auto entry = cie_entries_.find(start_offset);
- if (entry == cie_entries_.end()) {
- DwarfCie* cie = &cie_entries_[start_offset];
- cie->lsda_encoding = DW_EH_PE_omit;
- cie->cfa_instructions_end = next_entries_offset_;
- cie->fde_address_encoding = cie_fde_encoding;
-
- if (!FillInCie(cie)) {
- cie_entries_.erase(start_offset);
- return false;
- }
- }
- *fde_entry = nullptr;
- } else {
- auto entry = fde_entries_.find(start_offset);
- if (entry != fde_entries_.end()) {
- *fde_entry = &entry->second;
- } else {
- DwarfFde* fde = &fde_entries_[start_offset];
- fde->cfa_instructions_end = next_entries_offset_;
- fde->cie_offset = cie_offset;
-
- if (!FillInFde(fde)) {
- fde_entries_.erase(start_offset);
- return false;
- }
- *fde_entry = fde;
- }
- }
- return true;
-}
-
-template <typename AddressType>
-void DwarfSectionImpl<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
- // Loop through the already cached entries.
- uint64_t entry_offset = entries_offset_;
- while (entry_offset < next_entries_offset_) {
- auto cie_it = cie_entries_.find(entry_offset);
- if (cie_it != cie_entries_.end()) {
- entry_offset = cie_it->second.cfa_instructions_end;
- } else {
- auto fde_it = fde_entries_.find(entry_offset);
- if (fde_it == fde_entries_.end()) {
- // No fde or cie at this entry, should not be possible.
- return;
- }
- entry_offset = fde_it->second.cfa_instructions_end;
- fdes->push_back(&fde_it->second);
- }
- }
-
- while (next_entries_offset_ < entries_end_) {
- const DwarfFde* fde;
- if (!GetNextCieOrFde(&fde)) {
- break;
- }
- if (fde != nullptr) {
- InsertFde(fde);
- fdes->push_back(fde);
- }
-
- if (next_entries_offset_ < memory_.cur_offset()) {
- // Simply consider the processing done in this case.
- break;
- }
- }
-}
-
-template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromPc(uint64_t pc) {
- // Search in the list of fdes we already have.
- auto it = fdes_.upper_bound(pc);
- if (it != fdes_.end()) {
- if (pc >= it->second.first) {
- return it->second.second;
- }
- }
-
- // The section might have overlapping pcs in fdes, so it is necessary
- // to do a linear search of the fdes by pc. As fdes are read, a cached
- // search map is created.
- while (next_entries_offset_ < entries_end_) {
- const DwarfFde* fde;
- if (!GetNextCieOrFde(&fde)) {
- return nullptr;
- }
- if (fde != nullptr) {
- InsertFde(fde);
- if (pc >= fde->pc_start && pc < fde->pc_end) {
- return fde;
- }
- }
-
- if (next_entries_offset_ < memory_.cur_offset()) {
- // Simply consider the processing done in this case.
- break;
- }
- }
- return nullptr;
-}
-
-// Explicitly instantiate DwarfSectionImpl
-template class DwarfSectionImpl<uint32_t>;
-template class DwarfSectionImpl<uint64_t>;
-
-// Explicitly instantiate DwarfDebugFrame
-template class DwarfDebugFrame<uint32_t>;
-template class DwarfDebugFrame<uint64_t>;
-
-// Explicitly instantiate DwarfEhFrame
-template class DwarfEhFrame<uint32_t>;
-template class DwarfEhFrame<uint64_t>;
-
-} // namespace unwindstack
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
deleted file mode 100644
index 286febc..0000000
--- a/libunwindstack/Elf.cpp
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <string.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-#include <utility>
-
-#define LOG_TAG "unwind"
-#include <log/log.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-#include "ElfInterfaceArm.h"
-#include "Symbols.h"
-
-namespace unwindstack {
-
-bool Elf::cache_enabled_;
-std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* Elf::cache_;
-std::mutex* Elf::cache_lock_;
-
-bool Elf::Init() {
- load_bias_ = 0;
- if (!memory_) {
- return false;
- }
-
- interface_.reset(CreateInterfaceFromMemory(memory_.get()));
- if (!interface_) {
- return false;
- }
-
- valid_ = interface_->Init(&load_bias_);
- if (valid_) {
- interface_->InitHeaders();
- InitGnuDebugdata();
- } else {
- interface_.reset(nullptr);
- }
- return valid_;
-}
-
-// It is expensive to initialize the .gnu_debugdata section. Provide a method
-// to initialize this data separately.
-void Elf::InitGnuDebugdata() {
- if (!valid_ || interface_->gnu_debugdata_offset() == 0) {
- return;
- }
-
- gnu_debugdata_memory_.reset(interface_->CreateGnuDebugdataMemory());
- gnu_debugdata_interface_.reset(CreateInterfaceFromMemory(gnu_debugdata_memory_.get()));
- ElfInterface* gnu = gnu_debugdata_interface_.get();
- if (gnu == nullptr) {
- return;
- }
-
- // Ignore the load_bias from the compressed section, the correct load bias
- // is in the uncompressed data.
- int64_t load_bias;
- if (gnu->Init(&load_bias)) {
- gnu->InitHeaders();
- interface_->SetGnuDebugdataInterface(gnu);
- } else {
- // Free all of the memory associated with the gnu_debugdata section.
- gnu_debugdata_memory_.reset(nullptr);
- gnu_debugdata_interface_.reset(nullptr);
- }
-}
-
-void Elf::Invalidate() {
- interface_.reset(nullptr);
- valid_ = false;
-}
-
-std::string Elf::GetSoname() {
- std::lock_guard<std::mutex> guard(lock_);
- if (!valid_) {
- return "";
- }
- return interface_->GetSoname();
-}
-
-uint64_t Elf::GetRelPc(uint64_t pc, const MapInfo* map_info) {
- return pc - map_info->start + load_bias_ + map_info->elf_offset;
-}
-
-bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
- std::lock_guard<std::mutex> guard(lock_);
- return valid_ && (interface_->GetFunctionName(addr, name, func_offset) ||
- (gnu_debugdata_interface_ &&
- gnu_debugdata_interface_->GetFunctionName(addr, name, func_offset)));
-}
-
-bool Elf::GetGlobalVariableOffset(const std::string& name, uint64_t* memory_offset) {
- if (!valid_) {
- return false;
- }
-
- uint64_t vaddr;
- if (!interface_->GetGlobalVariable(name, &vaddr) &&
- (gnu_debugdata_interface_ == nullptr ||
- !gnu_debugdata_interface_->GetGlobalVariable(name, &vaddr))) {
- return false;
- }
-
- if (arch() == ARCH_ARM64) {
- // Tagged pointer after Android R would lead top byte to have random values
- // https://source.android.com/devices/tech/debug/tagged-pointers
- vaddr &= (1ULL << 56) - 1;
- }
-
- // Check the .data section.
- uint64_t vaddr_start = interface_->data_vaddr_start();
- if (vaddr >= vaddr_start && vaddr < interface_->data_vaddr_end()) {
- *memory_offset = vaddr - vaddr_start + interface_->data_offset();
- return true;
- }
-
- // Check the .dynamic section.
- vaddr_start = interface_->dynamic_vaddr_start();
- if (vaddr >= vaddr_start && vaddr < interface_->dynamic_vaddr_end()) {
- *memory_offset = vaddr - vaddr_start + interface_->dynamic_offset();
- return true;
- }
-
- return false;
-}
-
-std::string Elf::GetBuildID() {
- if (!valid_) {
- return "";
- }
- return interface_->GetBuildID();
-}
-
-void Elf::GetLastError(ErrorData* data) {
- if (valid_) {
- *data = interface_->last_error();
- }
-}
-
-ErrorCode Elf::GetLastErrorCode() {
- if (valid_) {
- return interface_->LastErrorCode();
- }
- return ERROR_INVALID_ELF;
-}
-
-uint64_t Elf::GetLastErrorAddress() {
- if (valid_) {
- return interface_->LastErrorAddress();
- }
- return 0;
-}
-
-// The relative pc expectd by this function is relative to the start of the elf.
-bool Elf::StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory) {
- if (!valid_) {
- return false;
- }
-
- // Convert the rel_pc to an elf_offset.
- if (rel_pc < static_cast<uint64_t>(load_bias_)) {
- return false;
- }
- return regs->StepIfSignalHandler(rel_pc - load_bias_, this, process_memory);
-}
-
-// The relative pc is always relative to the start of the map from which it comes.
-bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) {
- if (!valid_) {
- return false;
- }
-
- // Lock during the step which can update information in the object.
- std::lock_guard<std::mutex> guard(lock_);
- return interface_->Step(rel_pc, regs, process_memory, finished);
-}
-
-bool Elf::IsValidElf(Memory* memory) {
- if (memory == nullptr) {
- return false;
- }
-
- // Verify that this is a valid elf file.
- uint8_t e_ident[SELFMAG + 1];
- if (!memory->ReadFully(0, e_ident, SELFMAG)) {
- return false;
- }
-
- if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
- return false;
- }
- return true;
-}
-
-bool Elf::GetInfo(Memory* memory, uint64_t* size) {
- if (!IsValidElf(memory)) {
- return false;
- }
- *size = 0;
-
- uint8_t class_type;
- if (!memory->ReadFully(EI_CLASS, &class_type, 1)) {
- return false;
- }
-
- // Get the maximum size of the elf data from the header.
- if (class_type == ELFCLASS32) {
- ElfInterface32::GetMaxSize(memory, size);
- } else if (class_type == ELFCLASS64) {
- ElfInterface64::GetMaxSize(memory, size);
- } else {
- return false;
- }
- return true;
-}
-
-bool Elf::IsValidPc(uint64_t pc) {
- if (!valid_ || (load_bias_ > 0 && pc < static_cast<uint64_t>(load_bias_))) {
- return false;
- }
-
- if (interface_->IsValidPc(pc)) {
- return true;
- }
-
- if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->IsValidPc(pc)) {
- return true;
- }
-
- return false;
-}
-
-ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
- if (!IsValidElf(memory)) {
- return nullptr;
- }
-
- std::unique_ptr<ElfInterface> interface;
- if (!memory->ReadFully(EI_CLASS, &class_type_, 1)) {
- return nullptr;
- }
- if (class_type_ == ELFCLASS32) {
- Elf32_Half e_machine;
- if (!memory->ReadFully(EI_NIDENT + sizeof(Elf32_Half), &e_machine, sizeof(e_machine))) {
- return nullptr;
- }
-
- machine_type_ = e_machine;
- if (e_machine == EM_ARM) {
- arch_ = ARCH_ARM;
- interface.reset(new ElfInterfaceArm(memory));
- } else if (e_machine == EM_386) {
- arch_ = ARCH_X86;
- interface.reset(new ElfInterface32(memory));
- } else if (e_machine == EM_MIPS) {
- arch_ = ARCH_MIPS;
- interface.reset(new ElfInterface32(memory));
- } else {
- // Unsupported.
- ALOGI("32 bit elf that is neither arm nor x86 nor mips: e_machine = %d\n", e_machine);
- return nullptr;
- }
- } else if (class_type_ == ELFCLASS64) {
- Elf64_Half e_machine;
- if (!memory->ReadFully(EI_NIDENT + sizeof(Elf64_Half), &e_machine, sizeof(e_machine))) {
- return nullptr;
- }
-
- machine_type_ = e_machine;
- if (e_machine == EM_AARCH64) {
- arch_ = ARCH_ARM64;
- } else if (e_machine == EM_X86_64) {
- arch_ = ARCH_X86_64;
- } else if (e_machine == EM_MIPS) {
- arch_ = ARCH_MIPS64;
- } else {
- // Unsupported.
- ALOGI("64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = %d\n",
- e_machine);
- return nullptr;
- }
- interface.reset(new ElfInterface64(memory));
- }
-
- return interface.release();
-}
-
-int64_t Elf::GetLoadBias(Memory* memory) {
- if (!IsValidElf(memory)) {
- return 0;
- }
-
- uint8_t class_type;
- if (!memory->Read(EI_CLASS, &class_type, 1)) {
- return 0;
- }
-
- if (class_type == ELFCLASS32) {
- return ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(memory);
- } else if (class_type == ELFCLASS64) {
- return ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(memory);
- }
- return 0;
-}
-
-void Elf::SetCachingEnabled(bool enable) {
- if (!cache_enabled_ && enable) {
- cache_enabled_ = true;
- cache_ = new std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>;
- cache_lock_ = new std::mutex;
- } else if (cache_enabled_ && !enable) {
- cache_enabled_ = false;
- delete cache_;
- delete cache_lock_;
- }
-}
-
-void Elf::CacheLock() {
- cache_lock_->lock();
-}
-
-void Elf::CacheUnlock() {
- cache_lock_->unlock();
-}
-
-void Elf::CacheAdd(MapInfo* info) {
- // If elf_offset != 0, then cache both name:offset and name.
- // The cached name is used to do lookups if multiple maps for the same
- // named elf file exist.
- // For example, if there are two maps boot.odex:1000 and boot.odex:2000
- // where each reference the entire boot.odex, the cache will properly
- // use the same cached elf object.
-
- if (info->offset == 0 || info->elf_offset != 0) {
- (*cache_)[info->name] = std::make_pair(info->elf, true);
- }
-
- if (info->offset != 0) {
- // The second element in the pair indicates whether elf_offset should
- // be set to offset when getting out of the cache.
- (*cache_)[info->name + ':' + std::to_string(info->offset)] =
- std::make_pair(info->elf, info->elf_offset != 0);
- }
-}
-
-bool Elf::CacheAfterCreateMemory(MapInfo* info) {
- if (info->name.empty() || info->offset == 0 || info->elf_offset == 0) {
- return false;
- }
-
- auto entry = cache_->find(info->name);
- if (entry == cache_->end()) {
- return false;
- }
-
- // In this case, the whole file is the elf, and the name has already
- // been cached. Add an entry at name:offset to get this directly out
- // of the cache next time.
- info->elf = entry->second.first;
- (*cache_)[info->name + ':' + std::to_string(info->offset)] = std::make_pair(info->elf, true);
- return true;
-}
-
-bool Elf::CacheGet(MapInfo* info) {
- std::string name(info->name);
- if (info->offset != 0) {
- name += ':' + std::to_string(info->offset);
- }
- auto entry = cache_->find(name);
- if (entry != cache_->end()) {
- info->elf = entry->second.first;
- if (entry->second.second) {
- info->elf_offset = info->offset;
- }
- return true;
- }
- return false;
-}
-
-std::string Elf::GetBuildID(Memory* memory) {
- if (!IsValidElf(memory)) {
- return "";
- }
-
- uint8_t class_type;
- if (!memory->Read(EI_CLASS, &class_type, 1)) {
- return "";
- }
-
- if (class_type == ELFCLASS32) {
- return ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(memory);
- } else if (class_type == ELFCLASS64) {
- return ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>(memory);
- }
- return "";
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
deleted file mode 100644
index 17470fd..0000000
--- a/libunwindstack/ElfInterface.cpp
+++ /dev/null
@@ -1,718 +0,0 @@
-/*
- * Copyright (C) 2017 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 <elf.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <7zCrc.h>
-#include <Xz.h>
-#include <XzCrc64.h>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/Regs.h>
-
-#include "DwarfDebugFrame.h"
-#include "DwarfEhFrame.h"
-#include "DwarfEhFrameWithHdr.h"
-#include "MemoryBuffer.h"
-#include "Symbols.h"
-
-namespace unwindstack {
-
-ElfInterface::~ElfInterface() {
- for (auto symbol : symbols_) {
- delete symbol;
- }
-}
-
-bool ElfInterface::IsValidPc(uint64_t pc) {
- if (!pt_loads_.empty()) {
- for (auto& entry : pt_loads_) {
- uint64_t start = entry.second.table_offset;
- uint64_t end = start + entry.second.table_size;
- if (pc >= start && pc < end) {
- return true;
- }
- }
- return false;
- }
-
- // No PT_LOAD data, look for a fde for this pc in the section data.
- if (debug_frame_ != nullptr && debug_frame_->GetFdeFromPc(pc) != nullptr) {
- return true;
- }
-
- if (eh_frame_ != nullptr && eh_frame_->GetFdeFromPc(pc) != nullptr) {
- return true;
- }
-
- return false;
-}
-
-Memory* ElfInterface::CreateGnuDebugdataMemory() {
- if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
- return nullptr;
- }
-
- // TODO: Only call these initialization functions once.
- CrcGenerateTable();
- Crc64GenerateTable();
-
- // Verify the request is not larger than the max size_t value.
- if (gnu_debugdata_size_ > SIZE_MAX) {
- return nullptr;
- }
- size_t initial_buffer_size;
- if (__builtin_mul_overflow(5, gnu_debugdata_size_, &initial_buffer_size)) {
- return nullptr;
- }
-
- size_t buffer_increment;
- if (__builtin_mul_overflow(2, gnu_debugdata_size_, &buffer_increment)) {
- return nullptr;
- }
-
- std::unique_ptr<uint8_t[]> src(new (std::nothrow) uint8_t[gnu_debugdata_size_]);
- if (src.get() == nullptr) {
- return nullptr;
- }
-
- std::unique_ptr<MemoryBuffer> dst(new MemoryBuffer);
- if (!dst->Resize(initial_buffer_size)) {
- return nullptr;
- }
-
- if (!memory_->ReadFully(gnu_debugdata_offset_, src.get(), gnu_debugdata_size_)) {
- return nullptr;
- }
-
- ISzAlloc alloc;
- CXzUnpacker state;
- alloc.Alloc = [](ISzAllocPtr, size_t size) { return malloc(size); };
- alloc.Free = [](ISzAllocPtr, void* ptr) { return free(ptr); };
- XzUnpacker_Construct(&state, &alloc);
-
- int return_val;
- size_t src_offset = 0;
- size_t dst_offset = 0;
- ECoderStatus status;
- do {
- size_t src_remaining = gnu_debugdata_size_ - src_offset;
- size_t dst_remaining = dst->Size() - dst_offset;
- if (dst_remaining < buffer_increment) {
- size_t new_size;
- if (__builtin_add_overflow(dst->Size(), buffer_increment, &new_size) ||
- !dst->Resize(new_size)) {
- XzUnpacker_Free(&state);
- return nullptr;
- }
- dst_remaining += buffer_increment;
- }
- return_val = XzUnpacker_Code(&state, dst->GetPtr(dst_offset), &dst_remaining, &src[src_offset],
- &src_remaining, true, CODER_FINISH_ANY, &status);
- src_offset += src_remaining;
- dst_offset += dst_remaining;
- } while (return_val == SZ_OK && status == CODER_STATUS_NOT_FINISHED);
- XzUnpacker_Free(&state);
- if (return_val != SZ_OK || !XzUnpacker_IsStreamWasFinished(&state)) {
- return nullptr;
- }
-
- // Shrink back down to the exact size.
- if (!dst->Resize(dst_offset)) {
- return nullptr;
- }
-
- return dst.release();
-}
-
-template <typename AddressType>
-void ElfInterface::InitHeadersWithTemplate() {
- if (eh_frame_hdr_offset_ != 0) {
- DwarfEhFrameWithHdr<AddressType>* eh_frame_hdr = new DwarfEhFrameWithHdr<AddressType>(memory_);
- eh_frame_.reset(eh_frame_hdr);
- if (!eh_frame_hdr->EhFrameInit(eh_frame_offset_, eh_frame_size_, eh_frame_section_bias_) ||
- !eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, eh_frame_hdr_section_bias_)) {
- eh_frame_.reset(nullptr);
- }
- }
-
- if (eh_frame_.get() == nullptr && eh_frame_offset_ != 0) {
- // If there is an eh_frame section without an eh_frame_hdr section,
- // or using the frame hdr object failed to init.
- eh_frame_.reset(new DwarfEhFrame<AddressType>(memory_));
- if (!eh_frame_->Init(eh_frame_offset_, eh_frame_size_, eh_frame_section_bias_)) {
- eh_frame_.reset(nullptr);
- }
- }
-
- if (eh_frame_.get() == nullptr) {
- eh_frame_hdr_offset_ = 0;
- eh_frame_hdr_section_bias_ = 0;
- eh_frame_hdr_size_ = static_cast<uint64_t>(-1);
- eh_frame_offset_ = 0;
- eh_frame_section_bias_ = 0;
- eh_frame_size_ = static_cast<uint64_t>(-1);
- }
-
- if (debug_frame_offset_ != 0) {
- debug_frame_.reset(new DwarfDebugFrame<AddressType>(memory_));
- if (!debug_frame_->Init(debug_frame_offset_, debug_frame_size_, debug_frame_section_bias_)) {
- debug_frame_.reset(nullptr);
- debug_frame_offset_ = 0;
- debug_frame_size_ = static_cast<uint64_t>(-1);
- }
- }
-}
-
-template <typename EhdrType, typename PhdrType, typename ShdrType>
-bool ElfInterface::ReadAllHeaders(int64_t* load_bias) {
- EhdrType ehdr;
- if (!memory_->ReadFully(0, &ehdr, sizeof(ehdr))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = 0;
- return false;
- }
-
- // If we have enough information that this is an elf file, then allow
- // malformed program and section headers.
- ReadProgramHeaders<EhdrType, PhdrType>(ehdr, load_bias);
- ReadSectionHeaders<EhdrType, ShdrType>(ehdr);
- return true;
-}
-
-template <typename EhdrType, typename PhdrType>
-int64_t ElfInterface::GetLoadBias(Memory* memory) {
- EhdrType ehdr;
- if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
- return false;
- }
-
- uint64_t offset = ehdr.e_phoff;
- for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
- PhdrType phdr;
- if (!memory->ReadFully(offset, &phdr, sizeof(phdr))) {
- return 0;
- }
-
- // Find the first executable load when looking for the load bias.
- if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X)) {
- return static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
- }
- }
- return 0;
-}
-
-template <typename EhdrType, typename PhdrType>
-void ElfInterface::ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias) {
- uint64_t offset = ehdr.e_phoff;
- bool first_exec_load_header = true;
- for (size_t i = 0; i < ehdr.e_phnum; i++, offset += ehdr.e_phentsize) {
- PhdrType phdr;
- if (!memory_->ReadFully(offset, &phdr, sizeof(phdr))) {
- return;
- }
-
- switch (phdr.p_type) {
- case PT_LOAD:
- {
- if ((phdr.p_flags & PF_X) == 0) {
- continue;
- }
-
- pt_loads_[phdr.p_offset] = LoadInfo{phdr.p_offset, phdr.p_vaddr,
- static_cast<size_t>(phdr.p_memsz)};
- // Only set the load bias from the first executable load header.
- if (first_exec_load_header) {
- *load_bias = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
- }
- first_exec_load_header = false;
- break;
- }
-
- case PT_GNU_EH_FRAME:
- // This is really the pointer to the .eh_frame_hdr section.
- eh_frame_hdr_offset_ = phdr.p_offset;
- eh_frame_hdr_section_bias_ = static_cast<uint64_t>(phdr.p_vaddr) - phdr.p_offset;
- eh_frame_hdr_size_ = phdr.p_memsz;
- break;
-
- case PT_DYNAMIC:
- dynamic_offset_ = phdr.p_offset;
- dynamic_vaddr_start_ = phdr.p_vaddr;
- if (__builtin_add_overflow(dynamic_vaddr_start_, phdr.p_memsz, &dynamic_vaddr_end_)) {
- dynamic_offset_ = 0;
- dynamic_vaddr_start_ = 0;
- dynamic_vaddr_end_ = 0;
- }
- break;
-
- default:
- HandleUnknownType(phdr.p_type, phdr.p_offset, phdr.p_filesz);
- break;
- }
- }
-}
-
-template <typename NhdrType>
-std::string ElfInterface::ReadBuildID() {
- // Ensure there is no overflow in any of the calulations below.
- uint64_t tmp;
- if (__builtin_add_overflow(gnu_build_id_offset_, gnu_build_id_size_, &tmp)) {
- return "";
- }
-
- uint64_t offset = 0;
- while (offset < gnu_build_id_size_) {
- if (gnu_build_id_size_ - offset < sizeof(NhdrType)) {
- return "";
- }
- NhdrType hdr;
- if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &hdr, sizeof(hdr))) {
- return "";
- }
- offset += sizeof(hdr);
-
- if (gnu_build_id_size_ - offset < hdr.n_namesz) {
- return "";
- }
- if (hdr.n_namesz > 0) {
- std::string name(hdr.n_namesz, '\0');
- if (!memory_->ReadFully(gnu_build_id_offset_ + offset, &(name[0]), hdr.n_namesz)) {
- return "";
- }
-
- // Trim trailing \0 as GNU is stored as a C string in the ELF file.
- if (name.back() == '\0')
- name.resize(name.size() - 1);
-
- // Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
- offset += (hdr.n_namesz + 3) & ~3;
-
- if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
- if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) {
- return "";
- }
- 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;
- }
- return "";
- }
- }
- // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
- offset += (hdr.n_descsz + 3) & ~3;
- }
- return "";
-}
-
-template <typename EhdrType, typename ShdrType>
-void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) {
- uint64_t offset = ehdr.e_shoff;
- uint64_t sec_offset = 0;
- uint64_t sec_size = 0;
-
- // Get the location of the section header names.
- // If something is malformed in the header table data, we aren't going
- // to terminate, we'll simply ignore this part.
- ShdrType shdr;
- if (ehdr.e_shstrndx < ehdr.e_shnum) {
- uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
- if (memory_->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
- sec_offset = shdr.sh_offset;
- sec_size = shdr.sh_size;
- }
- }
-
- // Skip the first header, it's always going to be NULL.
- offset += ehdr.e_shentsize;
- for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
- if (!memory_->ReadFully(offset, &shdr, sizeof(shdr))) {
- return;
- }
-
- if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
- // Need to go get the information about the section that contains
- // the string terminated names.
- ShdrType str_shdr;
- if (shdr.sh_link >= ehdr.e_shnum) {
- continue;
- }
- uint64_t str_offset = ehdr.e_shoff + shdr.sh_link * ehdr.e_shentsize;
- if (!memory_->ReadFully(str_offset, &str_shdr, sizeof(str_shdr))) {
- continue;
- }
- if (str_shdr.sh_type != SHT_STRTAB) {
- continue;
- }
- 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 && 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, sec_size - shdr.sh_name)) {
- if (name == ".debug_frame") {
- debug_frame_offset_ = shdr.sh_offset;
- debug_frame_size_ = shdr.sh_size;
- debug_frame_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
- } else if (name == ".gnu_debugdata") {
- gnu_debugdata_offset_ = shdr.sh_offset;
- gnu_debugdata_size_ = shdr.sh_size;
- } else if (name == ".eh_frame") {
- eh_frame_offset_ = shdr.sh_offset;
- eh_frame_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
- eh_frame_size_ = shdr.sh_size;
- } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
- eh_frame_hdr_offset_ = shdr.sh_offset;
- eh_frame_hdr_section_bias_ = static_cast<uint64_t>(shdr.sh_addr) - shdr.sh_offset;
- eh_frame_hdr_size_ = shdr.sh_size;
- } else if (name == ".data") {
- data_offset_ = shdr.sh_offset;
- data_vaddr_start_ = shdr.sh_addr;
- if (__builtin_add_overflow(data_vaddr_start_, shdr.sh_size, &data_vaddr_end_)) {
- data_offset_ = 0;
- data_vaddr_start_ = 0;
- data_vaddr_end_ = 0;
- }
- }
- }
- }
- } else if (shdr.sh_type == SHT_STRTAB) {
- // In order to read soname, keep track of address to offset mapping.
- strtabs_.push_back(std::make_pair<uint64_t, uint64_t>(static_cast<uint64_t>(shdr.sh_addr),
- static_cast<uint64_t>(shdr.sh_offset)));
- } else if (shdr.sh_type == SHT_NOTE) {
- if (shdr.sh_name < sec_size) {
- std::string name;
- if (memory_->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
- name == ".note.gnu.build-id") {
- gnu_build_id_offset_ = shdr.sh_offset;
- gnu_build_id_size_ = shdr.sh_size;
- }
- }
- }
- }
-}
-
-template <typename DynType>
-std::string ElfInterface::GetSonameWithTemplate() {
- if (soname_type_ == SONAME_INVALID) {
- return "";
- }
- if (soname_type_ == SONAME_VALID) {
- return soname_;
- }
-
- soname_type_ = SONAME_INVALID;
-
- uint64_t soname_offset = 0;
- uint64_t strtab_addr = 0;
- uint64_t strtab_size = 0;
-
- // Find the soname location from the dynamic headers section.
- DynType dyn;
- uint64_t offset = dynamic_offset_;
- uint64_t max_offset = offset + dynamic_vaddr_end_ - dynamic_vaddr_start_;
- for (uint64_t offset = dynamic_offset_; offset < max_offset; offset += sizeof(DynType)) {
- if (!memory_->ReadFully(offset, &dyn, sizeof(dyn))) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset;
- return "";
- }
-
- if (dyn.d_tag == DT_STRTAB) {
- strtab_addr = dyn.d_un.d_ptr;
- } else if (dyn.d_tag == DT_STRSZ) {
- strtab_size = dyn.d_un.d_val;
- } else if (dyn.d_tag == DT_SONAME) {
- soname_offset = dyn.d_un.d_val;
- } else if (dyn.d_tag == DT_NULL) {
- break;
- }
- }
-
- // Need to map the strtab address to the real offset.
- for (const auto& entry : strtabs_) {
- if (entry.first == strtab_addr) {
- soname_offset = entry.second + soname_offset;
- uint64_t soname_max = entry.second + strtab_size;
- if (soname_offset >= soname_max) {
- return "";
- }
- if (!memory_->ReadString(soname_offset, &soname_, soname_max - soname_offset)) {
- return "";
- }
- soname_type_ = SONAME_VALID;
- return soname_;
- }
- }
- return "";
-}
-
-template <typename SymType>
-bool ElfInterface::GetFunctionNameWithTemplate(uint64_t addr, std::string* name,
- uint64_t* func_offset) {
- if (symbols_.empty()) {
- return false;
- }
-
- for (const auto symbol : symbols_) {
- if (symbol->GetName<SymType>(addr, memory_, name, func_offset)) {
- return true;
- }
- }
- return false;
-}
-
-template <typename SymType>
-bool ElfInterface::GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address) {
- if (symbols_.empty()) {
- return false;
- }
-
- for (const auto symbol : symbols_) {
- if (symbol->GetGlobal<SymType>(memory_, name, memory_address)) {
- return true;
- }
- }
- return false;
-}
-
-bool ElfInterface::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- last_error_.code = ERROR_NONE;
- last_error_.address = 0;
-
- // Try the debug_frame first since it contains the most specific unwind
- // information.
- DwarfSection* debug_frame = debug_frame_.get();
- if (debug_frame != nullptr && debug_frame->Step(pc, regs, process_memory, finished)) {
- return true;
- }
-
- // Try the eh_frame next.
- DwarfSection* eh_frame = eh_frame_.get();
- if (eh_frame != nullptr && eh_frame->Step(pc, regs, process_memory, finished)) {
- return true;
- }
-
- if (gnu_debugdata_interface_ != nullptr &&
- gnu_debugdata_interface_->Step(pc, regs, process_memory, finished)) {
- return true;
- }
-
- // Set the error code based on the first error encountered.
- DwarfSection* section = nullptr;
- if (debug_frame_ != nullptr) {
- section = debug_frame_.get();
- } else if (eh_frame_ != nullptr) {
- section = eh_frame_.get();
- } else if (gnu_debugdata_interface_ != nullptr) {
- last_error_ = gnu_debugdata_interface_->last_error();
- return false;
- } else {
- return false;
- }
-
- // Convert the DWARF ERROR to an external error.
- DwarfErrorCode code = section->LastErrorCode();
- switch (code) {
- case DWARF_ERROR_NONE:
- last_error_.code = ERROR_NONE;
- break;
-
- case DWARF_ERROR_MEMORY_INVALID:
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = section->LastErrorAddress();
- break;
-
- case DWARF_ERROR_ILLEGAL_VALUE:
- case DWARF_ERROR_ILLEGAL_STATE:
- case DWARF_ERROR_STACK_INDEX_NOT_VALID:
- case DWARF_ERROR_TOO_MANY_ITERATIONS:
- case DWARF_ERROR_CFA_NOT_DEFINED:
- case DWARF_ERROR_NO_FDES:
- last_error_.code = ERROR_UNWIND_INFO;
- break;
-
- case DWARF_ERROR_NOT_IMPLEMENTED:
- case DWARF_ERROR_UNSUPPORTED_VERSION:
- last_error_.code = ERROR_UNSUPPORTED;
- break;
- }
- return false;
-}
-
-// This is an estimation of the size of the elf file using the location
-// of the section headers and size. This assumes that the section headers
-// are at the end of the elf file. If the elf has a load bias, the size
-// will be too large, but this is acceptable.
-template <typename EhdrType>
-void ElfInterface::GetMaxSizeWithTemplate(Memory* memory, uint64_t* size) {
- EhdrType ehdr;
- if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
- return;
- }
- if (ehdr.e_shnum == 0) {
- return;
- }
- *size = ehdr.e_shoff + ehdr.e_shentsize * ehdr.e_shnum;
-}
-
-template <typename EhdrType, typename ShdrType>
-bool GetBuildIDInfo(Memory* memory, uint64_t* build_id_offset, uint64_t* build_id_size) {
- EhdrType ehdr;
- if (!memory->ReadFully(0, &ehdr, sizeof(ehdr))) {
- return false;
- }
-
- uint64_t offset = ehdr.e_shoff;
- uint64_t sec_offset;
- uint64_t sec_size;
- ShdrType shdr;
- if (ehdr.e_shstrndx >= ehdr.e_shnum) {
- return false;
- }
-
- uint64_t sh_offset = offset + ehdr.e_shstrndx * ehdr.e_shentsize;
- if (!memory->ReadFully(sh_offset, &shdr, sizeof(shdr))) {
- return false;
- }
- sec_offset = shdr.sh_offset;
- sec_size = shdr.sh_size;
-
- // Skip the first header, it's always going to be NULL.
- offset += ehdr.e_shentsize;
- for (size_t i = 1; i < ehdr.e_shnum; i++, offset += ehdr.e_shentsize) {
- if (!memory->ReadFully(offset, &shdr, sizeof(shdr))) {
- return false;
- }
- std::string name;
- if (shdr.sh_type == SHT_NOTE && shdr.sh_name < sec_size &&
- memory->ReadString(sec_offset + shdr.sh_name, &name, sec_size - shdr.sh_name) &&
- name == ".note.gnu.build-id") {
- *build_id_offset = shdr.sh_offset;
- *build_id_size = shdr.sh_size;
- return true;
- }
- }
-
- return false;
-}
-
-template <typename EhdrType, typename ShdrType, typename NhdrType>
-std::string ElfInterface::ReadBuildIDFromMemory(Memory* memory) {
- uint64_t note_offset;
- uint64_t note_size;
- if (!GetBuildIDInfo<EhdrType, ShdrType>(memory, ¬e_offset, ¬e_size)) {
- return "";
- }
-
- // Ensure there is no overflow in any of the calculations below.
- uint64_t tmp;
- if (__builtin_add_overflow(note_offset, note_size, &tmp)) {
- return "";
- }
-
- uint64_t offset = 0;
- while (offset < note_size) {
- if (note_size - offset < sizeof(NhdrType)) {
- return "";
- }
- NhdrType hdr;
- if (!memory->ReadFully(note_offset + offset, &hdr, sizeof(hdr))) {
- return "";
- }
- offset += sizeof(hdr);
-
- if (note_size - offset < hdr.n_namesz) {
- return "";
- }
- if (hdr.n_namesz > 0) {
- std::string name(hdr.n_namesz, '\0');
- if (!memory->ReadFully(note_offset + offset, &(name[0]), hdr.n_namesz)) {
- return "";
- }
-
- // Trim trailing \0 as GNU is stored as a C string in the ELF file.
- if (name.back() == '\0') name.resize(name.size() - 1);
-
- // Align hdr.n_namesz to next power multiple of 4. See man 5 elf.
- offset += (hdr.n_namesz + 3) & ~3;
-
- if (name == "GNU" && hdr.n_type == NT_GNU_BUILD_ID) {
- if (note_size - offset < hdr.n_descsz || hdr.n_descsz == 0) {
- return "";
- }
- std::string build_id(hdr.n_descsz, '\0');
- if (memory->ReadFully(note_offset + offset, &build_id[0], hdr.n_descsz)) {
- return build_id;
- }
- return "";
- }
- }
- // Align hdr.n_descsz to next power multiple of 4. See man 5 elf.
- offset += (hdr.n_descsz + 3) & ~3;
- }
- return "";
-}
-
-// Instantiate all of the needed template functions.
-template void ElfInterface::InitHeadersWithTemplate<uint32_t>();
-template void ElfInterface::InitHeadersWithTemplate<uint64_t>();
-
-template bool ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(int64_t*);
-template bool ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(int64_t*);
-
-template void ElfInterface::ReadProgramHeaders<Elf32_Ehdr, Elf32_Phdr>(const Elf32_Ehdr&, int64_t*);
-template void ElfInterface::ReadProgramHeaders<Elf64_Ehdr, Elf64_Phdr>(const Elf64_Ehdr&, int64_t*);
-
-template void ElfInterface::ReadSectionHeaders<Elf32_Ehdr, Elf32_Shdr>(const Elf32_Ehdr&);
-template void ElfInterface::ReadSectionHeaders<Elf64_Ehdr, Elf64_Shdr>(const Elf64_Ehdr&);
-
-template std::string ElfInterface::ReadBuildID<Elf32_Nhdr>();
-template std::string ElfInterface::ReadBuildID<Elf64_Nhdr>();
-
-template std::string ElfInterface::GetSonameWithTemplate<Elf32_Dyn>();
-template std::string ElfInterface::GetSonameWithTemplate<Elf64_Dyn>();
-
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(uint64_t, std::string*,
- uint64_t*);
-template bool ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(uint64_t, std::string*,
- uint64_t*);
-
-template bool ElfInterface::GetGlobalVariableWithTemplate<Elf32_Sym>(const std::string&, uint64_t*);
-template bool ElfInterface::GetGlobalVariableWithTemplate<Elf64_Sym>(const std::string&, uint64_t*);
-
-template void ElfInterface::GetMaxSizeWithTemplate<Elf32_Ehdr>(Memory*, uint64_t*);
-template void ElfInterface::GetMaxSizeWithTemplate<Elf64_Ehdr>(Memory*, uint64_t*);
-
-template int64_t ElfInterface::GetLoadBias<Elf32_Ehdr, Elf32_Phdr>(Memory*);
-template int64_t ElfInterface::GetLoadBias<Elf64_Ehdr, Elf64_Phdr>(Memory*);
-
-template std::string ElfInterface::ReadBuildIDFromMemory<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr>(
- Memory*);
-template std::string ElfInterface::ReadBuildIDFromMemory<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr>(
- Memory*);
-
-} // namespace unwindstack
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
deleted file mode 100644
index 76f2dc8..0000000
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <stdint.h>
-
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsArm.h>
-
-#include "ArmExidx.h"
-#include "ElfInterfaceArm.h"
-
-namespace unwindstack {
-
-bool ElfInterfaceArm::Init(int64_t* load_bias) {
- if (!ElfInterface32::Init(load_bias)) {
- return false;
- }
- load_bias_ = *load_bias;
- return true;
-}
-
-bool ElfInterfaceArm::FindEntry(uint32_t pc, uint64_t* entry_offset) {
- if (start_offset_ == 0 || total_entries_ == 0) {
- last_error_.code = ERROR_UNWIND_INFO;
- return false;
- }
-
- size_t first = 0;
- size_t last = total_entries_;
- while (first < last) {
- size_t current = (first + last) / 2;
- uint32_t addr = addrs_[current];
- if (addr == 0) {
- if (!GetPrel31Addr(start_offset_ + current * 8, &addr)) {
- return false;
- }
- addrs_[current] = addr;
- }
- if (pc == addr) {
- *entry_offset = start_offset_ + current * 8;
- return true;
- }
- if (pc < addr) {
- last = current;
- } else {
- first = current + 1;
- }
- }
- if (last != 0) {
- *entry_offset = start_offset_ + (last - 1) * 8;
- return true;
- }
- last_error_.code = ERROR_UNWIND_INFO;
- return false;
-}
-
-bool ElfInterfaceArm::GetPrel31Addr(uint32_t offset, uint32_t* addr) {
- uint32_t data;
- if (!memory_->Read32(offset, &data)) {
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = offset;
- return false;
- }
-
- // Sign extend the value if necessary.
- int32_t value = (static_cast<int32_t>(data) << 1) >> 1;
- *addr = offset + value;
- return true;
-}
-
-#if !defined(PT_ARM_EXIDX)
-#define PT_ARM_EXIDX 0x70000001
-#endif
-
-void ElfInterfaceArm::HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) {
- if (type != PT_ARM_EXIDX) {
- return;
- }
-
- // The offset already takes into account the load bias.
- start_offset_ = ph_offset;
-
- // Always use filesz instead of memsz. In most cases they are the same,
- // but some shared libraries wind up setting one correctly and not the other.
- total_entries_ = ph_filesz / 8;
-}
-
-bool ElfInterfaceArm::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- // Dwarf unwind information is precise about whether a pc is covered or not,
- // but arm unwind information only has ranges of pc. In order to avoid
- // incorrectly doing a bad unwind using arm unwind information for a
- // different function, always try and unwind with the dwarf information first.
- return ElfInterface32::Step(pc, regs, process_memory, finished) ||
- StepExidx(pc, regs, process_memory, finished);
-}
-
-bool ElfInterfaceArm::StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
- // Adjust the load bias to get the real relative pc.
- if (pc < load_bias_) {
- last_error_.code = ERROR_UNWIND_INFO;
- return false;
- }
- pc -= load_bias_;
-
- RegsArm* regs_arm = reinterpret_cast<RegsArm*>(regs);
- uint64_t entry_offset;
- if (!FindEntry(pc, &entry_offset)) {
- return false;
- }
-
- ArmExidx arm(regs_arm, memory_, process_memory);
- arm.set_cfa(regs_arm->sp());
- bool return_value = false;
- if (arm.ExtractEntryData(entry_offset) && arm.Eval()) {
- // If the pc was not set, then use the LR registers for the PC.
- if (!arm.pc_set()) {
- (*regs_arm)[ARM_REG_PC] = (*regs_arm)[ARM_REG_LR];
- }
- (*regs_arm)[ARM_REG_SP] = arm.cfa();
- return_value = true;
-
- // If the pc was set to zero, consider this the final frame.
- *finished = (regs_arm->pc() == 0) ? true : false;
- }
-
- if (arm.status() == ARM_STATUS_NO_UNWIND) {
- *finished = true;
- return true;
- }
-
- if (!return_value) {
- switch (arm.status()) {
- case ARM_STATUS_NONE:
- case ARM_STATUS_NO_UNWIND:
- case ARM_STATUS_FINISH:
- last_error_.code = ERROR_NONE;
- break;
-
- case ARM_STATUS_RESERVED:
- case ARM_STATUS_SPARE:
- case ARM_STATUS_TRUNCATED:
- case ARM_STATUS_MALFORMED:
- case ARM_STATUS_INVALID_ALIGNMENT:
- case ARM_STATUS_INVALID_PERSONALITY:
- last_error_.code = ERROR_UNWIND_INFO;
- break;
-
- case ARM_STATUS_READ_FAILED:
- last_error_.code = ERROR_MEMORY_INVALID;
- last_error_.address = arm.status_address();
- break;
- }
- }
- return return_value;
-}
-
-bool ElfInterfaceArm::GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) {
- // For ARM, thumb function symbols have bit 0 set, but the address passed
- // in here might not have this bit set and result in a failure to find
- // the thumb function names. Adjust the address and offset to account
- // for this possible case.
- if (ElfInterface32::GetFunctionName(addr | 1, name, offset)) {
- *offset &= ~1;
- return true;
- }
- return false;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/ElfInterfaceArm.h b/libunwindstack/ElfInterfaceArm.h
deleted file mode 100644
index 1d71cac..0000000
--- a/libunwindstack/ElfInterfaceArm.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
-#define _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
-
-#include <elf.h>
-#include <stdint.h>
-
-#include <iterator>
-#include <unordered_map>
-
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class ElfInterfaceArm : public ElfInterface32 {
- public:
- ElfInterfaceArm(Memory* memory) : ElfInterface32(memory) {}
- virtual ~ElfInterfaceArm() = default;
-
- class iterator : public std::iterator<std::bidirectional_iterator_tag, uint32_t> {
- public:
- iterator(ElfInterfaceArm* interface, size_t index) : interface_(interface), index_(index) { }
-
- iterator& operator++() { index_++; return *this; }
- iterator& operator++(int increment) { index_ += increment; return *this; }
- iterator& operator--() { index_--; return *this; }
- iterator& operator--(int decrement) { index_ -= decrement; return *this; }
-
- bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
- bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
-
- uint32_t operator*() {
- uint32_t addr = interface_->addrs_[index_];
- if (addr == 0) {
- if (!interface_->GetPrel31Addr(interface_->start_offset_ + index_ * 8, &addr)) {
- return 0;
- }
- interface_->addrs_[index_] = addr;
- }
- return addr;
- }
-
- private:
- ElfInterfaceArm* interface_ = nullptr;
- size_t index_ = 0;
- };
-
- iterator begin() { return iterator(this, 0); }
- iterator end() { return iterator(this, total_entries_); }
-
- bool Init(int64_t* section_bias) override;
-
- bool GetPrel31Addr(uint32_t offset, uint32_t* addr);
-
- bool FindEntry(uint32_t pc, uint64_t* entry_offset);
-
- void HandleUnknownType(uint32_t type, uint64_t ph_offset, uint64_t ph_filesz) override;
-
- bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) override;
-
- bool StepExidx(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished);
-
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) override;
-
- uint64_t start_offset() { return start_offset_; }
-
- size_t total_entries() { return total_entries_; }
-
- void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; }
-
- protected:
- uint64_t start_offset_ = 0;
- size_t total_entries_ = 0;
- uint64_t load_bias_ = 0;
-
- std::unordered_map<size_t, uint32_t> addrs_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ELF_INTERFACE_ARM_H
diff --git a/libunwindstack/Global.cpp b/libunwindstack/Global.cpp
deleted file mode 100644
index ee6c8a5..0000000
--- a/libunwindstack/Global.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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 <string.h>
-#include <sys/mman.h>
-
-#include <string>
-#include <vector>
-
-#include <unwindstack/Global.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-Global::Global(std::shared_ptr<Memory>& memory) : memory_(memory) {}
-Global::Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
- : memory_(memory), search_libs_(search_libs) {}
-
-void Global::SetArch(ArchEnum arch) {
- if (arch_ == ARCH_UNKNOWN) {
- arch_ = arch;
- ProcessArch();
- }
-}
-
-bool Global::Searchable(const std::string& name) {
- if (search_libs_.empty()) {
- return true;
- }
-
- if (name.empty()) {
- return false;
- }
-
- const char* base_name = basename(name.c_str());
- for (const std::string& lib : search_libs_) {
- if (base_name == lib) {
- return true;
- }
- }
- return false;
-}
-
-void Global::FindAndReadVariable(Maps* maps, const char* var_str) {
- std::string variable(var_str);
- // When looking for global variables, do not arbitrarily search every
- // readable map. Instead look for a specific pattern that must exist.
- // The pattern should be a readable map, followed by a read-write
- // map with a non-zero offset.
- // For example:
- // f0000-f1000 0 r-- /system/lib/libc.so
- // f1000-f2000 1000 r-x /system/lib/libc.so
- // f2000-f3000 2000 rw- /system/lib/libc.so
- // This also works:
- // f0000-f2000 0 r-- /system/lib/libc.so
- // f2000-f3000 2000 rw- /system/lib/libc.so
- // It is also possible to see empty maps after the read-only like so:
- // f0000-f1000 0 r-- /system/lib/libc.so
- // f1000-f2000 0 ---
- // f2000-f3000 1000 r-x /system/lib/libc.so
- // f3000-f4000 2000 rw- /system/lib/libc.so
- MapInfo* map_zero = nullptr;
- for (const auto& info : *maps) {
- if (info->offset != 0 && (info->flags & (PROT_READ | PROT_WRITE)) == (PROT_READ | PROT_WRITE) &&
- map_zero != nullptr && Searchable(info->name) && info->name == map_zero->name) {
- Elf* elf = map_zero->GetElf(memory_, arch());
- uint64_t ptr;
- if (elf->GetGlobalVariableOffset(variable, &ptr) && ptr != 0) {
- uint64_t offset_end = info->offset + info->end - info->start;
- if (ptr >= info->offset && ptr < offset_end) {
- ptr = info->start + ptr - info->offset;
- if (ReadVariableData(ptr)) {
- break;
- }
- }
- }
- } else if (info->offset == 0 && !info->name.empty()) {
- map_zero = info.get();
- }
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
deleted file mode 100644
index 8a85607..0000000
--- a/libunwindstack/JitDebug.cpp
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * Copyright (C) 2017 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 <memory>
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Maps.h>
-
-#include "MemoryRange.h"
-
-// This implements the JIT Compilation Interface.
-// See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
-
-namespace unwindstack {
-
-struct JITCodeEntry32Pack {
- uint32_t next;
- uint32_t prev;
- uint32_t symfile_addr;
- uint64_t symfile_size;
-} __attribute__((packed));
-
-struct JITCodeEntry32Pad {
- uint32_t next;
- uint32_t prev;
- uint32_t symfile_addr;
- uint32_t pad;
- uint64_t symfile_size;
-};
-
-struct JITCodeEntry64 {
- uint64_t next;
- uint64_t prev;
- uint64_t symfile_addr;
- uint64_t symfile_size;
-};
-
-struct JITDescriptorHeader {
- uint32_t version;
- uint32_t action_flag;
-};
-
-struct JITDescriptor32 {
- JITDescriptorHeader header;
- uint32_t relevant_entry;
- uint32_t first_entry;
-};
-
-struct JITDescriptor64 {
- JITDescriptorHeader header;
- uint64_t relevant_entry;
- uint64_t first_entry;
-};
-
-JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
-
-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;
- }
-
- if (desc.header.version != 1 || desc.first_entry == 0) {
- // Either unknown version, or no jit entries.
- return 0;
- }
-
- return desc.first_entry;
-}
-
-uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
- JITDescriptor64 desc;
- if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
- return 0;
- }
-
- if (desc.header.version != 1 || desc.first_entry == 0) {
- // Either unknown version, or no jit entries.
- return 0;
- }
-
- 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:
- read_descriptor_func_ = &JitDebug::ReadDescriptor32;
- read_entry_func_ = &JitDebug::ReadEntry32Pack;
- break;
-
- case ARCH_ARM:
- case ARCH_MIPS:
- read_descriptor_func_ = &JitDebug::ReadDescriptor32;
- read_entry_func_ = &JitDebug::ReadEntry32Pad;
- break;
-
- case ARCH_ARM64:
- case ARCH_X86_64:
- case ARCH_MIPS64:
- read_descriptor_func_ = &JitDebug::ReadDescriptor64;
- read_entry_func_ = &JitDebug::ReadEntry64;
- break;
- case ARCH_UNKNOWN:
- abort();
- }
-}
-
-bool JitDebug::ReadVariableData(uint64_t ptr) {
- entry_addr_ = (this->*read_descriptor_func_)(ptr);
- return entry_addr_ != 0;
-}
-
-void JitDebug::Init(Maps* maps) {
- if (initialized_) {
- return;
- }
- // Regardless of what happens below, consider the init finished.
- initialized_ = true;
-
- FindAndReadVariable(maps, "__jit_debug_descriptor");
-}
-
-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_) {
- Init(maps);
- }
-
- // Search the existing elf object first.
- for (Elf* elf : elf_list_) {
- if (elf->IsValidPc(pc)) {
- return elf;
- }
- }
-
- while (entry_addr_ != 0) {
- uint64_t start;
- uint64_t size;
- entry_addr_ = (this->*read_entry_func_)(&start, &size);
-
- 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;
- }
- }
- return nullptr;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp
deleted file mode 100644
index 05650fb..0000000
--- a/libunwindstack/LocalUnwinder.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <pthread.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/LocalUnwinder.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsGetLocal.h>
-
-namespace unwindstack {
-
-bool LocalUnwinder::Init() {
- pthread_rwlock_init(&maps_rwlock_, nullptr);
-
- // Create the maps.
- maps_.reset(new unwindstack::LocalUpdatableMaps());
- if (!maps_->Parse()) {
- maps_.reset();
- return false;
- }
-
- process_memory_ = unwindstack::Memory::CreateProcessMemory(getpid());
-
- return true;
-}
-
-bool LocalUnwinder::ShouldSkipLibrary(const std::string& map_name) {
- for (const std::string& skip_library : skip_libraries_) {
- if (skip_library == map_name) {
- return true;
- }
- }
- return false;
-}
-
-MapInfo* LocalUnwinder::GetMapInfo(uint64_t pc) {
- pthread_rwlock_rdlock(&maps_rwlock_);
- MapInfo* map_info = maps_->Find(pc);
- pthread_rwlock_unlock(&maps_rwlock_);
-
- if (map_info == nullptr) {
- pthread_rwlock_wrlock(&maps_rwlock_);
- // This is guaranteed not to invalidate any previous MapInfo objects so
- // we don't need to worry about any MapInfo* values already in use.
- if (maps_->Reparse()) {
- map_info = maps_->Find(pc);
- }
- pthread_rwlock_unlock(&maps_rwlock_);
- }
-
- return map_info;
-}
-
-bool LocalUnwinder::Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames) {
- std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
- unwindstack::RegsGetLocal(regs.get());
- ArchEnum arch = regs->Arch();
-
- size_t num_frames = 0;
- bool adjust_pc = false;
- while (true) {
- uint64_t cur_pc = regs->pc();
- uint64_t cur_sp = regs->sp();
-
- MapInfo* map_info = GetMapInfo(cur_pc);
- if (map_info == nullptr) {
- break;
- }
-
- Elf* elf = map_info->GetElf(process_memory_, arch);
- uint64_t rel_pc = elf->GetRelPc(cur_pc, map_info);
- uint64_t step_pc = rel_pc;
- uint64_t pc_adjustment;
- if (adjust_pc) {
- pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
- } else {
- pc_adjustment = 0;
- }
- step_pc -= pc_adjustment;
-
- bool finished = false;
- if (elf->StepIfSignalHandler(rel_pc, regs.get(), process_memory_.get())) {
- step_pc = rel_pc;
- } else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished)) {
- finished = true;
- }
-
- // Skip any locations that are within this library.
- if (num_frames != 0 || !ShouldSkipLibrary(map_info->name)) {
- // Add frame information.
- std::string func_name;
- uint64_t func_offset;
- if (elf->GetFunctionName(rel_pc, &func_name, &func_offset)) {
- frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment,
- func_name, func_offset);
- } else {
- frame_info->emplace_back(map_info, cur_pc - pc_adjustment, rel_pc - pc_adjustment, "", 0);
- }
- num_frames++;
- }
-
- if (finished || frame_info->size() == max_frames ||
- (cur_pc == regs->pc() && cur_sp == regs->sp())) {
- break;
- }
- adjust_pc = true;
- }
- return num_frames != 0;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/Log.cpp b/libunwindstack/Log.cpp
deleted file mode 100644
index 436e23c..0000000
--- a/libunwindstack/Log.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include <string>
-
-#define LOG_TAG "unwind"
-#include <log/log.h>
-
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/Log.h>
-
-namespace unwindstack {
-
-static bool g_print_to_stdout = false;
-
-void log_to_stdout(bool enable) {
- g_print_to_stdout = enable;
-}
-
-// Send the data to the log.
-void log(uint8_t indent, const char* format, ...) {
- std::string real_format;
- if (indent > 0) {
- real_format = android::base::StringPrintf("%*s%s", 2 * indent, " ", format);
- } else {
- real_format = format;
- }
- va_list args;
- va_start(args, format);
- if (g_print_to_stdout) {
- real_format += '\n';
- vprintf(real_format.c_str(), args);
- } else {
- LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, real_format.c_str(), args);
- }
- va_end(args);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp
deleted file mode 100644
index 31f3144..0000000
--- a/libunwindstack/MapInfo.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (C) 2017 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/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-
-#include "MemoryFileAtOffset.h"
-#include "MemoryRange.h"
-
-namespace unwindstack {
-
-bool MapInfo::InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory) {
- // One last attempt, see if the previous map is read-only with the
- // same name and stretches across this map.
- if (prev_real_map == nullptr || prev_real_map->flags != PROT_READ) {
- return false;
- }
-
- uint64_t map_size = end - prev_real_map->end;
- if (!memory->Init(name, prev_real_map->offset, map_size)) {
- return false;
- }
-
- uint64_t max_size;
- if (!Elf::GetInfo(memory, &max_size) || max_size < map_size) {
- return false;
- }
-
- if (!memory->Init(name, prev_real_map->offset, max_size)) {
- return false;
- }
-
- elf_offset = offset - prev_real_map->offset;
- elf_start_offset = prev_real_map->offset;
- return true;
-}
-
-Memory* MapInfo::GetFileMemory() {
- std::unique_ptr<MemoryFileAtOffset> memory(new MemoryFileAtOffset);
- if (offset == 0) {
- if (memory->Init(name, 0)) {
- return memory.release();
- }
- return nullptr;
- }
-
- // These are the possibilities when the offset is non-zero.
- // - There is an elf file embedded in a file, and the offset is the
- // the start of the elf in the file.
- // - There is an elf file embedded in a file, and the offset is the
- // the start of the executable part of the file. The actual start
- // of the elf is in the read-only segment preceeding this map.
- // - The whole file is an elf file, and the offset needs to be saved.
- //
- // Map in just the part of the file for the map. If this is not
- // a valid elf, then reinit as if the whole file is an elf file.
- // If the offset is a valid elf, then determine the size of the map
- // and reinit to that size. This is needed because the dynamic linker
- // only maps in a portion of the original elf, and never the symbol
- // file data.
- uint64_t map_size = end - start;
- if (!memory->Init(name, offset, map_size)) {
- return nullptr;
- }
-
- // Check if the start of this map is an embedded elf.
- uint64_t max_size = 0;
- if (Elf::GetInfo(memory.get(), &max_size)) {
- elf_start_offset = offset;
- if (max_size > map_size) {
- if (memory->Init(name, offset, max_size)) {
- return memory.release();
- }
- // Try to reinit using the default map_size.
- if (memory->Init(name, offset, map_size)) {
- return memory.release();
- }
- elf_start_offset = 0;
- return nullptr;
- }
- return memory.release();
- }
-
- // No elf at offset, try to init as if the whole file is an elf.
- if (memory->Init(name, 0) && Elf::IsValidElf(memory.get())) {
- elf_offset = offset;
- // Need to check how to set the elf start offset. If this map is not
- // the r-x map of a r-- map, then use the real offset value. Otherwise,
- // use 0.
- if (prev_real_map == nullptr || prev_real_map->offset != 0 ||
- prev_real_map->flags != PROT_READ || prev_real_map->name != name) {
- elf_start_offset = offset;
- }
- return memory.release();
- }
-
- // See if the map previous to this one contains a read-only map
- // that represents the real start of the elf data.
- if (InitFileMemoryFromPreviousReadOnlyMap(memory.get())) {
- return memory.release();
- }
-
- // Failed to find elf at start of file or at read-only map, return
- // file object from the current map.
- if (memory->Init(name, offset, map_size)) {
- return memory.release();
- }
- return nullptr;
-}
-
-Memory* MapInfo::CreateMemory(const std::shared_ptr<Memory>& process_memory) {
- if (end <= start) {
- return nullptr;
- }
-
- elf_offset = 0;
-
- // Fail on device maps.
- if (flags & MAPS_FLAGS_DEVICE_MAP) {
- return nullptr;
- }
-
- // First try and use the file associated with the info.
- if (!name.empty()) {
- Memory* memory = GetFileMemory();
- if (memory != nullptr) {
- return memory;
- }
- }
-
- if (process_memory == nullptr) {
- return nullptr;
- }
-
- // Need to verify that this elf is valid. It's possible that
- // only part of the elf file to be mapped into memory is in the executable
- // map. In this case, there will be another read-only map that includes the
- // first part of the elf file. This is done if the linker rosegment
- // option is used.
- std::unique_ptr<MemoryRange> memory(new MemoryRange(process_memory, start, end - start, 0));
- if (Elf::IsValidElf(memory.get())) {
- memory_backed_elf = true;
- return memory.release();
- }
-
- // Find the read-only map by looking at the previous map. The linker
- // doesn't guarantee that this invariant will always be true. However,
- // if that changes, there is likely something else that will change and
- // break something.
- if (offset == 0 || name.empty() || prev_real_map == nullptr || prev_real_map->name != name ||
- prev_real_map->offset >= offset) {
- return nullptr;
- }
-
- // Make sure that relative pc values are corrected properly.
- elf_offset = offset - prev_real_map->offset;
- // Use this as the elf start offset, otherwise, you always get offsets into
- // the r-x section, which is not quite the right information.
- elf_start_offset = prev_real_map->offset;
-
- MemoryRanges* ranges = new MemoryRanges;
- ranges->Insert(new MemoryRange(process_memory, prev_real_map->start,
- prev_real_map->end - prev_real_map->start, 0));
- ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset));
-
- memory_backed_elf = true;
- return ranges;
-}
-
-Elf* MapInfo::GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch) {
- {
- // Make sure no other thread is trying to add the elf to this map.
- std::lock_guard<std::mutex> guard(mutex_);
-
- if (elf.get() != nullptr) {
- return elf.get();
- }
-
- bool locked = false;
- if (Elf::CachingEnabled() && !name.empty()) {
- Elf::CacheLock();
- locked = true;
- if (Elf::CacheGet(this)) {
- Elf::CacheUnlock();
- return elf.get();
- }
- }
-
- Memory* memory = CreateMemory(process_memory);
- if (locked) {
- if (Elf::CacheAfterCreateMemory(this)) {
- delete memory;
- Elf::CacheUnlock();
- return elf.get();
- }
- }
- elf.reset(new Elf(memory));
- // If the init fails, keep the elf around as an invalid object so we
- // don't try to reinit the object.
- elf->Init();
- if (elf->valid() && expected_arch != elf->arch()) {
- // Make the elf invalid, mismatch between arch and expected arch.
- elf->Invalidate();
- }
-
- if (locked) {
- Elf::CacheAdd(this);
- Elf::CacheUnlock();
- }
- }
-
- if (!elf->valid()) {
- elf_start_offset = offset;
- } else if (prev_real_map != nullptr && elf_start_offset != offset &&
- prev_real_map->offset == elf_start_offset && prev_real_map->name == name) {
- // If there is a read-only map then a read-execute map that represents the
- // same elf object, make sure the previous map is using the same elf
- // object if it hasn't already been set.
- std::lock_guard<std::mutex> guard(prev_real_map->mutex_);
- if (prev_real_map->elf.get() == nullptr) {
- prev_real_map->elf = elf;
- prev_real_map->memory_backed_elf = memory_backed_elf;
- }
- }
- return elf.get();
-}
-
-bool MapInfo::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) {
- {
- // Make sure no other thread is trying to update this elf object.
- std::lock_guard<std::mutex> guard(mutex_);
- if (elf == nullptr) {
- return false;
- }
- }
- // No longer need the lock, once the elf object is created, it is not deleted
- // until this object is deleted.
- return elf->GetFunctionName(addr, name, func_offset);
-}
-
-uint64_t MapInfo::GetLoadBias(const std::shared_ptr<Memory>& process_memory) {
- int64_t cur_load_bias = load_bias.load();
- if (cur_load_bias != INT64_MAX) {
- return cur_load_bias;
- }
-
- {
- // Make sure no other thread is trying to add the elf to this map.
- std::lock_guard<std::mutex> guard(mutex_);
- if (elf != nullptr) {
- if (elf->valid()) {
- cur_load_bias = elf->GetLoadBias();
- load_bias = cur_load_bias;
- return cur_load_bias;
- } else {
- load_bias = 0;
- return 0;
- }
- }
- }
-
- // Call lightweight static function that will only read enough of the
- // elf data to get the load bias.
- std::unique_ptr<Memory> memory(CreateMemory(process_memory));
- cur_load_bias = Elf::GetLoadBias(memory.get());
- load_bias = cur_load_bias;
- return cur_load_bias;
-}
-
-MapInfo::~MapInfo() {
- uintptr_t id = build_id.load();
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- }
-}
-
-std::string MapInfo::GetBuildID() {
- uintptr_t id = build_id.load();
- if (id != 0) {
- return *reinterpret_cast<std::string*>(id);
- }
-
- // No need to lock, at worst if multiple threads do this at the same
- // time it should be detected and only one thread should win and
- // save the data.
- std::unique_ptr<std::string> cur_build_id(new std::string);
-
- // Now need to see if the elf object exists.
- // Make sure no other thread is trying to add the elf to this map.
- mutex_.lock();
- Elf* elf_obj = elf.get();
- mutex_.unlock();
- if (elf_obj != nullptr) {
- *cur_build_id = elf_obj->GetBuildID();
- } else {
- // This will only work if we can get the file associated with this memory.
- // If this is only available in memory, then the section name information
- // is not present and we will not be able to find the build id info.
- std::unique_ptr<Memory> memory(GetFileMemory());
- if (memory != nullptr) {
- *cur_build_id = Elf::GetBuildID(memory.get());
- }
- }
-
- id = reinterpret_cast<uintptr_t>(cur_build_id.get());
- uintptr_t expected_id = 0;
- if (build_id.compare_exchange_weak(expected_id, id)) {
- // Value saved, so make sure the memory is not freed.
- cur_build_id.release();
- }
- return *reinterpret_cast<std::string*>(id);
-}
-
-std::string MapInfo::GetPrintableBuildID() {
- std::string raw_build_id = GetBuildID();
- if (raw_build_id.empty()) {
- return "";
- }
- std::string printable_build_id;
- for (const char& c : raw_build_id) {
- // Use %hhx to avoid sign extension on abis that have signed chars.
- printable_build_id += android::base::StringPrintf("%02hhx", c);
- }
- return printable_build_id;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/Maps.cpp b/libunwindstack/Maps.cpp
deleted file mode 100644
index 670d904..0000000
--- a/libunwindstack/Maps.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android-base/unique_fd.h>
-#include <procinfo/process_map.h>
-
-#include <algorithm>
-#include <cctype>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-MapInfo* Maps::Find(uint64_t pc) {
- if (maps_.empty()) {
- return nullptr;
- }
- size_t first = 0;
- size_t last = maps_.size();
- while (first < last) {
- size_t index = (first + last) / 2;
- const auto& cur = maps_[index];
- if (pc >= cur->start && pc < cur->end) {
- return cur.get();
- } else if (pc < cur->start) {
- last = index;
- } else {
- first = index + 1;
- }
- }
- return nullptr;
-}
-
-bool Maps::Parse() {
- MapInfo* prev_map = nullptr;
- MapInfo* prev_real_map = nullptr;
- return android::procinfo::ReadMapFile(
- GetMapsFile(),
- [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t, const char* name) {
- // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
- if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
- flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
- }
- maps_.emplace_back(new MapInfo(prev_map, prev_real_map, start, end, pgoff, flags, name));
- prev_map = maps_.back().get();
- if (!prev_map->IsBlank()) {
- prev_real_map = prev_map;
- }
- });
-}
-
-void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
- const std::string& name, uint64_t load_bias) {
- MapInfo* prev_map = maps_.empty() ? nullptr : maps_.back().get();
- MapInfo* prev_real_map = prev_map;
- while (prev_real_map != nullptr && prev_real_map->IsBlank()) {
- prev_real_map = prev_real_map->prev_map;
- }
-
- auto map_info =
- std::make_unique<MapInfo>(prev_map, prev_real_map, start, end, offset, flags, name);
- map_info->load_bias = load_bias;
- maps_.emplace_back(std::move(map_info));
-}
-
-void Maps::Sort() {
- std::sort(maps_.begin(), maps_.end(),
- [](const std::unique_ptr<MapInfo>& a, const std::unique_ptr<MapInfo>& b) {
- return a->start < b->start; });
-
- // Set the prev_map values on the info objects.
- MapInfo* prev_map = nullptr;
- MapInfo* prev_real_map = nullptr;
- for (const auto& map_info : maps_) {
- map_info->prev_map = prev_map;
- map_info->prev_real_map = prev_real_map;
- prev_map = map_info.get();
- if (!prev_map->IsBlank()) {
- prev_real_map = prev_map;
- }
- }
-}
-
-bool BufferMaps::Parse() {
- std::string content(buffer_);
- MapInfo* prev_map = nullptr;
- MapInfo* prev_real_map = nullptr;
- return android::procinfo::ReadMapFileContent(
- &content[0],
- [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t, const char* name) {
- // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
- if (strncmp(name, "/dev/", 5) == 0 && strncmp(name + 5, "ashmem/", 7) != 0) {
- flags |= unwindstack::MAPS_FLAGS_DEVICE_MAP;
- }
- maps_.emplace_back(new MapInfo(prev_map, prev_real_map, start, end, pgoff, flags, name));
- prev_map = maps_.back().get();
- if (!prev_map->IsBlank()) {
- prev_real_map = prev_map;
- }
- });
-}
-
-const std::string RemoteMaps::GetMapsFile() const {
- return "/proc/" + std::to_string(pid_) + "/maps";
-}
-
-const std::string LocalUpdatableMaps::GetMapsFile() const {
- return "/proc/self/maps";
-}
-
-bool LocalUpdatableMaps::Reparse() {
- // New maps will be added at the end without deleting the old ones.
- size_t last_map_idx = maps_.size();
- if (!Parse()) {
- maps_.resize(last_map_idx);
- return false;
- }
-
- size_t total_entries = maps_.size();
- size_t search_map_idx = 0;
- for (size_t new_map_idx = last_map_idx; new_map_idx < maps_.size(); new_map_idx++) {
- auto& new_map_info = maps_[new_map_idx];
- uint64_t start = new_map_info->start;
- uint64_t end = new_map_info->end;
- uint64_t flags = new_map_info->flags;
- std::string* name = &new_map_info->name;
- for (size_t old_map_idx = search_map_idx; old_map_idx < last_map_idx; old_map_idx++) {
- auto& info = maps_[old_map_idx];
- if (start == info->start && end == info->end && flags == info->flags && *name == info->name) {
- // No need to check
- search_map_idx = old_map_idx + 1;
- if (new_map_idx + 1 < maps_.size()) {
- maps_[new_map_idx + 1]->prev_map = info.get();
- maps_[new_map_idx + 1]->prev_real_map =
- info->IsBlank() ? info->prev_real_map : info.get();
- }
- maps_[new_map_idx] = nullptr;
- total_entries--;
- break;
- } else if (info->start > start) {
- // Stop, there isn't going to be a match.
- search_map_idx = old_map_idx;
- break;
- }
-
- // Never delete these maps, they may be in use. The assumption is
- // that there will only every be a handful of these so waiting
- // to destroy them is not too expensive.
- saved_maps_.emplace_back(std::move(info));
- search_map_idx = old_map_idx + 1;
- maps_[old_map_idx] = nullptr;
- total_entries--;
- }
- if (search_map_idx >= last_map_idx) {
- break;
- }
- }
-
- // Now move out any of the maps that never were found.
- for (size_t i = search_map_idx; i < last_map_idx; i++) {
- saved_maps_.emplace_back(std::move(maps_[i]));
- maps_[i] = nullptr;
- total_entries--;
- }
-
- // Sort all of the values such that the nullptrs wind up at the end, then
- // resize them away.
- std::sort(maps_.begin(), maps_.end(), [](const auto& a, const auto& b) {
- if (a == nullptr) {
- return false;
- } else if (b == nullptr) {
- return true;
- }
- return a->start < b->start;
- });
- maps_.resize(total_entries);
-
- return true;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
deleted file mode 100644
index b4623fa..0000000
--- a/libunwindstack/Memory.cpp
+++ /dev/null
@@ -1,498 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <memory>
-
-#include <android-base/unique_fd.h>
-
-#include <unwindstack/Memory.h>
-
-#include "Check.h"
-#include "MemoryBuffer.h"
-#include "MemoryCache.h"
-#include "MemoryFileAtOffset.h"
-#include "MemoryLocal.h"
-#include "MemoryOffline.h"
-#include "MemoryOfflineBuffer.h"
-#include "MemoryRange.h"
-#include "MemoryRemote.h"
-
-namespace unwindstack {
-
-static size_t ProcessVmRead(pid_t pid, uint64_t remote_src, void* dst, size_t len) {
-
- // Split up the remote read across page boundaries.
- // From the manpage:
- // A partial read/write may result if one of the remote_iov elements points to an invalid
- // memory region in the remote process.
- //
- // Partial transfers apply at the granularity of iovec elements. These system calls won't
- // perform a partial transfer that splits a single iovec element.
- constexpr size_t kMaxIovecs = 64;
- struct iovec src_iovs[kMaxIovecs];
-
- uint64_t cur = remote_src;
- size_t total_read = 0;
- while (len > 0) {
- struct iovec dst_iov = {
- .iov_base = &reinterpret_cast<uint8_t*>(dst)[total_read], .iov_len = len,
- };
-
- size_t iovecs_used = 0;
- while (len > 0) {
- if (iovecs_used == kMaxIovecs) {
- break;
- }
-
- // struct iovec uses void* for iov_base.
- if (cur >= UINTPTR_MAX) {
- errno = EFAULT;
- return total_read;
- }
-
- src_iovs[iovecs_used].iov_base = reinterpret_cast<void*>(cur);
-
- uintptr_t misalignment = cur & (getpagesize() - 1);
- size_t iov_len = getpagesize() - misalignment;
- iov_len = std::min(iov_len, len);
-
- len -= iov_len;
- if (__builtin_add_overflow(cur, iov_len, &cur)) {
- errno = EFAULT;
- return total_read;
- }
-
- src_iovs[iovecs_used].iov_len = iov_len;
- ++iovecs_used;
- }
-
- ssize_t rc = process_vm_readv(pid, &dst_iov, 1, src_iovs, iovecs_used, 0);
- if (rc == -1) {
- return total_read;
- }
- total_read += rc;
- }
- return total_read;
-}
-
-static bool PtraceReadLong(pid_t pid, uint64_t addr, long* value) {
- // ptrace() returns -1 and sets errno when the operation fails.
- // To disambiguate -1 from a valid result, we clear errno beforehand.
- errno = 0;
- *value = ptrace(PTRACE_PEEKTEXT, pid, reinterpret_cast<void*>(addr), nullptr);
- if (*value == -1 && errno) {
- return false;
- }
- return true;
-}
-
-static size_t PtraceRead(pid_t pid, uint64_t addr, void* dst, size_t bytes) {
- // Make sure that there is no overflow.
- uint64_t max_size;
- if (__builtin_add_overflow(addr, bytes, &max_size)) {
- return 0;
- }
-
- size_t bytes_read = 0;
- long data;
- size_t align_bytes = addr & (sizeof(long) - 1);
- if (align_bytes != 0) {
- if (!PtraceReadLong(pid, addr & ~(sizeof(long) - 1), &data)) {
- return 0;
- }
- size_t copy_bytes = std::min(sizeof(long) - align_bytes, bytes);
- memcpy(dst, reinterpret_cast<uint8_t*>(&data) + align_bytes, copy_bytes);
- addr += copy_bytes;
- dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + copy_bytes);
- bytes -= copy_bytes;
- bytes_read += copy_bytes;
- }
-
- for (size_t i = 0; i < bytes / sizeof(long); i++) {
- if (!PtraceReadLong(pid, addr, &data)) {
- return bytes_read;
- }
- memcpy(dst, &data, sizeof(long));
- dst = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(dst) + sizeof(long));
- addr += sizeof(long);
- bytes_read += sizeof(long);
- }
-
- size_t left_over = bytes & (sizeof(long) - 1);
- if (left_over) {
- if (!PtraceReadLong(pid, addr, &data)) {
- return bytes_read;
- }
- memcpy(dst, &data, left_over);
- bytes_read += left_over;
- }
- return bytes_read;
-}
-
-bool Memory::ReadFully(uint64_t addr, void* dst, size_t size) {
- size_t rc = Read(addr, dst, size);
- return rc == size;
-}
-
-bool Memory::ReadString(uint64_t addr, std::string* dst, size_t max_read) {
- char buffer[256]; // Large enough for 99% of symbol names.
- size_t size = 0; // Number of bytes which were read into the buffer.
- for (size_t offset = 0; offset < max_read; offset += size) {
- // Look for null-terminator first, so we can allocate string of exact size.
- // If we know the end of valid memory range, do the reads in larger blocks.
- size_t read = std::min(sizeof(buffer), max_read - offset);
- size = Read(addr + offset, buffer, read);
- if (size == 0) {
- return false; // We have not found end of string yet and we can not read more data.
- }
- size_t length = strnlen(buffer, size); // Index of the null-terminator.
- if (length < size) {
- // We found the null-terminator. Allocate the string and set its content.
- if (offset == 0) {
- // We did just single read, so the buffer already contains the whole string.
- dst->assign(buffer, length);
- return true;
- } else {
- // The buffer contains only the last block. Read the whole string again.
- dst->assign(offset + length, '\0');
- return ReadFully(addr, dst->data(), dst->size());
- }
- }
- }
- return false;
-}
-
-std::unique_ptr<Memory> Memory::CreateFileMemory(const std::string& path, uint64_t offset) {
- auto memory = std::make_unique<MemoryFileAtOffset>();
-
- if (memory->Init(path, offset)) {
- return memory;
- }
-
- return nullptr;
-}
-
-std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
- if (pid == getpid()) {
- return std::shared_ptr<Memory>(new MemoryLocal());
- }
- return std::shared_ptr<Memory>(new MemoryRemote(pid));
-}
-
-std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
- if (pid == getpid()) {
- return std::shared_ptr<Memory>(new MemoryCache(new MemoryLocal()));
- }
- return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
-}
-
-std::shared_ptr<Memory> Memory::CreateOfflineMemory(const uint8_t* data, uint64_t start,
- uint64_t end) {
- return std::shared_ptr<Memory>(new MemoryOfflineBuffer(data, start, end));
-}
-
-size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) {
- if (addr >= size_) {
- return 0;
- }
-
- size_t bytes_left = size_ - static_cast<size_t>(addr);
- const unsigned char* actual_base = static_cast<const unsigned char*>(raw_) + addr;
- size_t actual_len = std::min(bytes_left, size);
-
- memcpy(dst, actual_base, actual_len);
- return actual_len;
-}
-
-uint8_t* MemoryBuffer::GetPtr(size_t offset) {
- if (offset < size_) {
- return &raw_[offset];
- }
- return nullptr;
-}
-
-MemoryFileAtOffset::~MemoryFileAtOffset() {
- Clear();
-}
-
-void MemoryFileAtOffset::Clear() {
- if (data_) {
- munmap(&data_[-offset_], size_ + offset_);
- data_ = nullptr;
- }
-}
-
-bool MemoryFileAtOffset::Init(const std::string& file, uint64_t offset, uint64_t size) {
- // Clear out any previous data if it exists.
- Clear();
-
- android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd == -1) {
- return false;
- }
- struct stat buf;
- if (fstat(fd, &buf) == -1) {
- return false;
- }
- if (offset >= static_cast<uint64_t>(buf.st_size)) {
- return false;
- }
-
- offset_ = offset & (getpagesize() - 1);
- uint64_t aligned_offset = offset & ~(getpagesize() - 1);
- if (aligned_offset > static_cast<uint64_t>(buf.st_size) ||
- offset > static_cast<uint64_t>(buf.st_size)) {
- return false;
- }
-
- size_ = buf.st_size - aligned_offset;
- uint64_t max_size;
- if (!__builtin_add_overflow(size, offset_, &max_size) && max_size < size_) {
- // Truncate the mapped size.
- size_ = max_size;
- }
- void* map = mmap(nullptr, size_, PROT_READ, MAP_PRIVATE, fd, aligned_offset);
- if (map == MAP_FAILED) {
- return false;
- }
-
- data_ = &reinterpret_cast<uint8_t*>(map)[offset_];
- size_ -= offset_;
-
- return true;
-}
-
-size_t MemoryFileAtOffset::Read(uint64_t addr, void* dst, size_t size) {
- if (addr >= size_) {
- return 0;
- }
-
- size_t bytes_left = size_ - static_cast<size_t>(addr);
- const unsigned char* actual_base = static_cast<const unsigned char*>(data_) + addr;
- size_t actual_len = std::min(bytes_left, size);
-
- memcpy(dst, actual_base, actual_len);
- return actual_len;
-}
-
-size_t MemoryRemote::Read(uint64_t addr, void* dst, size_t size) {
-#if !defined(__LP64__)
- // Cannot read an address greater than 32 bits in a 32 bit context.
- if (addr > UINT32_MAX) {
- return 0;
- }
-#endif
-
- size_t (*read_func)(pid_t, uint64_t, void*, size_t) =
- reinterpret_cast<size_t (*)(pid_t, uint64_t, void*, size_t)>(read_redirect_func_.load());
- if (read_func != nullptr) {
- return read_func(pid_, addr, dst, size);
- } else {
- // Prefer process_vm_read, try it first. If it doesn't work, use the
- // ptrace function. If at least one of them returns at least some data,
- // set that as the permanent function to use.
- // This assumes that if process_vm_read works once, it will continue
- // to work.
- size_t bytes = ProcessVmRead(pid_, addr, dst, size);
- if (bytes > 0) {
- read_redirect_func_ = reinterpret_cast<uintptr_t>(ProcessVmRead);
- return bytes;
- }
- bytes = PtraceRead(pid_, addr, dst, size);
- if (bytes > 0) {
- read_redirect_func_ = reinterpret_cast<uintptr_t>(PtraceRead);
- }
- return bytes;
- }
-}
-
-size_t MemoryLocal::Read(uint64_t addr, void* dst, size_t size) {
- return ProcessVmRead(getpid(), addr, dst, size);
-}
-
-#if !defined(ANDROID_EXPERIMENTAL_MTE)
-long MemoryRemote::ReadTag(uint64_t) {
- return -1;
-}
-
-long MemoryLocal::ReadTag(uint64_t) {
- return -1;
-}
-#endif
-
-MemoryRange::MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
- uint64_t offset)
- : memory_(memory), begin_(begin), length_(length), offset_(offset) {}
-
-size_t MemoryRange::Read(uint64_t addr, void* dst, size_t size) {
- if (addr < offset_) {
- return 0;
- }
-
- uint64_t read_offset = addr - offset_;
- if (read_offset >= length_) {
- return 0;
- }
-
- uint64_t read_length = std::min(static_cast<uint64_t>(size), length_ - read_offset);
- uint64_t read_addr;
- if (__builtin_add_overflow(read_offset, begin_, &read_addr)) {
- return 0;
- }
-
- return memory_->Read(read_addr, dst, read_length);
-}
-
-void MemoryRanges::Insert(MemoryRange* memory) {
- maps_.emplace(memory->offset() + memory->length(), memory);
-}
-
-size_t MemoryRanges::Read(uint64_t addr, void* dst, size_t size) {
- auto entry = maps_.upper_bound(addr);
- if (entry != maps_.end()) {
- return entry->second->Read(addr, dst, size);
- }
- return 0;
-}
-
-bool MemoryOffline::Init(const std::string& file, uint64_t offset) {
- auto memory_file = std::make_shared<MemoryFileAtOffset>();
- if (!memory_file->Init(file, offset)) {
- return false;
- }
-
- // The first uint64_t value is the start of memory.
- uint64_t start;
- if (!memory_file->ReadFully(0, &start, sizeof(start))) {
- return false;
- }
-
- uint64_t size = memory_file->Size();
- if (__builtin_sub_overflow(size, sizeof(start), &size)) {
- return false;
- }
-
- memory_ = std::make_unique<MemoryRange>(memory_file, sizeof(start), size, start);
- return true;
-}
-
-size_t MemoryOffline::Read(uint64_t addr, void* dst, size_t size) {
- if (!memory_) {
- return 0;
- }
-
- return memory_->Read(addr, dst, size);
-}
-
-MemoryOfflineBuffer::MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end)
- : data_(data), start_(start), end_(end) {}
-
-void MemoryOfflineBuffer::Reset(const uint8_t* data, uint64_t start, uint64_t end) {
- data_ = data;
- start_ = start;
- end_ = end;
-}
-
-size_t MemoryOfflineBuffer::Read(uint64_t addr, void* dst, size_t size) {
- if (addr < start_ || addr >= end_) {
- return 0;
- }
-
- size_t read_length = std::min(size, static_cast<size_t>(end_ - addr));
- memcpy(dst, &data_[addr - start_], read_length);
- return read_length;
-}
-
-MemoryOfflineParts::~MemoryOfflineParts() {
- for (auto memory : memories_) {
- delete memory;
- }
-}
-
-size_t MemoryOfflineParts::Read(uint64_t addr, void* dst, size_t size) {
- if (memories_.empty()) {
- return 0;
- }
-
- // Do a read on each memory object, no support for reading across the
- // different memory objects.
- for (MemoryOffline* memory : memories_) {
- size_t bytes = memory->Read(addr, dst, size);
- if (bytes != 0) {
- return bytes;
- }
- }
- return 0;
-}
-
-size_t MemoryCache::Read(uint64_t addr, void* dst, size_t size) {
- // Only bother caching and looking at the cache if this is a small read for now.
- if (size > 64) {
- return impl_->Read(addr, dst, size);
- }
-
- uint64_t addr_page = addr >> kCacheBits;
- auto entry = cache_.find(addr_page);
- uint8_t* cache_dst;
- if (entry != cache_.end()) {
- cache_dst = entry->second;
- } else {
- cache_dst = cache_[addr_page];
- if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
- // Erase the entry.
- cache_.erase(addr_page);
- return impl_->Read(addr, dst, size);
- }
- }
- size_t max_read = ((addr_page + 1) << kCacheBits) - addr;
- if (size <= max_read) {
- memcpy(dst, &cache_dst[addr & kCacheMask], size);
- return size;
- }
-
- // The read crossed into another cached entry, since a read can only cross
- // into one extra cached page, duplicate the code rather than looping.
- memcpy(dst, &cache_dst[addr & kCacheMask], max_read);
- dst = &reinterpret_cast<uint8_t*>(dst)[max_read];
- addr_page++;
-
- entry = cache_.find(addr_page);
- if (entry != cache_.end()) {
- cache_dst = entry->second;
- } else {
- cache_dst = cache_[addr_page];
- if (!impl_->ReadFully(addr_page << kCacheBits, cache_dst, kCacheSize)) {
- // Erase the entry.
- cache_.erase(addr_page);
- return impl_->Read(addr_page << kCacheBits, dst, size - max_read) + max_read;
- }
- }
- memcpy(dst, cache_dst, size - max_read);
- return size;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/MemoryBuffer.h b/libunwindstack/MemoryBuffer.h
deleted file mode 100644
index a91e59f..0000000
--- a/libunwindstack/MemoryBuffer.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_BUFFER_H
-#define _LIBUNWINDSTACK_MEMORY_BUFFER_H
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class MemoryBuffer : public Memory {
- public:
- MemoryBuffer() = default;
- virtual ~MemoryBuffer() { free(raw_); }
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- uint8_t* GetPtr(size_t offset);
-
- bool Resize(size_t size) {
- raw_ = reinterpret_cast<uint8_t*>(realloc(raw_, size));
- if (raw_ == nullptr) {
- size_ = 0;
- return false;
- }
- size_ = size;
- return true;
- }
-
- uint64_t Size() { return size_; }
-
- private:
- uint8_t* raw_ = nullptr;
- size_t size_ = 0;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_BUFFER_H
diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h
deleted file mode 100644
index d97640d..0000000
--- a/libunwindstack/MemoryCache.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_CACHE_H
-#define _LIBUNWINDSTACK_MEMORY_CACHE_H
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class MemoryCache : public Memory {
- public:
- MemoryCache(Memory* memory) : impl_(memory) {}
- virtual ~MemoryCache() = default;
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
- long ReadTag(uint64_t addr) override { return impl_->ReadTag(addr); }
-
- void Clear() override { cache_.clear(); }
-
- private:
- constexpr static size_t kCacheBits = 12;
- constexpr static size_t kCacheMask = (1 << kCacheBits) - 1;
- constexpr static size_t kCacheSize = 1 << kCacheBits;
- std::unordered_map<uint64_t, uint8_t[kCacheSize]> cache_;
-
- std::unique_ptr<Memory> impl_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_CACHE_H
diff --git a/libunwindstack/MemoryFileAtOffset.h b/libunwindstack/MemoryFileAtOffset.h
deleted file mode 100644
index d136eb4..0000000
--- a/libunwindstack/MemoryFileAtOffset.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
-#define _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
-
-#include <stdint.h>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class MemoryFileAtOffset : public Memory {
- public:
- MemoryFileAtOffset() = default;
- virtual ~MemoryFileAtOffset();
-
- bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX);
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- size_t Size() { return size_; }
-
- void Clear() override;
-
- protected:
- size_t size_ = 0;
- size_t offset_ = 0;
- uint8_t* data_ = nullptr;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H
diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h
deleted file mode 100644
index 741f107..0000000
--- a/libunwindstack/MemoryLocal.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_LOCAL_H
-#define _LIBUNWINDSTACK_MEMORY_LOCAL_H
-
-#include <stdint.h>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class MemoryLocal : public Memory {
- public:
- MemoryLocal() = default;
- virtual ~MemoryLocal() = default;
-
- bool IsLocal() const override { return true; }
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
- long ReadTag(uint64_t addr) override;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_LOCAL_H
diff --git a/libunwindstack/MemoryMte.cpp b/libunwindstack/MemoryMte.cpp
deleted file mode 100644
index 46a546e..0000000
--- a/libunwindstack/MemoryMte.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#if defined(ANDROID_EXPERIMENTAL_MTE)
-
-#include <sys/ptrace.h>
-#include <sys/uio.h>
-
-#include <bionic/mte.h>
-#include <bionic/mte_kernel.h>
-
-#include "MemoryLocal.h"
-#include "MemoryRemote.h"
-
-namespace unwindstack {
-
-long MemoryRemote::ReadTag(uint64_t addr) {
-#if defined(__aarch64__)
- char tag;
- iovec iov = {&tag, 1};
- if (ptrace(PTRACE_PEEKMTETAGS, pid_, reinterpret_cast<void*>(addr), &iov) != 0 ||
- iov.iov_len != 1) {
- return -1;
- }
- return tag;
-#else
- (void)addr;
- return -1;
-#endif
-}
-
-long MemoryLocal::ReadTag(uint64_t addr) {
-#if defined(__aarch64__)
- // Check that the memory is readable first. This is racy with the ldg but there's not much
- // we can do about it.
- char data;
- if (!mte_supported() || !Read(addr, &data, 1)) {
- return -1;
- }
-
- __asm__ __volatile__(".arch_extension mte; ldg %0, [%0]" : "+r"(addr) : : "memory");
- return (addr >> 56) & 0xf;
-#else
- (void)addr;
- return -1;
-#endif
-}
-
-} // namespace unwindstack
-
-#endif
diff --git a/libunwindstack/MemoryOffline.h b/libunwindstack/MemoryOffline.h
deleted file mode 100644
index 789f1a2..0000000
--- a/libunwindstack/MemoryOffline.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_OFFLINE_H
-#define _LIBUNWINDSTACK_MEMORY_OFFLINE_H
-
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Memory.h>
-
-#include "MemoryRange.h"
-
-namespace unwindstack {
-
-class MemoryOffline : public Memory {
- public:
- MemoryOffline() = default;
- virtual ~MemoryOffline() = default;
-
- bool Init(const std::string& file, uint64_t offset);
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
- std::unique_ptr<MemoryRange> memory_;
-};
-
-class MemoryOfflineParts : public Memory {
- public:
- MemoryOfflineParts() = default;
- virtual ~MemoryOfflineParts();
-
- void Add(MemoryOffline* memory) { memories_.push_back(memory); }
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
- std::vector<MemoryOffline*> memories_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_H
diff --git a/libunwindstack/MemoryOfflineBuffer.h b/libunwindstack/MemoryOfflineBuffer.h
deleted file mode 100644
index 64c49a1..0000000
--- a/libunwindstack/MemoryOfflineBuffer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
-#define _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
-
-#include <stdint.h>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class MemoryOfflineBuffer : public Memory {
- public:
- MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end);
- virtual ~MemoryOfflineBuffer() = default;
-
- void Reset(const uint8_t* data, uint64_t start, uint64_t end);
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
- const uint8_t* data_;
- uint64_t start_;
- uint64_t end_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H
diff --git a/libunwindstack/MemoryRange.h b/libunwindstack/MemoryRange.h
deleted file mode 100644
index 3b4ab5c..0000000
--- a/libunwindstack/MemoryRange.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_RANGE_H
-#define _LIBUNWINDSTACK_MEMORY_RANGE_H
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-// MemoryRange maps one address range onto another.
-// The range [src_begin, src_begin + length) in the underlying Memory is mapped onto offset,
-// such that range.read(offset) is equivalent to underlying.read(src_begin).
-class MemoryRange : public Memory {
- public:
- MemoryRange(const std::shared_ptr<Memory>& memory, uint64_t begin, uint64_t length,
- uint64_t offset);
- virtual ~MemoryRange() = default;
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- uint64_t offset() { return offset_; }
- uint64_t length() { return length_; }
-
- private:
- std::shared_ptr<Memory> memory_;
- uint64_t begin_;
- uint64_t length_;
- uint64_t offset_;
-};
-
-class MemoryRanges : public Memory {
- public:
- MemoryRanges() = default;
- virtual ~MemoryRanges() = default;
-
- void Insert(MemoryRange* memory);
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- private:
- std::map<uint64_t, std::unique_ptr<MemoryRange>> maps_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_RANGE_H
diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h
deleted file mode 100644
index dd09c88..0000000
--- a/libunwindstack/MemoryRemote.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_REMOTE_H
-#define _LIBUNWINDSTACK_MEMORY_REMOTE_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <atomic>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class MemoryRemote : public Memory {
- public:
- MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {}
- virtual ~MemoryRemote() = default;
-
- size_t Read(uint64_t addr, void* dst, size_t size) override;
- long ReadTag(uint64_t addr) override;
-
- pid_t pid() { return pid_; }
-
- private:
- pid_t pid_;
- std::atomic_uintptr_t read_redirect_func_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_REMOTE_H
diff --git a/libunwindstack/OWNERS b/libunwindstack/OWNERS
deleted file mode 100644
index 6f7e4a3..0000000
--- a/libunwindstack/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-cferris@google.com
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
deleted file mode 100644
index 03aa6c2..0000000
--- a/libunwindstack/Regs.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <sys/ptrace.h>
-#include <sys/uio.h>
-
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsMips.h>
-#include <unwindstack/RegsMips64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-#include <unwindstack/UserArm.h>
-#include <unwindstack/UserArm64.h>
-#include <unwindstack/UserMips.h>
-#include <unwindstack/UserMips64.h>
-#include <unwindstack/UserX86.h>
-#include <unwindstack/UserX86_64.h>
-
-namespace unwindstack {
-
-// The largest user structure.
-constexpr size_t MAX_USER_REGS_SIZE = sizeof(mips64_user_regs) + 10;
-
-// This function assumes that reg_data is already aligned to a 64 bit value.
-// If not this could crash with an unaligned access.
-Regs* Regs::RemoteGet(pid_t pid) {
- // Make the buffer large enough to contain the largest registers type.
- std::vector<uint64_t> buffer(MAX_USER_REGS_SIZE / sizeof(uint64_t));
- struct iovec io;
- io.iov_base = buffer.data();
- io.iov_len = buffer.size() * sizeof(uint64_t);
-
- if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, reinterpret_cast<void*>(&io)) == -1) {
- return nullptr;
- }
-
- switch (io.iov_len) {
- case sizeof(x86_user_regs):
- return RegsX86::Read(buffer.data());
- case sizeof(x86_64_user_regs):
- return RegsX86_64::Read(buffer.data());
- case sizeof(arm_user_regs):
- return RegsArm::Read(buffer.data());
- case sizeof(arm64_user_regs):
- return RegsArm64::Read(buffer.data());
- case sizeof(mips_user_regs):
- return RegsMips::Read(buffer.data());
- case sizeof(mips64_user_regs):
- return RegsMips64::Read(buffer.data());
- }
- return nullptr;
-}
-
-Regs* Regs::CreateFromUcontext(ArchEnum arch, void* ucontext) {
- switch (arch) {
- case ARCH_X86:
- return RegsX86::CreateFromUcontext(ucontext);
- case ARCH_X86_64:
- return RegsX86_64::CreateFromUcontext(ucontext);
- case ARCH_ARM:
- return RegsArm::CreateFromUcontext(ucontext);
- case ARCH_ARM64:
- return RegsArm64::CreateFromUcontext(ucontext);
- case ARCH_MIPS:
- return RegsMips::CreateFromUcontext(ucontext);
- case ARCH_MIPS64:
- return RegsMips64::CreateFromUcontext(ucontext);
- case ARCH_UNKNOWN:
- default:
- return nullptr;
- }
-}
-
-ArchEnum Regs::CurrentArch() {
-#if defined(__arm__)
- return ARCH_ARM;
-#elif defined(__aarch64__)
- return ARCH_ARM64;
-#elif defined(__i386__)
- return ARCH_X86;
-#elif defined(__x86_64__)
- return ARCH_X86_64;
-#else
- abort();
-#endif
-}
-
-Regs* Regs::CreateFromLocal() {
- Regs* regs;
-#if defined(__arm__)
- regs = new RegsArm();
-#elif defined(__aarch64__)
- regs = new RegsArm64();
-#elif defined(__i386__)
- regs = new RegsX86();
-#elif defined(__x86_64__)
- regs = new RegsX86_64();
-#else
- abort();
-#endif
- return regs;
-}
-
-uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch) {
- switch (arch) {
- case ARCH_ARM: {
- if (!elf->valid()) {
- return 2;
- }
-
- uint64_t load_bias = elf->GetLoadBias();
- if (rel_pc < load_bias) {
- if (rel_pc < 2) {
- return 0;
- }
- return 2;
- }
- uint64_t adjusted_rel_pc = rel_pc - load_bias;
- if (adjusted_rel_pc < 5) {
- if (adjusted_rel_pc < 2) {
- return 0;
- }
- return 2;
- }
-
- if (adjusted_rel_pc & 1) {
- // This is a thumb instruction, it could be 2 or 4 bytes.
- uint32_t value;
- if (!elf->memory()->ReadFully(adjusted_rel_pc - 5, &value, sizeof(value)) ||
- (value & 0xe000f000) != 0xe000f000) {
- return 2;
- }
- }
- return 4;
- }
- case ARCH_ARM64: {
- if (rel_pc < 4) {
- return 0;
- }
- return 4;
- }
- case ARCH_MIPS:
- case ARCH_MIPS64: {
- if (rel_pc < 8) {
- return 0;
- }
- // For now, just assume no compact branches
- return 8;
- }
- case ARCH_X86:
- case ARCH_X86_64: {
- if (rel_pc == 0) {
- return 0;
- }
- return 1;
- }
- case ARCH_UNKNOWN:
- return 0;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
deleted file mode 100644
index 1aaa08f..0000000
--- a/libunwindstack/RegsArm.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <string.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/UcontextArm.h>
-#include <unwindstack/UserArm.h>
-
-namespace unwindstack {
-
-RegsArm::RegsArm() : RegsImpl<uint32_t>(ARM_REG_LAST, Location(LOCATION_REGISTER, ARM_REG_LR)) {}
-
-ArchEnum RegsArm::Arch() {
- return ARCH_ARM;
-}
-
-uint64_t RegsArm::pc() {
- return regs_[ARM_REG_PC];
-}
-
-uint64_t RegsArm::sp() {
- return regs_[ARM_REG_SP];
-}
-
-void RegsArm::set_pc(uint64_t pc) {
- regs_[ARM_REG_PC] = pc;
-}
-
-void RegsArm::set_sp(uint64_t sp) {
- regs_[ARM_REG_SP] = sp;
-}
-
-bool RegsArm::SetPcFromReturnAddress(Memory*) {
- uint32_t lr = regs_[ARM_REG_LR];
- if (regs_[ARM_REG_PC] == lr) {
- return false;
- }
-
- regs_[ARM_REG_PC] = lr;
- return true;
-}
-
-void RegsArm::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("r0", regs_[ARM_REG_R0]);
- fn("r1", regs_[ARM_REG_R1]);
- fn("r2", regs_[ARM_REG_R2]);
- fn("r3", regs_[ARM_REG_R3]);
- fn("r4", regs_[ARM_REG_R4]);
- fn("r5", regs_[ARM_REG_R5]);
- fn("r6", regs_[ARM_REG_R6]);
- fn("r7", regs_[ARM_REG_R7]);
- fn("r8", regs_[ARM_REG_R8]);
- fn("r9", regs_[ARM_REG_R9]);
- fn("r10", regs_[ARM_REG_R10]);
- fn("r11", regs_[ARM_REG_R11]);
- fn("ip", regs_[ARM_REG_R12]);
- fn("sp", regs_[ARM_REG_SP]);
- fn("lr", regs_[ARM_REG_LR]);
- fn("pc", regs_[ARM_REG_PC]);
-}
-
-Regs* RegsArm::Read(void* remote_data) {
- arm_user_regs* user = reinterpret_cast<arm_user_regs*>(remote_data);
-
- RegsArm* regs = new RegsArm();
- memcpy(regs->RawData(), &user->regs[0], ARM_REG_LAST * sizeof(uint32_t));
- return regs;
-}
-
-Regs* RegsArm::CreateFromUcontext(void* ucontext) {
- arm_ucontext_t* arm_ucontext = reinterpret_cast<arm_ucontext_t*>(ucontext);
-
- RegsArm* regs = new RegsArm();
- memcpy(regs->RawData(), &arm_ucontext->uc_mcontext.regs[0], ARM_REG_LAST * sizeof(uint32_t));
- return regs;
-}
-
-bool RegsArm::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
- uint32_t data;
- Memory* elf_memory = elf->memory();
- // Read from elf memory since it is usually more expensive to read from
- // process memory.
- if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
- return false;
- }
-
- uint64_t offset = 0;
- if (data == 0xe3a07077 || data == 0xef900077 || data == 0xdf002777) {
- uint64_t sp = regs_[ARM_REG_SP];
- // non-RT sigreturn call.
- // __restore:
- //
- // Form 1 (arm):
- // 0x77 0x70 mov r7, #0x77
- // 0xa0 0xe3 svc 0x00000000
- //
- // Form 2 (arm):
- // 0x77 0x00 0x90 0xef svc 0x00900077
- //
- // Form 3 (thumb):
- // 0x77 0x27 movs r7, #77
- // 0x00 0xdf svc 0
- if (!process_memory->ReadFully(sp, &data, sizeof(data))) {
- return false;
- }
- if (data == 0x5ac3c35a) {
- // SP + uc_mcontext offset + r0 offset.
- offset = sp + 0x14 + 0xc;
- } else {
- // SP + r0 offset
- offset = sp + 0xc;
- }
- } else if (data == 0xe3a070ad || data == 0xef9000ad || data == 0xdf0027ad) {
- uint64_t sp = regs_[ARM_REG_SP];
- // RT sigreturn call.
- // __restore_rt:
- //
- // Form 1 (arm):
- // 0xad 0x70 mov r7, #0xad
- // 0xa0 0xe3 svc 0x00000000
- //
- // Form 2 (arm):
- // 0xad 0x00 0x90 0xef svc 0x009000ad
- //
- // Form 3 (thumb):
- // 0xad 0x27 movs r7, #ad
- // 0x00 0xdf svc 0
- if (!process_memory->ReadFully(sp, &data, sizeof(data))) {
- return false;
- }
- if (data == sp + 8) {
- // SP + 8 + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
- offset = sp + 8 + 0x80 + 0x14 + 0xc;
- } else {
- // SP + sizeof(siginfo_t) + uc_mcontext_offset + r0 offset
- offset = sp + 0x80 + 0x14 + 0xc;
- }
- }
- if (offset == 0) {
- return false;
- }
-
- if (!process_memory->ReadFully(offset, regs_.data(), sizeof(uint32_t) * ARM_REG_LAST)) {
- return false;
- }
- return true;
-}
-
-Regs* RegsArm::Clone() {
- return new RegsArm(*this);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
deleted file mode 100644
index b496187..0000000
--- a/libunwindstack/RegsArm64.cpp
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <string.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineArm64.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/UcontextArm64.h>
-#include <unwindstack/UserArm64.h>
-
-namespace unwindstack {
-
-RegsArm64::RegsArm64()
- : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {
- ResetPseudoRegisters();
- pac_mask_ = 0;
-}
-
-ArchEnum RegsArm64::Arch() {
- return ARCH_ARM64;
-}
-
-uint64_t RegsArm64::pc() {
- return regs_[ARM64_REG_PC];
-}
-
-uint64_t RegsArm64::sp() {
- return regs_[ARM64_REG_SP];
-}
-
-void RegsArm64::set_pc(uint64_t pc) {
- // If the target is aarch64 then the return address may have been
- // signed using the Armv8.3-A Pointer Authentication extension. The
- // original return address can be restored by stripping out the
- // authentication code using a mask or xpaclri. xpaclri is a NOP on
- // pre-Armv8.3-A architectures.
- if ((0 != pc) && IsRASigned()) {
- if (pac_mask_) {
- pc &= ~pac_mask_;
-#if defined(__aarch64__)
- } else {
- register uint64_t x30 __asm("x30") = pc;
- // This is XPACLRI.
- asm("hint 0x7" : "+r"(x30));
- pc = x30;
-#endif
- }
- }
- regs_[ARM64_REG_PC] = pc;
-}
-
-void RegsArm64::set_sp(uint64_t sp) {
- regs_[ARM64_REG_SP] = sp;
-}
-
-bool RegsArm64::SetPcFromReturnAddress(Memory*) {
- uint64_t lr = regs_[ARM64_REG_LR];
- if (regs_[ARM64_REG_PC] == lr) {
- return false;
- }
-
- regs_[ARM64_REG_PC] = lr;
- return true;
-}
-
-void RegsArm64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("x0", regs_[ARM64_REG_R0]);
- fn("x1", regs_[ARM64_REG_R1]);
- fn("x2", regs_[ARM64_REG_R2]);
- fn("x3", regs_[ARM64_REG_R3]);
- fn("x4", regs_[ARM64_REG_R4]);
- fn("x5", regs_[ARM64_REG_R5]);
- fn("x6", regs_[ARM64_REG_R6]);
- fn("x7", regs_[ARM64_REG_R7]);
- fn("x8", regs_[ARM64_REG_R8]);
- fn("x9", regs_[ARM64_REG_R9]);
- fn("x10", regs_[ARM64_REG_R10]);
- fn("x11", regs_[ARM64_REG_R11]);
- fn("x12", regs_[ARM64_REG_R12]);
- fn("x13", regs_[ARM64_REG_R13]);
- fn("x14", regs_[ARM64_REG_R14]);
- fn("x15", regs_[ARM64_REG_R15]);
- fn("x16", regs_[ARM64_REG_R16]);
- fn("x17", regs_[ARM64_REG_R17]);
- fn("x18", regs_[ARM64_REG_R18]);
- fn("x19", regs_[ARM64_REG_R19]);
- fn("x20", regs_[ARM64_REG_R20]);
- fn("x21", regs_[ARM64_REG_R21]);
- fn("x22", regs_[ARM64_REG_R22]);
- fn("x23", regs_[ARM64_REG_R23]);
- fn("x24", regs_[ARM64_REG_R24]);
- fn("x25", regs_[ARM64_REG_R25]);
- fn("x26", regs_[ARM64_REG_R26]);
- fn("x27", regs_[ARM64_REG_R27]);
- fn("x28", regs_[ARM64_REG_R28]);
- fn("x29", regs_[ARM64_REG_R29]);
- fn("lr", regs_[ARM64_REG_LR]);
- fn("sp", regs_[ARM64_REG_SP]);
- fn("pc", regs_[ARM64_REG_PC]);
- fn("pst", regs_[ARM64_REG_PSTATE]);
-}
-
-Regs* RegsArm64::Read(void* remote_data) {
- arm64_user_regs* user = reinterpret_cast<arm64_user_regs*>(remote_data);
-
- RegsArm64* regs = new RegsArm64();
- memcpy(regs->RawData(), &user->regs[0], (ARM64_REG_R30 + 1) * sizeof(uint64_t));
- uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
- reg_data[ARM64_REG_SP] = user->sp;
- reg_data[ARM64_REG_PC] = user->pc;
- reg_data[ARM64_REG_PSTATE] = user->pstate;
- return regs;
-}
-
-Regs* RegsArm64::CreateFromUcontext(void* ucontext) {
- arm64_ucontext_t* arm64_ucontext = reinterpret_cast<arm64_ucontext_t*>(ucontext);
-
- RegsArm64* regs = new RegsArm64();
- memcpy(regs->RawData(), &arm64_ucontext->uc_mcontext.regs[0], ARM64_REG_LAST * sizeof(uint64_t));
- return regs;
-}
-
-bool RegsArm64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
- uint64_t data;
- Memory* elf_memory = elf->memory();
- // Read from elf memory since it is usually more expensive to read from
- // process memory.
- if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
- return false;
- }
-
- // Look for the kernel sigreturn function.
- // __kernel_rt_sigreturn:
- // 0xd2801168 mov x8, #0x8b
- // 0xd4000001 svc #0x0
- if (data != 0xd4000001d2801168ULL) {
- return false;
- }
-
- // SP + sizeof(siginfo_t) + uc_mcontext offset + X0 offset.
- if (!process_memory->ReadFully(regs_[ARM64_REG_SP] + 0x80 + 0xb0 + 0x08, regs_.data(),
- sizeof(uint64_t) * ARM64_REG_LAST)) {
- return false;
- }
- return true;
-}
-
-void RegsArm64::ResetPseudoRegisters(void) {
- // DWARF for AArch64 says RA_SIGN_STATE should be initialized to 0.
- this->SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 0);
-}
-
-bool RegsArm64::SetPseudoRegister(uint16_t id, uint64_t value) {
- if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) {
- pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST] = value;
- return true;
- }
- return false;
-}
-
-bool RegsArm64::GetPseudoRegister(uint16_t id, uint64_t* value) {
- if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) {
- *value = pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST];
- return true;
- }
- return false;
-}
-
-bool RegsArm64::IsRASigned() {
- uint64_t value;
- auto result = this->GetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, &value);
- return (result && (value != 0));
-}
-
-void RegsArm64::SetPACMask(uint64_t mask) {
- pac_mask_ = mask;
-}
-
-Regs* RegsArm64::Clone() {
- return new RegsArm64(*this);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/RegsInfo.h b/libunwindstack/RegsInfo.h
deleted file mode 100644
index e445a91..0000000
--- a/libunwindstack/RegsInfo.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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_REGS_INFO_H
-#define _LIBUNWINDSTACK_REGS_INFO_H
-
-#include <stdint.h>
-
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-template <typename AddressType>
-struct RegsInfo {
- static constexpr size_t MAX_REGISTERS = 64;
-
- RegsInfo(RegsImpl<AddressType>* regs) : regs(regs) {}
-
- RegsImpl<AddressType>* regs = nullptr;
- uint64_t saved_reg_map = 0;
- AddressType saved_regs[MAX_REGISTERS];
-
- inline AddressType Get(uint32_t reg) {
- if (IsSaved(reg)) {
- return saved_regs[reg];
- }
- return (*regs)[reg];
- }
-
- inline AddressType* Save(uint32_t reg) {
- if (reg >= MAX_REGISTERS) {
- // This should never happen since all currently supported
- // architectures have < 64 total registers.
- abort();
- }
- saved_reg_map |= 1ULL << reg;
- saved_regs[reg] = (*regs)[reg];
- return &(*regs)[reg];
- }
-
- inline bool IsSaved(uint32_t reg) {
- if (reg > MAX_REGISTERS) {
- // This should never happen since all currently supported
- // architectures have < 64 total registers.
- abort();
- }
- return saved_reg_map & (1ULL << reg);
- }
-
- inline uint16_t Total() { return regs->total_regs(); }
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_INFO_H
diff --git a/libunwindstack/RegsMips.cpp b/libunwindstack/RegsMips.cpp
deleted file mode 100644
index ab84691..0000000
--- a/libunwindstack/RegsMips.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2017 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 <string.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineMips.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsMips.h>
-#include <unwindstack/UcontextMips.h>
-#include <unwindstack/UserMips.h>
-
-namespace unwindstack {
-
-RegsMips::RegsMips()
- : RegsImpl<uint32_t>(MIPS_REG_LAST, Location(LOCATION_REGISTER, MIPS_REG_RA)) {}
-
-ArchEnum RegsMips::Arch() {
- return ARCH_MIPS;
-}
-
-uint64_t RegsMips::pc() {
- return regs_[MIPS_REG_PC];
-}
-
-uint64_t RegsMips::sp() {
- return regs_[MIPS_REG_SP];
-}
-
-void RegsMips::set_pc(uint64_t pc) {
- regs_[MIPS_REG_PC] = static_cast<uint32_t>(pc);
-}
-
-void RegsMips::set_sp(uint64_t sp) {
- regs_[MIPS_REG_SP] = static_cast<uint32_t>(sp);
-}
-
-bool RegsMips::SetPcFromReturnAddress(Memory*) {
- uint32_t ra = regs_[MIPS_REG_RA];
- if (regs_[MIPS_REG_PC] == ra) {
- return false;
- }
-
- regs_[MIPS_REG_PC] = ra;
- return true;
-}
-
-void RegsMips::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("r0", regs_[MIPS_REG_R0]);
- fn("r1", regs_[MIPS_REG_R1]);
- fn("r2", regs_[MIPS_REG_R2]);
- fn("r3", regs_[MIPS_REG_R3]);
- fn("r4", regs_[MIPS_REG_R4]);
- fn("r5", regs_[MIPS_REG_R5]);
- fn("r6", regs_[MIPS_REG_R6]);
- fn("r7", regs_[MIPS_REG_R7]);
- fn("r8", regs_[MIPS_REG_R8]);
- fn("r9", regs_[MIPS_REG_R9]);
- fn("r10", regs_[MIPS_REG_R10]);
- fn("r11", regs_[MIPS_REG_R11]);
- fn("r12", regs_[MIPS_REG_R12]);
- fn("r13", regs_[MIPS_REG_R13]);
- fn("r14", regs_[MIPS_REG_R14]);
- fn("r15", regs_[MIPS_REG_R15]);
- fn("r16", regs_[MIPS_REG_R16]);
- fn("r17", regs_[MIPS_REG_R17]);
- fn("r18", regs_[MIPS_REG_R18]);
- fn("r19", regs_[MIPS_REG_R19]);
- fn("r20", regs_[MIPS_REG_R20]);
- fn("r21", regs_[MIPS_REG_R21]);
- fn("r22", regs_[MIPS_REG_R22]);
- fn("r23", regs_[MIPS_REG_R23]);
- fn("r24", regs_[MIPS_REG_R24]);
- fn("r25", regs_[MIPS_REG_R25]);
- fn("r26", regs_[MIPS_REG_R26]);
- fn("r27", regs_[MIPS_REG_R27]);
- fn("r28", regs_[MIPS_REG_R28]);
- fn("sp", regs_[MIPS_REG_SP]);
- fn("r30", regs_[MIPS_REG_R30]);
- fn("ra", regs_[MIPS_REG_RA]);
- fn("pc", regs_[MIPS_REG_PC]);
-}
-
-Regs* RegsMips::Read(void* remote_data) {
- mips_user_regs* user = reinterpret_cast<mips_user_regs*>(remote_data);
- RegsMips* regs = new RegsMips();
- uint32_t* reg_data = reinterpret_cast<uint32_t*>(regs->RawData());
-
- memcpy(regs->RawData(), &user->regs[MIPS32_EF_R0], (MIPS_REG_R31 + 1) * sizeof(uint32_t));
-
- reg_data[MIPS_REG_PC] = user->regs[MIPS32_EF_CP0_EPC];
- return regs;
-}
-
-Regs* RegsMips::CreateFromUcontext(void* ucontext) {
- mips_ucontext_t* mips_ucontext = reinterpret_cast<mips_ucontext_t*>(ucontext);
-
- RegsMips* regs = new RegsMips();
- // Copy 64 bit sc_regs over to 32 bit regs
- for (int i = 0; i < 32; i++) {
- (*regs)[MIPS_REG_R0 + i] = mips_ucontext->uc_mcontext.sc_regs[i];
- }
- (*regs)[MIPS_REG_PC] = mips_ucontext->uc_mcontext.sc_pc;
- return regs;
-}
-
-bool RegsMips::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
- uint64_t data;
- uint64_t offset = 0;
- Memory* elf_memory = elf->memory();
- // Read from elf memory since it is usually more expensive to read from
- // process memory.
- if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
- return false;
- }
-
- // Look for the kernel sigreturn functions.
- // __vdso_rt_sigreturn:
- // 0x24021061 li v0, 0x1061
- // 0x0000000c syscall
- // __vdso_sigreturn:
- // 0x24021017 li v0, 0x1017
- // 0x0000000c syscall
- if (data == 0x0000000c24021061ULL) {
- // vdso_rt_sigreturn => read rt_sigframe
- // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset + sc_pc offset
- offset = 24 + 128 + 24 + 8;
- } else if (data == 0x0000000c24021017LL) {
- // vdso_sigreturn => read sigframe
- // offset = sigcontext offset + sc_pc offset
- offset = 24 + 8;
- } else {
- return false;
- }
-
- // read sc_pc and sc_regs[32] from stack
- uint64_t values[MIPS_REG_LAST];
- if (!process_memory->ReadFully(regs_[MIPS_REG_SP] + offset, values, sizeof(values))) {
- return false;
- }
-
- // Copy 64 bit sc_pc over to 32 bit regs_[MIPS_REG_PC]
- regs_[MIPS_REG_PC] = values[0];
-
- // Copy 64 bit sc_regs over to 32 bit regs
- for (int i = 0; i < 32; i++) {
- regs_[MIPS_REG_R0 + i] = values[1 + i];
- }
- return true;
-}
-
-Regs* RegsMips::Clone() {
- return new RegsMips(*this);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
deleted file mode 100644
index 7f600d3..0000000
--- a/libunwindstack/RegsMips64.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2017 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 <string.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineMips64.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsMips64.h>
-#include <unwindstack/UcontextMips64.h>
-#include <unwindstack/UserMips64.h>
-
-namespace unwindstack {
-
-RegsMips64::RegsMips64()
- : RegsImpl<uint64_t>(MIPS64_REG_LAST, Location(LOCATION_REGISTER, MIPS64_REG_RA)) {}
-
-ArchEnum RegsMips64::Arch() {
- return ARCH_MIPS64;
-}
-
-uint64_t RegsMips64::pc() {
- return regs_[MIPS64_REG_PC];
-}
-
-uint64_t RegsMips64::sp() {
- return regs_[MIPS64_REG_SP];
-}
-
-void RegsMips64::set_pc(uint64_t pc) {
- regs_[MIPS64_REG_PC] = pc;
-}
-
-void RegsMips64::set_sp(uint64_t sp) {
- regs_[MIPS64_REG_SP] = sp;
-}
-
-bool RegsMips64::SetPcFromReturnAddress(Memory*) {
- uint64_t ra = regs_[MIPS64_REG_RA];
- if (regs_[MIPS64_REG_PC] == ra) {
- return false;
- }
-
- regs_[MIPS64_REG_PC] = ra;
- return true;
-}
-
-void RegsMips64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("r0", regs_[MIPS64_REG_R0]);
- fn("r1", regs_[MIPS64_REG_R1]);
- fn("r2", regs_[MIPS64_REG_R2]);
- fn("r3", regs_[MIPS64_REG_R3]);
- fn("r4", regs_[MIPS64_REG_R4]);
- fn("r5", regs_[MIPS64_REG_R5]);
- fn("r6", regs_[MIPS64_REG_R6]);
- fn("r7", regs_[MIPS64_REG_R7]);
- fn("r8", regs_[MIPS64_REG_R8]);
- fn("r9", regs_[MIPS64_REG_R9]);
- fn("r10", regs_[MIPS64_REG_R10]);
- fn("r11", regs_[MIPS64_REG_R11]);
- fn("r12", regs_[MIPS64_REG_R12]);
- fn("r13", regs_[MIPS64_REG_R13]);
- fn("r14", regs_[MIPS64_REG_R14]);
- fn("r15", regs_[MIPS64_REG_R15]);
- fn("r16", regs_[MIPS64_REG_R16]);
- fn("r17", regs_[MIPS64_REG_R17]);
- fn("r18", regs_[MIPS64_REG_R18]);
- fn("r19", regs_[MIPS64_REG_R19]);
- fn("r20", regs_[MIPS64_REG_R20]);
- fn("r21", regs_[MIPS64_REG_R21]);
- fn("r22", regs_[MIPS64_REG_R22]);
- fn("r23", regs_[MIPS64_REG_R23]);
- fn("r24", regs_[MIPS64_REG_R24]);
- fn("r25", regs_[MIPS64_REG_R25]);
- fn("r26", regs_[MIPS64_REG_R26]);
- fn("r27", regs_[MIPS64_REG_R27]);
- fn("r28", regs_[MIPS64_REG_R28]);
- fn("sp", regs_[MIPS64_REG_SP]);
- fn("r30", regs_[MIPS64_REG_R30]);
- fn("ra", regs_[MIPS64_REG_RA]);
- fn("pc", regs_[MIPS64_REG_PC]);
-}
-
-Regs* RegsMips64::Read(void* remote_data) {
- mips64_user_regs* user = reinterpret_cast<mips64_user_regs*>(remote_data);
- RegsMips64* regs = new RegsMips64();
- uint64_t* reg_data = reinterpret_cast<uint64_t*>(regs->RawData());
-
- memcpy(regs->RawData(), &user->regs[MIPS64_EF_R0], (MIPS64_REG_R31 + 1) * sizeof(uint64_t));
-
- reg_data[MIPS64_REG_PC] = user->regs[MIPS64_EF_CP0_EPC];
- return regs;
-}
-
-Regs* RegsMips64::CreateFromUcontext(void* ucontext) {
- mips64_ucontext_t* mips64_ucontext = reinterpret_cast<mips64_ucontext_t*>(ucontext);
-
- RegsMips64* regs = new RegsMips64();
- // Copy 64 bit sc_regs over to 64 bit regs
- memcpy(regs->RawData(), &mips64_ucontext->uc_mcontext.sc_regs[0], 32 * sizeof(uint64_t));
- (*regs)[MIPS64_REG_PC] = mips64_ucontext->uc_mcontext.sc_pc;
- return regs;
-}
-
-bool RegsMips64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
- uint64_t data;
- Memory* elf_memory = elf->memory();
- // Read from elf memory since it is usually more expensive to read from
- // process memory.
- if (!elf_memory->Read(elf_offset, &data, sizeof(data))) {
- return false;
- }
-
- // Look for the kernel sigreturn function.
- // __vdso_rt_sigreturn:
- // 0x2402145b li v0, 0x145b
- // 0x0000000c syscall
- if (data != 0x0000000c2402145bULL) {
- return false;
- }
-
- // vdso_rt_sigreturn => read rt_sigframe
- // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset
- // read 64 bit sc_regs[32] from stack into 64 bit regs_
- uint64_t sp = regs_[MIPS64_REG_SP];
- if (!process_memory->Read(sp + 24 + 128 + 40, regs_.data(),
- sizeof(uint64_t) * (MIPS64_REG_LAST - 1))) {
- return false;
- }
-
- // offset = siginfo offset + sizeof(siginfo) + uc_mcontext offset + sc_pc offset
- // read 64 bit sc_pc from stack into 64 bit regs_[MIPS64_REG_PC]
- if (!process_memory->Read(sp + 24 + 128 + 40 + 576, ®s_[MIPS64_REG_PC], sizeof(uint64_t))) {
- return false;
- }
- return true;
-}
-
-Regs* RegsMips64::Clone() {
- return new RegsMips64(*this);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
deleted file mode 100644
index 4d3c246..0000000
--- a/libunwindstack/RegsX86.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineX86.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/UcontextX86.h>
-#include <unwindstack/UserX86.h>
-
-namespace unwindstack {
-
-RegsX86::RegsX86() : RegsImpl<uint32_t>(X86_REG_LAST, Location(LOCATION_SP_OFFSET, -4)) {}
-
-ArchEnum RegsX86::Arch() {
- return ARCH_X86;
-}
-
-uint64_t RegsX86::pc() {
- return regs_[X86_REG_PC];
-}
-
-uint64_t RegsX86::sp() {
- return regs_[X86_REG_SP];
-}
-
-void RegsX86::set_pc(uint64_t pc) {
- regs_[X86_REG_PC] = static_cast<uint32_t>(pc);
-}
-
-void RegsX86::set_sp(uint64_t sp) {
- regs_[X86_REG_SP] = static_cast<uint32_t>(sp);
-}
-
-bool RegsX86::SetPcFromReturnAddress(Memory* process_memory) {
- // Attempt to get the return address from the top of the stack.
- uint32_t new_pc;
- if (!process_memory->ReadFully(regs_[X86_REG_SP], &new_pc, sizeof(new_pc)) ||
- new_pc == regs_[X86_REG_PC]) {
- return false;
- }
-
- regs_[X86_REG_PC] = new_pc;
- return true;
-}
-
-void RegsX86::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("eax", regs_[X86_REG_EAX]);
- fn("ebx", regs_[X86_REG_EBX]);
- fn("ecx", regs_[X86_REG_ECX]);
- fn("edx", regs_[X86_REG_EDX]);
- fn("ebp", regs_[X86_REG_EBP]);
- fn("edi", regs_[X86_REG_EDI]);
- fn("esi", regs_[X86_REG_ESI]);
- fn("esp", regs_[X86_REG_ESP]);
- fn("eip", regs_[X86_REG_EIP]);
-}
-
-Regs* RegsX86::Read(void* user_data) {
- x86_user_regs* user = reinterpret_cast<x86_user_regs*>(user_data);
-
- RegsX86* regs = new RegsX86();
- (*regs)[X86_REG_EAX] = user->eax;
- (*regs)[X86_REG_EBX] = user->ebx;
- (*regs)[X86_REG_ECX] = user->ecx;
- (*regs)[X86_REG_EDX] = user->edx;
- (*regs)[X86_REG_EBP] = user->ebp;
- (*regs)[X86_REG_EDI] = user->edi;
- (*regs)[X86_REG_ESI] = user->esi;
- (*regs)[X86_REG_ESP] = user->esp;
- (*regs)[X86_REG_EIP] = user->eip;
-
- return regs;
-}
-
-void RegsX86::SetFromUcontext(x86_ucontext_t* ucontext) {
- // Put the registers in the expected order.
- regs_[X86_REG_EDI] = ucontext->uc_mcontext.edi;
- regs_[X86_REG_ESI] = ucontext->uc_mcontext.esi;
- regs_[X86_REG_EBP] = ucontext->uc_mcontext.ebp;
- regs_[X86_REG_ESP] = ucontext->uc_mcontext.esp;
- regs_[X86_REG_EBX] = ucontext->uc_mcontext.ebx;
- regs_[X86_REG_EDX] = ucontext->uc_mcontext.edx;
- regs_[X86_REG_ECX] = ucontext->uc_mcontext.ecx;
- regs_[X86_REG_EAX] = ucontext->uc_mcontext.eax;
- regs_[X86_REG_EIP] = ucontext->uc_mcontext.eip;
-}
-
-Regs* RegsX86::CreateFromUcontext(void* ucontext) {
- x86_ucontext_t* x86_ucontext = reinterpret_cast<x86_ucontext_t*>(ucontext);
-
- RegsX86* regs = new RegsX86();
- regs->SetFromUcontext(x86_ucontext);
- return regs;
-}
-
-bool RegsX86::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
- uint64_t data;
- Memory* elf_memory = elf->memory();
- // Read from elf memory since it is usually more expensive to read from
- // process memory.
- if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data))) {
- return false;
- }
-
- if (data == 0x80cd00000077b858ULL) {
- // Without SA_SIGINFO set, the return sequence is:
- //
- // __restore:
- // 0x58 pop %eax
- // 0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
- // 0xcd 0x80 int 0x80
- //
- // SP points at arguments:
- // int signum
- // struct sigcontext (same format as mcontext)
- struct x86_mcontext_t context;
- if (!process_memory->ReadFully(regs_[X86_REG_SP] + 4, &context, sizeof(context))) {
- return false;
- }
- regs_[X86_REG_EBP] = context.ebp;
- regs_[X86_REG_ESP] = context.esp;
- regs_[X86_REG_EBX] = context.ebx;
- regs_[X86_REG_EDX] = context.edx;
- regs_[X86_REG_ECX] = context.ecx;
- regs_[X86_REG_EAX] = context.eax;
- regs_[X86_REG_EIP] = context.eip;
- return true;
- } else if ((data & 0x00ffffffffffffffULL) == 0x0080cd000000adb8ULL) {
- // With SA_SIGINFO set, the return sequence is:
- //
- // __restore_rt:
- // 0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
- // 0xcd 0x80 int 0x80
- //
- // SP points at arguments:
- // int signum
- // siginfo*
- // ucontext*
-
- // Get the location of the sigcontext data.
- uint32_t ptr;
- if (!process_memory->ReadFully(regs_[X86_REG_SP] + 8, &ptr, sizeof(ptr))) {
- return false;
- }
- // Only read the portion of the data structure we care about.
- x86_ucontext_t x86_ucontext;
- if (!process_memory->ReadFully(ptr + 0x14, &x86_ucontext.uc_mcontext, sizeof(x86_mcontext_t))) {
- return false;
- }
- SetFromUcontext(&x86_ucontext);
- return true;
- }
- return false;
-}
-
-Regs* RegsX86::Clone() {
- return new RegsX86(*this);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
deleted file mode 100644
index c9e245d..0000000
--- a/libunwindstack/RegsX86_64.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <string.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineX86_64.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/RegsX86_64.h>
-#include <unwindstack/UcontextX86_64.h>
-#include <unwindstack/UserX86_64.h>
-
-namespace unwindstack {
-
-RegsX86_64::RegsX86_64() : RegsImpl<uint64_t>(X86_64_REG_LAST, Location(LOCATION_SP_OFFSET, -8)) {}
-
-ArchEnum RegsX86_64::Arch() {
- return ARCH_X86_64;
-}
-
-uint64_t RegsX86_64::pc() {
- return regs_[X86_64_REG_PC];
-}
-
-uint64_t RegsX86_64::sp() {
- return regs_[X86_64_REG_SP];
-}
-
-void RegsX86_64::set_pc(uint64_t pc) {
- regs_[X86_64_REG_PC] = pc;
-}
-
-void RegsX86_64::set_sp(uint64_t sp) {
- regs_[X86_64_REG_SP] = sp;
-}
-
-bool RegsX86_64::SetPcFromReturnAddress(Memory* process_memory) {
- // Attempt to get the return address from the top of the stack.
- uint64_t new_pc;
- if (!process_memory->ReadFully(regs_[X86_64_REG_SP], &new_pc, sizeof(new_pc)) ||
- new_pc == regs_[X86_64_REG_PC]) {
- return false;
- }
-
- regs_[X86_64_REG_PC] = new_pc;
- return true;
-}
-
-void RegsX86_64::IterateRegisters(std::function<void(const char*, uint64_t)> fn) {
- fn("rax", regs_[X86_64_REG_RAX]);
- fn("rbx", regs_[X86_64_REG_RBX]);
- fn("rcx", regs_[X86_64_REG_RCX]);
- fn("rdx", regs_[X86_64_REG_RDX]);
- fn("r8", regs_[X86_64_REG_R8]);
- fn("r9", regs_[X86_64_REG_R9]);
- fn("r10", regs_[X86_64_REG_R10]);
- fn("r11", regs_[X86_64_REG_R11]);
- fn("r12", regs_[X86_64_REG_R12]);
- fn("r13", regs_[X86_64_REG_R13]);
- fn("r14", regs_[X86_64_REG_R14]);
- fn("r15", regs_[X86_64_REG_R15]);
- fn("rdi", regs_[X86_64_REG_RDI]);
- fn("rsi", regs_[X86_64_REG_RSI]);
- fn("rbp", regs_[X86_64_REG_RBP]);
- fn("rsp", regs_[X86_64_REG_RSP]);
- fn("rip", regs_[X86_64_REG_RIP]);
-}
-
-Regs* RegsX86_64::Read(void* remote_data) {
- x86_64_user_regs* user = reinterpret_cast<x86_64_user_regs*>(remote_data);
-
- RegsX86_64* regs = new RegsX86_64();
- (*regs)[X86_64_REG_RAX] = user->rax;
- (*regs)[X86_64_REG_RBX] = user->rbx;
- (*regs)[X86_64_REG_RCX] = user->rcx;
- (*regs)[X86_64_REG_RDX] = user->rdx;
- (*regs)[X86_64_REG_R8] = user->r8;
- (*regs)[X86_64_REG_R9] = user->r9;
- (*regs)[X86_64_REG_R10] = user->r10;
- (*regs)[X86_64_REG_R11] = user->r11;
- (*regs)[X86_64_REG_R12] = user->r12;
- (*regs)[X86_64_REG_R13] = user->r13;
- (*regs)[X86_64_REG_R14] = user->r14;
- (*regs)[X86_64_REG_R15] = user->r15;
- (*regs)[X86_64_REG_RDI] = user->rdi;
- (*regs)[X86_64_REG_RSI] = user->rsi;
- (*regs)[X86_64_REG_RBP] = user->rbp;
- (*regs)[X86_64_REG_RSP] = user->rsp;
- (*regs)[X86_64_REG_RIP] = user->rip;
-
- return regs;
-}
-
-void RegsX86_64::SetFromUcontext(x86_64_ucontext_t* ucontext) {
- // R8-R15
- memcpy(®s_[X86_64_REG_R8], &ucontext->uc_mcontext.r8, 8 * sizeof(uint64_t));
-
- // Rest of the registers.
- regs_[X86_64_REG_RDI] = ucontext->uc_mcontext.rdi;
- regs_[X86_64_REG_RSI] = ucontext->uc_mcontext.rsi;
- regs_[X86_64_REG_RBP] = ucontext->uc_mcontext.rbp;
- regs_[X86_64_REG_RBX] = ucontext->uc_mcontext.rbx;
- regs_[X86_64_REG_RDX] = ucontext->uc_mcontext.rdx;
- regs_[X86_64_REG_RAX] = ucontext->uc_mcontext.rax;
- regs_[X86_64_REG_RCX] = ucontext->uc_mcontext.rcx;
- regs_[X86_64_REG_RSP] = ucontext->uc_mcontext.rsp;
- regs_[X86_64_REG_RIP] = ucontext->uc_mcontext.rip;
-}
-
-Regs* RegsX86_64::CreateFromUcontext(void* ucontext) {
- x86_64_ucontext_t* x86_64_ucontext = reinterpret_cast<x86_64_ucontext_t*>(ucontext);
-
- RegsX86_64* regs = new RegsX86_64();
- regs->SetFromUcontext(x86_64_ucontext);
- return regs;
-}
-
-bool RegsX86_64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) {
- uint64_t data;
- Memory* elf_memory = elf->memory();
- // Read from elf memory since it is usually more expensive to read from
- // process memory.
- if (!elf_memory->ReadFully(elf_offset, &data, sizeof(data)) || data != 0x0f0000000fc0c748) {
- return false;
- }
-
- uint16_t data2;
- if (!elf_memory->ReadFully(elf_offset + 8, &data2, sizeof(data2)) || data2 != 0x0f05) {
- return false;
- }
-
- // __restore_rt:
- // 0x48 0xc7 0xc0 0x0f 0x00 0x00 0x00 mov $0xf,%rax
- // 0x0f 0x05 syscall
- // 0x0f nopl 0x0($rax)
-
- // Read the mcontext data from the stack.
- // sp points to the ucontext data structure, read only the mcontext part.
- x86_64_ucontext_t x86_64_ucontext;
- if (!process_memory->ReadFully(regs_[X86_64_REG_SP] + 0x28, &x86_64_ucontext.uc_mcontext,
- sizeof(x86_64_mcontext_t))) {
- return false;
- }
- SetFromUcontext(&x86_64_ucontext);
- return true;
-}
-
-Regs* RegsX86_64::Clone() {
- return new RegsX86_64(*this);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/Symbols.cpp b/libunwindstack/Symbols.cpp
deleted file mode 100644
index 2117ebd..0000000
--- a/libunwindstack/Symbols.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2017 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 <elf.h>
-#include <stdint.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Memory.h>
-
-#include "Check.h"
-#include "Symbols.h"
-
-namespace unwindstack {
-
-Symbols::Symbols(uint64_t offset, uint64_t size, uint64_t entry_size, uint64_t str_offset,
- uint64_t str_size)
- : offset_(offset),
- count_(entry_size != 0 ? size / entry_size : 0),
- entry_size_(entry_size),
- str_offset_(str_offset),
- str_end_(str_offset_ + str_size) {}
-
-template <typename SymType>
-static bool IsFunc(const SymType* entry) {
- return entry->st_shndx != SHN_UNDEF && ELF32_ST_TYPE(entry->st_info) == STT_FUNC;
-}
-
-// Read symbol entry from memory and cache it so we don't have to read it again.
-template <typename SymType>
-inline __attribute__((__always_inline__)) const Symbols::Info* Symbols::ReadFuncInfo(
- uint32_t symbol_index, Memory* elf_memory) {
- auto it = symbols_.find(symbol_index);
- if (it != symbols_.end()) {
- return &it->second;
- }
- SymType sym;
- if (!elf_memory->ReadFully(offset_ + symbol_index * entry_size_, &sym, sizeof(sym))) {
- return nullptr;
- }
- if (!IsFunc(&sym)) {
- // We need the address for binary search, but we don't want it to be matched.
- sym.st_size = 0;
- }
- Info info{.addr = sym.st_value, .size = static_cast<uint32_t>(sym.st_size), .name = sym.st_name};
- return &symbols_.emplace(symbol_index, info).first->second;
-}
-
-// Binary search the symbol table to find function containing the given address.
-// Without remap, the symbol table is assumed to be sorted and accessed directly.
-// If the symbol table is not sorted this method might fail but should not crash.
-// When the indices are remapped, they are guaranteed to be sorted by address.
-template <typename SymType, bool RemapIndices>
-const Symbols::Info* Symbols::BinarySearch(uint64_t addr, Memory* elf_memory) {
- size_t first = 0;
- size_t last = RemapIndices ? remap_->size() : count_;
- while (first < last) {
- size_t current = first + (last - first) / 2;
- size_t symbol_index = RemapIndices ? remap_.value()[current] : current;
- const Info* info = ReadFuncInfo<SymType>(symbol_index, elf_memory);
- if (info == nullptr) {
- return nullptr;
- }
- if (addr < info->addr) {
- last = current;
- } else if (addr < info->addr + info->size) {
- return info;
- } else {
- first = current + 1;
- }
- }
- return nullptr;
-}
-
-// Create remapping table which allows us to access symbols as if they were sorted by address.
-template <typename SymType>
-void Symbols::BuildRemapTable(Memory* elf_memory) {
- std::vector<uint64_t> addrs; // Addresses of all symbols (addrs[i] == symbols[i].st_value).
- addrs.reserve(count_);
- remap_.emplace(); // Construct the optional remap table.
- remap_->reserve(count_);
- for (size_t symbol_idx = 0; symbol_idx < count_;) {
- // Read symbols from memory. We intentionally bypass the cache to save memory.
- // Do the reads in batches so that we minimize the number of memory read calls.
- uint8_t buffer[1024];
- size_t read = std::min<size_t>(sizeof(buffer), (count_ - symbol_idx) * entry_size_);
- size_t size = elf_memory->Read(offset_ + symbol_idx * entry_size_, buffer, read);
- if (size < sizeof(SymType)) {
- break; // Stop processing, something looks like it is corrupted.
- }
- for (size_t offset = 0; offset + sizeof(SymType) <= size; offset += entry_size_, symbol_idx++) {
- SymType sym;
- memcpy(&sym, &buffer[offset], sizeof(SymType)); // Copy to ensure alignment.
- addrs.push_back(sym.st_value); // Always insert so it is indexable by symbol index.
- if (IsFunc(&sym)) {
- remap_->push_back(symbol_idx); // Indices of function symbols only.
- }
- }
- }
- // Sort by address to make the remap list binary searchable (stable due to the a<b tie break).
- auto comp = [&addrs](auto a, auto b) { return std::tie(addrs[a], a) < std::tie(addrs[b], b); };
- std::sort(remap_->begin(), remap_->end(), comp);
- // Remove duplicate entries (methods de-duplicated by the linker).
- auto pred = [&addrs](auto a, auto b) { return addrs[a] == addrs[b]; };
- remap_->erase(std::unique(remap_->begin(), remap_->end(), pred), remap_->end());
- remap_->shrink_to_fit();
-}
-
-template <typename SymType>
-bool Symbols::GetName(uint64_t addr, Memory* elf_memory, std::string* name, uint64_t* func_offset) {
- const Info* info;
- if (!remap_.has_value()) {
- // Assume the symbol table is sorted. If it is not, this will gracefully fail.
- info = BinarySearch<SymType, false>(addr, elf_memory);
- if (info == nullptr) {
- // Create the remapping table and retry the search.
- BuildRemapTable<SymType>(elf_memory);
- symbols_.clear(); // Remove cached symbols since the access pattern will be different.
- info = BinarySearch<SymType, true>(addr, elf_memory);
- }
- } else {
- // Fast search using the previously created remap table.
- info = BinarySearch<SymType, true>(addr, elf_memory);
- }
- if (info == nullptr) {
- return false;
- }
- // Read the function name from the string table.
- *func_offset = addr - info->addr;
- uint64_t str = str_offset_ + info->name;
- return str < str_end_ && elf_memory->ReadString(str, name, str_end_ - str);
-}
-
-template <typename SymType>
-bool Symbols::GetGlobal(Memory* elf_memory, const std::string& name, uint64_t* memory_address) {
- for (uint32_t i = 0; i < count_; i++) {
- SymType entry;
- if (!elf_memory->ReadFully(offset_ + i * entry_size_, &entry, sizeof(entry))) {
- return false;
- }
-
- if (entry.st_shndx != SHN_UNDEF && ELF32_ST_TYPE(entry.st_info) == STT_OBJECT &&
- ELF32_ST_BIND(entry.st_info) == STB_GLOBAL) {
- uint64_t str_offset = str_offset_ + entry.st_name;
- if (str_offset < str_end_) {
- std::string symbol;
- if (elf_memory->ReadString(str_offset, &symbol, str_end_ - str_offset) && symbol == name) {
- *memory_address = entry.st_value;
- return true;
- }
- }
- }
- }
- return false;
-}
-
-// Instantiate all of the needed template functions.
-template bool Symbols::GetName<Elf32_Sym>(uint64_t, Memory*, std::string*, uint64_t*);
-template bool Symbols::GetName<Elf64_Sym>(uint64_t, Memory*, std::string*, uint64_t*);
-
-template bool Symbols::GetGlobal<Elf32_Sym>(Memory*, const std::string&, uint64_t*);
-template bool Symbols::GetGlobal<Elf64_Sym>(Memory*, const std::string&, uint64_t*);
-} // namespace unwindstack
diff --git a/libunwindstack/Symbols.h b/libunwindstack/Symbols.h
deleted file mode 100644
index 3b3f20b..0000000
--- a/libunwindstack/Symbols.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_SYMBOLS_H
-#define _LIBUNWINDSTACK_SYMBOLS_H
-
-#include <stdint.h>
-
-#include <optional>
-#include <string>
-#include <unordered_map>
-
-namespace unwindstack {
-
-// Forward declaration.
-class Memory;
-
-class Symbols {
- struct Info {
- uint64_t addr; // Symbol address.
- uint32_t size; // Symbol size in bytes. Zero if not a function.
- uint32_t name; // Offset in .strtab.
- };
-
- public:
- Symbols(uint64_t offset, uint64_t size, uint64_t entry_size, uint64_t str_offset,
- uint64_t str_size);
- virtual ~Symbols() = default;
-
- template <typename SymType>
- bool GetName(uint64_t addr, Memory* elf_memory, std::string* name, uint64_t* func_offset);
-
- template <typename SymType>
- bool GetGlobal(Memory* elf_memory, const std::string& name, uint64_t* memory_address);
-
- void ClearCache() {
- symbols_.clear();
- remap_.reset();
- }
-
- private:
- template <typename SymType>
- const Info* ReadFuncInfo(uint32_t symbol_index, Memory* elf_memory);
-
- template <typename SymType, bool RemapIndices>
- const Info* BinarySearch(uint64_t addr, Memory* elf_memory);
-
- template <typename SymType>
- void BuildRemapTable(Memory* elf_memory);
-
- const uint64_t offset_;
- const uint64_t count_;
- const uint64_t entry_size_;
- const uint64_t str_offset_;
- const uint64_t str_end_;
-
- std::unordered_map<uint32_t, Info> symbols_; // Cache of read symbols (keyed by symbol index).
- std::optional<std::vector<uint32_t>> remap_; // Indices of function symbols sorted by address.
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_SYMBOLS_H
diff --git a/libunwindstack/TEST_MAPPING b/libunwindstack/TEST_MAPPING
deleted file mode 100644
index 909f897..0000000
--- a/libunwindstack/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "presubmit": [
- {
- "name": "libunwindstack_unit_test"
- },
- {
- "name": "CtsSimpleperfTestCases"
- }
- ]
-}
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
deleted file mode 100644
index b904632..0000000
--- a/libunwindstack/Unwinder.cpp
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE 1
-#include <elf.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Unwinder.h>
-
-#include <unwindstack/DexFiles.h>
-
-// Use the demangler from libc++.
-extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
-
-namespace unwindstack {
-
-// 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.
-// Adding the dex frame first here will create something like:
-// #7 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8
-// #8 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625
-// #9 pc 0039a1ef libartd.so art::interpreter::Execute+719
-void Unwinder::FillInDexFrame() {
- size_t frame_num = frames_.size();
- frames_.resize(frame_num + 1);
- FrameData* frame = &frames_.at(frame_num);
- frame->num = frame_num;
-
- uint64_t dex_pc = regs_->dex_pc();
- frame->pc = dex_pc;
- frame->sp = regs_->sp();
-
- MapInfo* info = maps_->Find(dex_pc);
- if (info != nullptr) {
- frame->map_start = info->start;
- frame->map_end = info->end;
- // Since this is a dex file frame, the elf_start_offset is not set
- // by any of the normal code paths. Use the offset of the map since
- // that matches the actual offset.
- frame->map_elf_start_offset = info->offset;
- frame->map_exact_offset = info->offset;
- frame->map_load_bias = info->load_bias;
- frame->map_flags = info->flags;
- if (resolve_names_) {
- frame->map_name = info->name;
- }
- frame->rel_pc = dex_pc - info->start;
- } else {
- frame->rel_pc = dex_pc;
- warnings_ |= WARNING_DEX_PC_NOT_IN_MAP;
- }
-
- if (!resolve_names_) {
- return;
- }
-
-#if defined(DEXFILE_SUPPORT)
- if (dex_files_ == nullptr) {
- return;
- }
-
- dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
- &frame->function_offset);
-#endif
-}
-
-FrameData* Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc,
- uint64_t pc_adjustment) {
- size_t frame_num = frames_.size();
- frames_.resize(frame_num + 1);
- FrameData* frame = &frames_.at(frame_num);
- frame->num = frame_num;
- frame->sp = regs_->sp();
- frame->rel_pc = rel_pc - pc_adjustment;
- frame->pc = regs_->pc() - pc_adjustment;
-
- if (map_info == nullptr) {
- // Nothing else to update.
- return nullptr;
- }
-
- if (resolve_names_) {
- frame->map_name = map_info->name;
- if (embedded_soname_ && map_info->elf_start_offset != 0 && !frame->map_name.empty()) {
- std::string soname = elf->GetSoname();
- if (!soname.empty()) {
- frame->map_name += '!' + soname;
- }
- }
- }
- frame->map_elf_start_offset = map_info->elf_start_offset;
- frame->map_exact_offset = map_info->offset;
- frame->map_start = map_info->start;
- frame->map_end = map_info->end;
- frame->map_flags = map_info->flags;
- frame->map_load_bias = elf->GetLoadBias();
- return frame;
-}
-
-static bool ShouldStop(const std::vector<std::string>* map_suffixes_to_ignore,
- std::string& map_name) {
- if (map_suffixes_to_ignore == nullptr) {
- return false;
- }
- auto pos = map_name.find_last_of('.');
- if (pos == std::string::npos) {
- return false;
- }
-
- return std::find(map_suffixes_to_ignore->begin(), map_suffixes_to_ignore->end(),
- map_name.substr(pos + 1)) != map_suffixes_to_ignore->end();
-}
-
-void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
- const std::vector<std::string>* map_suffixes_to_ignore) {
- frames_.clear();
- warnings_ = WARNING_NONE;
- last_error_.code = ERROR_NONE;
- last_error_.address = 0;
- elf_from_memory_not_file_ = false;
-
- ArchEnum arch = regs_->Arch();
-
- bool return_address_attempt = false;
- bool adjust_pc = false;
- for (; frames_.size() < max_frames_;) {
- uint64_t cur_pc = regs_->pc();
- uint64_t cur_sp = regs_->sp();
-
- MapInfo* map_info = maps_->Find(regs_->pc());
- uint64_t pc_adjustment = 0;
- uint64_t step_pc;
- uint64_t rel_pc;
- Elf* elf;
- if (map_info == nullptr) {
- step_pc = regs_->pc();
- rel_pc = step_pc;
- last_error_.code = ERROR_INVALID_MAP;
- } else {
- if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
- break;
- }
- elf = map_info->GetElf(process_memory_, arch);
- // If this elf is memory backed, and there is a valid file, then set
- // an indicator that we couldn't open the file.
- if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() &&
- map_info->name[0] != '[' && !android::base::StartsWith(map_info->name, "/memfd:")) {
- elf_from_memory_not_file_ = true;
- }
- step_pc = regs_->pc();
- rel_pc = elf->GetRelPc(step_pc, map_info);
- // Everyone except elf data in gdb jit debug maps uses the relative pc.
- if (!(map_info->flags & MAPS_FLAGS_JIT_SYMFILE_MAP)) {
- step_pc = rel_pc;
- }
- if (adjust_pc) {
- pc_adjustment = GetPcAdjustment(rel_pc, elf, arch);
- } else {
- pc_adjustment = 0;
- }
- step_pc -= pc_adjustment;
-
- // If the pc is in an invalid elf file, try and get an Elf object
- // 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_->GetElf(maps_, adjusted_jit_pc);
- if (jit_elf != nullptr) {
- // The jit debug information requires a non relative adjusted pc.
- step_pc = adjusted_jit_pc;
- elf = jit_elf;
- }
- }
- }
-
- FrameData* frame = nullptr;
- if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
- std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
- basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
- if (regs_->dex_pc() != 0) {
- // Add a frame to represent the dex file.
- FillInDexFrame();
- // Clear the dex pc so that we don't repeat this frame later.
- regs_->set_dex_pc(0);
-
- // Make sure there is enough room for the real frame.
- if (frames_.size() == max_frames_) {
- last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
- break;
- }
- }
-
- frame = FillInFrame(map_info, elf, rel_pc, pc_adjustment);
-
- // Once a frame is added, stop skipping frames.
- initial_map_names_to_skip = nullptr;
- }
- adjust_pc = true;
-
- bool stepped = false;
- bool in_device_map = false;
- bool finished = false;
- if (map_info != nullptr) {
- if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) {
- // Do not stop here, fall through in case we are
- // in the speculative unwind path and need to remove
- // some of the speculative frames.
- in_device_map = true;
- } else {
- MapInfo* sp_info = maps_->Find(regs_->sp());
- if (sp_info != nullptr && sp_info->flags & MAPS_FLAGS_DEVICE_MAP) {
- // Do not stop here, fall through in case we are
- // in the speculative unwind path and need to remove
- // some of the speculative frames.
- in_device_map = true;
- } else {
- if (elf->StepIfSignalHandler(rel_pc, regs_, process_memory_.get())) {
- stepped = true;
- if (frame != nullptr) {
- // Need to adjust the relative pc because the signal handler
- // pc should not be adjusted.
- frame->rel_pc = rel_pc;
- frame->pc += pc_adjustment;
- step_pc = rel_pc;
- }
- } else if (elf->Step(step_pc, regs_, process_memory_.get(), &finished)) {
- stepped = true;
- }
- elf->GetLastError(&last_error_);
- }
- }
- }
-
- if (frame != nullptr) {
- if (!resolve_names_ ||
- !elf->GetFunctionName(step_pc, &frame->function_name, &frame->function_offset)) {
- frame->function_name = "";
- frame->function_offset = 0;
- }
- }
-
- if (finished) {
- break;
- }
-
- if (!stepped) {
- if (return_address_attempt) {
- // Only remove the speculative frame if there are more than two frames
- // or the pc in the first frame is in a valid map.
- // This allows for a case where the code jumps into the middle of
- // nowhere, but there is no other unwind information after that.
- if (frames_.size() > 2 || (frames_.size() > 0 && maps_->Find(frames_[0].pc) != nullptr)) {
- // Remove the speculative frame.
- frames_.pop_back();
- }
- break;
- } else if (in_device_map) {
- // Do not attempt any other unwinding, pc or sp is in a device
- // map.
- break;
- } else {
- // Steping didn't work, try this secondary method.
- if (!regs_->SetPcFromReturnAddress(process_memory_.get())) {
- break;
- }
- return_address_attempt = true;
- }
- } else {
- return_address_attempt = false;
- if (max_frames_ == frames_.size()) {
- last_error_.code = ERROR_MAX_FRAMES_EXCEEDED;
- }
- }
-
- // If the pc and sp didn't change, then consider everything stopped.
- if (cur_pc == regs_->pc() && cur_sp == regs_->sp()) {
- last_error_.code = ERROR_REPEATED_FRAME;
- break;
- }
- }
-}
-
-std::string Unwinder::FormatFrame(const FrameData& frame) const {
- std::string data;
- if (regs_->Is32Bit()) {
- data += android::base::StringPrintf(" #%02zu pc %08" PRIx64, frame.num, frame.rel_pc);
- } else {
- data += android::base::StringPrintf(" #%02zu pc %016" PRIx64, frame.num, frame.rel_pc);
- }
-
- if (frame.map_start == frame.map_end) {
- // No valid map associated with this frame.
- data += " <unknown>";
- } else if (!frame.map_name.empty()) {
- data += " " + frame.map_name;
- } else {
- data += android::base::StringPrintf(" <anonymous:%" PRIx64 ">", frame.map_start);
- }
-
- if (frame.map_elf_start_offset != 0) {
- data += android::base::StringPrintf(" (offset 0x%" PRIx64 ")", frame.map_elf_start_offset);
- }
-
- if (!frame.function_name.empty()) {
- char* demangled_name = __cxa_demangle(frame.function_name.c_str(), nullptr, nullptr, nullptr);
- if (demangled_name == nullptr) {
- data += " (" + frame.function_name;
- } else {
- data += " (";
- data += demangled_name;
- free(demangled_name);
- }
- if (frame.function_offset != 0) {
- data += android::base::StringPrintf("+%" PRId64, frame.function_offset);
- }
- data += ')';
- }
-
- MapInfo* map_info = maps_->Find(frame.map_start);
- if (map_info != nullptr && display_build_id_) {
- std::string build_id = map_info->GetPrintableBuildID();
- if (!build_id.empty()) {
- data += " (BuildId: " + build_id + ')';
- }
- }
- return data;
-}
-
-std::string Unwinder::FormatFrame(size_t frame_num) const {
- if (frame_num >= frames_.size()) {
- return "";
- }
- return FormatFrame(frames_[frame_num]);
-}
-
-void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
- jit_debug->SetArch(arch);
- jit_debug_ = jit_debug;
-}
-
-void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
- dex_files->SetArch(arch);
- dex_files_ = dex_files;
-}
-
-bool UnwinderFromPid::Init(ArchEnum arch) {
- if (pid_ == getpid()) {
- maps_ptr_.reset(new LocalMaps());
- } else {
- maps_ptr_.reset(new RemoteMaps(pid_));
- }
- if (!maps_ptr_->Parse()) {
- return false;
- }
- maps_ = maps_ptr_.get();
-
- 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(DEXFILE_SUPPORT)
- dex_files_ptr_.reset(new DexFiles(process_memory_));
- dex_files_ = dex_files_ptr_.get();
- SetDexFiles(dex_files_, arch);
-#endif
-
- return true;
-}
-
-FrameData Unwinder::BuildFrameFromPcOnly(uint64_t pc) {
- FrameData frame;
-
- Maps* maps = GetMaps();
- MapInfo* map_info = maps->Find(pc);
- if (!map_info) {
- frame.rel_pc = pc;
- return frame;
- }
-
- ArchEnum arch = Regs::CurrentArch();
- Elf* elf = map_info->GetElf(GetProcessMemory(), arch);
-
- uint64_t relative_pc = elf->GetRelPc(pc, map_info);
-
- uint64_t pc_adjustment = GetPcAdjustment(relative_pc, elf, arch);
- relative_pc -= pc_adjustment;
- // The debug PC may be different if the PC comes from the JIT.
- uint64_t debug_pc = relative_pc;
-
- // If we don't have a valid ELF file, check the JIT.
- if (!elf->valid()) {
- JitDebug jit_debug(GetProcessMemory());
- uint64_t jit_pc = pc - pc_adjustment;
- Elf* jit_elf = jit_debug.GetElf(maps, jit_pc);
- if (jit_elf != nullptr) {
- debug_pc = jit_pc;
- elf = jit_elf;
- }
- }
-
- // Copy all the things we need into the frame for symbolization.
- frame.rel_pc = relative_pc;
- frame.pc = pc - pc_adjustment;
- frame.map_name = map_info->name;
- frame.map_elf_start_offset = map_info->elf_start_offset;
- frame.map_exact_offset = map_info->offset;
- frame.map_start = map_info->start;
- frame.map_end = map_info->end;
- frame.map_flags = map_info->flags;
- frame.map_load_bias = elf->GetLoadBias();
-
- if (!resolve_names_ ||
- !elf->GetFunctionName(relative_pc, &frame.function_name, &frame.function_offset)) {
- frame.function_name = "";
- frame.function_offset = 0;
- }
- return frame;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/benchmarks/ElfBenchmark.cpp b/libunwindstack/benchmarks/ElfBenchmark.cpp
deleted file mode 100644
index a46bd7a..0000000
--- a/libunwindstack/benchmarks/ElfBenchmark.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2020 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 <err.h>
-#include <malloc.h>
-#include <stdint.h>
-
-#include <string>
-
-#include <benchmark/benchmark.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-#include "Utils.h"
-
-static void BenchmarkElfCreate(benchmark::State& state, const std::string& elf_file) {
-#if defined(__BIONIC__)
- uint64_t rss_bytes = 0;
-#endif
- uint64_t alloc_bytes = 0;
- for (auto _ : state) {
- state.PauseTiming();
-#if defined(__BIONIC__)
- mallopt(M_PURGE, 0);
- uint64_t rss_bytes_before = 0;
- GatherRss(&rss_bytes_before);
-#endif
- uint64_t alloc_bytes_before = mallinfo().uordblks;
- auto file_memory = unwindstack::Memory::CreateFileMemory(elf_file, 0);
- state.ResumeTiming();
-
- unwindstack::Elf elf(file_memory.release());
- if (!elf.Init() || !elf.valid()) {
- errx(1, "Internal Error: Cannot open elf.");
- }
-
- state.PauseTiming();
-#if defined(__BIONIC__)
- mallopt(M_PURGE, 0);
-#endif
- alloc_bytes += mallinfo().uordblks - alloc_bytes_before;
-#if defined(__BIONIC__)
- GatherRss(&rss_bytes);
- rss_bytes -= rss_bytes_before;
-#endif
- state.ResumeTiming();
- }
-
-#if defined(__BIONIC__)
- state.counters["RSS_BYTES"] = rss_bytes / static_cast<double>(state.iterations());
-#endif
- state.counters["ALLOCATED_BYTES"] = alloc_bytes / static_cast<double>(state.iterations());
-}
-
-void BM_elf_create(benchmark::State& state) {
- BenchmarkElfCreate(state, GetElfFile());
-}
-BENCHMARK(BM_elf_create);
-
-void BM_elf_create_compressed(benchmark::State& state) {
- BenchmarkElfCreate(state, GetCompressedElfFile());
-}
-BENCHMARK(BM_elf_create_compressed);
-
-static void InitializeBuildId(benchmark::State& state, unwindstack::Maps& maps,
- unwindstack::MapInfo** build_id_map_info) {
- if (!maps.Parse()) {
- state.SkipWithError("Failed to parse local maps.");
- return;
- }
-
- // Find the libc.so share library and use that for benchmark purposes.
- *build_id_map_info = nullptr;
- for (auto& map_info : maps) {
- if (map_info->offset == 0 && map_info->GetBuildID() != "") {
- *build_id_map_info = map_info.get();
- break;
- }
- }
-
- if (*build_id_map_info == nullptr) {
- state.SkipWithError("Failed to find a map with a BuildID.");
- }
-}
-
-static void BM_elf_get_build_id_from_object(benchmark::State& state) {
- unwindstack::LocalMaps maps;
- unwindstack::MapInfo* build_id_map_info;
- InitializeBuildId(state, maps, &build_id_map_info);
-
- unwindstack::Elf* elf = build_id_map_info->GetElf(std::shared_ptr<unwindstack::Memory>(),
- unwindstack::Regs::CurrentArch());
- if (!elf->valid()) {
- state.SkipWithError("Cannot get valid elf from map.");
- }
-
- for (auto _ : state) {
- state.PauseTiming();
- uintptr_t id = build_id_map_info->build_id;
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- build_id_map_info->build_id = 0;
- }
- state.ResumeTiming();
- benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
- }
-}
-BENCHMARK(BM_elf_get_build_id_from_object);
-
-static void BM_elf_get_build_id_from_file(benchmark::State& state) {
- unwindstack::LocalMaps maps;
- unwindstack::MapInfo* build_id_map_info;
- InitializeBuildId(state, maps, &build_id_map_info);
-
- for (auto _ : state) {
- state.PauseTiming();
- uintptr_t id = build_id_map_info->build_id;
- if (id != 0) {
- delete reinterpret_cast<std::string*>(id);
- build_id_map_info->build_id = 0;
- }
- state.ResumeTiming();
- benchmark::DoNotOptimize(build_id_map_info->GetBuildID());
- }
-}
-BENCHMARK(BM_elf_get_build_id_from_file);
diff --git a/libunwindstack/benchmarks/MapsBenchmark.cpp b/libunwindstack/benchmarks/MapsBenchmark.cpp
deleted file mode 100644
index 5df14916..0000000
--- a/libunwindstack/benchmarks/MapsBenchmark.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2020 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 <err.h>
-#include <stdint.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-
-#include <benchmark/benchmark.h>
-
-#include <unwindstack/Maps.h>
-
-class BenchmarkLocalUpdatableMaps : public unwindstack::LocalUpdatableMaps {
- public:
- BenchmarkLocalUpdatableMaps() : unwindstack::LocalUpdatableMaps() {}
- virtual ~BenchmarkLocalUpdatableMaps() = default;
-
- const std::string GetMapsFile() const override { return maps_file_; }
-
- void BenchmarkSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
-
- private:
- std::string maps_file_;
-};
-
-static constexpr size_t kNumSmallMaps = 100;
-static constexpr size_t kNumLargeMaps = 10000;
-
-static void CreateMap(const char* filename, size_t num_maps, size_t increment = 1) {
- std::string maps;
- for (size_t i = 0; i < num_maps; i += increment) {
- maps += android::base::StringPrintf("%zu-%zu r-xp 0000 00:00 0 name%zu\n", i * 1000,
- (i + 1) * 1000 * increment, i * increment);
- }
- if (!android::base::WriteStringToFile(maps, filename)) {
- errx(1, "WriteStringToFile failed");
- }
-}
-
-static void ReparseBenchmark(benchmark::State& state, const char* maps1, size_t maps1_total,
- const char* maps2, size_t maps2_total) {
- for (auto _ : state) {
- BenchmarkLocalUpdatableMaps maps;
- maps.BenchmarkSetMapsFile(maps1);
- if (!maps.Reparse()) {
- errx(1, "Internal Error: reparse of initial maps filed.");
- }
- if (maps.Total() != maps1_total) {
- errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
- maps1_total);
- }
- maps.BenchmarkSetMapsFile(maps2);
- if (!maps.Reparse()) {
- errx(1, "Internal Error: reparse of second set of maps filed.");
- }
- if (maps.Total() != maps2_total) {
- errx(1, "Internal Error: Incorrect total number of maps %zu, expected %zu.", maps.Total(),
- maps2_total);
- }
- }
-}
-
-void BM_local_updatable_maps_reparse_double_initial_small(benchmark::State& state) {
- TemporaryFile initial_maps;
- CreateMap(initial_maps.path, kNumSmallMaps, 2);
-
- TemporaryFile reparse_maps;
- CreateMap(reparse_maps.path, kNumSmallMaps);
-
- ReparseBenchmark(state, initial_maps.path, kNumSmallMaps / 2, reparse_maps.path, kNumSmallMaps);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_double_initial_small);
-
-void BM_local_updatable_maps_reparse_double_initial_large(benchmark::State& state) {
- TemporaryFile initial_maps;
- CreateMap(initial_maps.path, kNumLargeMaps, 2);
-
- TemporaryFile reparse_maps;
- CreateMap(reparse_maps.path, kNumLargeMaps);
-
- ReparseBenchmark(state, initial_maps.path, kNumLargeMaps / 2, reparse_maps.path, kNumLargeMaps);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_double_initial_large);
-
-void BM_local_updatable_maps_reparse_same_maps_small(benchmark::State& state) {
- static constexpr size_t kNumSmallMaps = 100;
- TemporaryFile maps;
- CreateMap(maps.path, kNumSmallMaps);
-
- ReparseBenchmark(state, maps.path, kNumSmallMaps, maps.path, kNumSmallMaps);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_same_maps_small);
-
-void BM_local_updatable_maps_reparse_same_maps_large(benchmark::State& state) {
- TemporaryFile maps;
- CreateMap(maps.path, kNumLargeMaps);
-
- ReparseBenchmark(state, maps.path, kNumLargeMaps, maps.path, kNumLargeMaps);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_same_maps_large);
-
-void BM_local_updatable_maps_reparse_few_extra_small(benchmark::State& state) {
- TemporaryFile maps1;
- CreateMap(maps1.path, kNumSmallMaps - 4);
-
- TemporaryFile maps2;
- CreateMap(maps2.path, kNumSmallMaps);
-
- ReparseBenchmark(state, maps1.path, kNumSmallMaps - 4, maps2.path, kNumSmallMaps);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_few_extra_small);
-
-void BM_local_updatable_maps_reparse_few_extra_large(benchmark::State& state) {
- TemporaryFile maps1;
- CreateMap(maps1.path, kNumLargeMaps - 4);
-
- TemporaryFile maps2;
- CreateMap(maps2.path, kNumLargeMaps);
-
- ReparseBenchmark(state, maps1.path, kNumLargeMaps - 4, maps2.path, kNumLargeMaps);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_few_extra_large);
-
-void BM_local_updatable_maps_reparse_few_less_small(benchmark::State& state) {
- TemporaryFile maps1;
- CreateMap(maps1.path, kNumSmallMaps);
-
- TemporaryFile maps2;
- CreateMap(maps2.path, kNumSmallMaps - 4);
-
- ReparseBenchmark(state, maps1.path, kNumSmallMaps, maps2.path, kNumSmallMaps - 4);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_few_less_small);
-
-void BM_local_updatable_maps_reparse_few_less_large(benchmark::State& state) {
- TemporaryFile maps1;
- CreateMap(maps1.path, kNumLargeMaps);
-
- TemporaryFile maps2;
- CreateMap(maps2.path, kNumLargeMaps - 4);
-
- ReparseBenchmark(state, maps1.path, kNumLargeMaps, maps2.path, kNumLargeMaps - 4);
-}
-BENCHMARK(BM_local_updatable_maps_reparse_few_less_large);
diff --git a/libunwindstack/benchmarks/SymbolBenchmark.cpp b/libunwindstack/benchmarks/SymbolBenchmark.cpp
deleted file mode 100644
index 73088da..0000000
--- a/libunwindstack/benchmarks/SymbolBenchmark.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2020 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 <err.h>
-#include <inttypes.h>
-#include <malloc.h>
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include <benchmark/benchmark.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Memory.h>
-
-#include "Utils.h"
-
-static void BenchmarkSymbolLookup(benchmark::State& state, std::vector<uint64_t> offsets,
- std::string elf_file, bool expect_found) {
-#if defined(__BIONIC__)
- uint64_t rss_bytes = 0;
-#endif
- uint64_t alloc_bytes = 0;
- for (auto _ : state) {
- state.PauseTiming();
- unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(elf_file, 0).release());
- if (!elf.Init() || !elf.valid()) {
- errx(1, "Internal Error: Cannot open elf.");
- }
-
-#if defined(__BIONIC__)
- mallopt(M_PURGE, 0);
- uint64_t rss_bytes_before = 0;
- GatherRss(&rss_bytes_before);
-#endif
- uint64_t alloc_bytes_before = mallinfo().uordblks;
- state.ResumeTiming();
-
- for (auto pc : offsets) {
- std::string name;
- uint64_t offset;
- bool found = elf.GetFunctionName(pc, &name, &offset);
- if (expect_found && !found) {
- errx(1, "expected pc 0x%" PRIx64 " present, but not found.", pc);
- } else if (!expect_found && found) {
- errx(1, "expected pc 0x%" PRIx64 " not present, but found.", pc);
- }
- }
-
- state.PauseTiming();
-#if defined(__BIONIC__)
- mallopt(M_PURGE, 0);
-#endif
- alloc_bytes += mallinfo().uordblks - alloc_bytes_before;
-#if defined(__BIONIC__)
- GatherRss(&rss_bytes);
- rss_bytes -= rss_bytes_before;
-#endif
- state.ResumeTiming();
- }
-
-#if defined(__BIONIC__)
- state.counters["RSS_BYTES"] = rss_bytes / static_cast<double>(state.iterations());
-#endif
- state.counters["ALLOCATED_BYTES"] = alloc_bytes / static_cast<double>(state.iterations());
-}
-
-static void BenchmarkSymbolLookup(benchmark::State& state, uint64_t pc, std::string elf_file,
- bool expect_found) {
- BenchmarkSymbolLookup(state, std::vector<uint64_t>{pc}, elf_file, expect_found);
-}
-
-void BM_symbol_not_present(benchmark::State& state) {
- BenchmarkSymbolLookup(state, 0, GetElfFile(), false);
-}
-BENCHMARK(BM_symbol_not_present);
-
-void BM_symbol_find_single(benchmark::State& state) {
- BenchmarkSymbolLookup(state, 0x22b2bc, GetElfFile(), true);
-}
-BENCHMARK(BM_symbol_find_single);
-
-void BM_symbol_find_single_many_times(benchmark::State& state) {
- BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x22b2bc), GetElfFile(), true);
-}
-BENCHMARK(BM_symbol_find_single_many_times);
-
-void BM_symbol_find_multiple(benchmark::State& state) {
- BenchmarkSymbolLookup(state,
- std::vector<uint64_t>{0x22b2bc, 0xd5d30, 0x1312e8, 0x13582e, 0x1389c8},
- GetElfFile(), true);
-}
-BENCHMARK(BM_symbol_find_multiple);
-
-void BM_symbol_not_present_from_sorted(benchmark::State& state) {
- BenchmarkSymbolLookup(state, 0, GetSymbolSortedElfFile(), false);
-}
-BENCHMARK(BM_symbol_not_present_from_sorted);
-
-void BM_symbol_find_single_from_sorted(benchmark::State& state) {
- BenchmarkSymbolLookup(state, 0x138638, GetSymbolSortedElfFile(), true);
-}
-BENCHMARK(BM_symbol_find_single_from_sorted);
-
-void BM_symbol_find_single_many_times_from_sorted(benchmark::State& state) {
- BenchmarkSymbolLookup(state, std::vector<uint64_t>(15, 0x138638), GetSymbolSortedElfFile(), true);
-}
-BENCHMARK(BM_symbol_find_single_many_times_from_sorted);
-
-void BM_symbol_find_multiple_from_sorted(benchmark::State& state) {
- BenchmarkSymbolLookup(state,
- std::vector<uint64_t>{0x138638, 0x84350, 0x14df18, 0x1f3a38, 0x1f3ca8},
- GetSymbolSortedElfFile(), true);
-}
-BENCHMARK(BM_symbol_find_multiple_from_sorted);
diff --git a/libunwindstack/benchmarks/Utils.cpp b/libunwindstack/benchmarks/Utils.cpp
deleted file mode 100644
index c92f109..0000000
--- a/libunwindstack/benchmarks/Utils.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 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 <err.h>
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/strings.h>
-#include <benchmark/benchmark.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Memory.h>
-
-std::string GetElfFile() {
- return android::base::GetExecutableDirectory() + "/benchmarks/files/libart_arm.so";
-}
-
-std::string GetSymbolSortedElfFile() {
- return android::base::GetExecutableDirectory() + "/benchmarks/files/boot_arm.oat";
-}
-
-std::string GetCompressedElfFile() {
- // Both are the same right now.
- return GetSymbolSortedElfFile();
-}
-
-#if defined(__BIONIC__)
-
-#include <meminfo/procmeminfo.h>
-#include <procinfo/process_map.h>
-
-void GatherRss(uint64_t* rss_bytes) {
- android::meminfo::ProcMemInfo proc_mem(getpid());
- const std::vector<android::meminfo::Vma>& maps = proc_mem.MapsWithoutUsageStats();
- for (auto& vma : maps) {
- if (vma.name == "[anon:libc_malloc]" || android::base::StartsWith(vma.name, "[anon:scudo:") ||
- android::base::StartsWith(vma.name, "[anon:GWP-ASan")) {
- android::meminfo::Vma update_vma(vma);
- if (!proc_mem.FillInVmaStats(update_vma)) {
- err(1, "FillInVmaStats failed\n");
- }
- *rss_bytes += update_vma.usage.rss;
- }
- }
-}
-#endif
diff --git a/libunwindstack/benchmarks/Utils.h b/libunwindstack/benchmarks/Utils.h
deleted file mode 100644
index bee6efc..0000000
--- a/libunwindstack/benchmarks/Utils.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2020 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_UTILS_H
-#define _LIBUNWINDSTACK_UTILS_H
-
-#include <stdint.h>
-
-#include <string>
-
-std::string GetElfFile();
-
-std::string GetSymbolSortedElfFile();
-
-std::string GetCompressedElfFile();
-
-#if defined(__BIONIC__)
-
-#include <meminfo/procmeminfo.h>
-#include <procinfo/process_map.h>
-
-void GatherRss(uint64_t* rss_bytes);
-
-#endif
-
-#endif // _LIBUNWINDSTACK_UTILS_h
diff --git a/libunwindstack/benchmarks/files/boot_arm.oat b/libunwindstack/benchmarks/files/boot_arm.oat
deleted file mode 100644
index 51188eb..0000000
--- a/libunwindstack/benchmarks/files/boot_arm.oat
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/benchmarks/files/libart_arm.so b/libunwindstack/benchmarks/files/libart_arm.so
deleted file mode 100644
index 2201faf..0000000
--- a/libunwindstack/benchmarks/files/libart_arm.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/benchmarks/unwind_benchmarks.cpp b/libunwindstack/benchmarks/unwind_benchmarks.cpp
deleted file mode 100644
index 0bee6ef..0000000
--- a/libunwindstack/benchmarks/unwind_benchmarks.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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 <memory>
-
-#include <benchmark/benchmark.h>
-
-#include <android-base/strings.h>
-
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsGetLocal.h>
-#include <unwindstack/Unwinder.h>
-
-size_t Call6(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
- std::unique_ptr<unwindstack::Regs> regs(unwindstack::Regs::CreateFromLocal());
- unwindstack::RegsGetLocal(regs.get());
- unwindstack::Unwinder unwinder(32, maps, regs.get(), process_memory);
- unwinder.Unwind();
- return unwinder.NumFrames();
-}
-
-size_t Call5(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
- return Call6(process_memory, maps);
-}
-
-size_t Call4(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
- return Call5(process_memory, maps);
-}
-
-size_t Call3(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
- return Call4(process_memory, maps);
-}
-
-size_t Call2(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
- return Call3(process_memory, maps);
-}
-
-size_t Call1(std::shared_ptr<unwindstack::Memory>& process_memory, unwindstack::Maps* maps) {
- return Call2(process_memory, maps);
-}
-
-static void BM_uncached_unwind(benchmark::State& state) {
- auto process_memory = unwindstack::Memory::CreateProcessMemory(getpid());
- unwindstack::LocalMaps maps;
- if (!maps.Parse()) {
- state.SkipWithError("Failed to parse local maps.");
- }
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(Call1(process_memory, &maps));
- }
-}
-BENCHMARK(BM_uncached_unwind);
-
-static void BM_cached_unwind(benchmark::State& state) {
- auto process_memory = unwindstack::Memory::CreateProcessMemoryCached(getpid());
- unwindstack::LocalMaps maps;
- if (!maps.Parse()) {
- state.SkipWithError("Failed to parse local maps.");
- }
-
- for (auto _ : state) {
- benchmark::DoNotOptimize(Call1(process_memory, &maps));
- }
-}
-BENCHMARK(BM_cached_unwind);
-
-BENCHMARK_MAIN();
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
deleted file mode 100644
index 67a9640..0000000
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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/DwarfError.h b/libunwindstack/include/unwindstack/DwarfError.h
deleted file mode 100644
index 763e2cb..0000000
--- a/libunwindstack/include/unwindstack/DwarfError.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_ERROR_H
-#define _LIBUNWINDSTACK_DWARF_ERROR_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum DwarfErrorCode : uint8_t {
- DWARF_ERROR_NONE,
- DWARF_ERROR_MEMORY_INVALID,
- DWARF_ERROR_ILLEGAL_VALUE,
- DWARF_ERROR_ILLEGAL_STATE,
- DWARF_ERROR_STACK_INDEX_NOT_VALID,
- DWARF_ERROR_NOT_IMPLEMENTED,
- DWARF_ERROR_TOO_MANY_ITERATIONS,
- DWARF_ERROR_CFA_NOT_DEFINED,
- DWARF_ERROR_UNSUPPORTED_VERSION,
- DWARF_ERROR_NO_FDES,
-};
-
-struct DwarfErrorData {
- DwarfErrorCode code;
- uint64_t address;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_ERROR_H
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h
deleted file mode 100644
index bf45bc7..0000000
--- a/libunwindstack/include/unwindstack/DwarfLocation.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_LOCATION_H
-#define _LIBUNWINDSTACK_DWARF_LOCATION_H
-
-#include <stdint.h>
-
-#include <unordered_map>
-
-namespace unwindstack {
-
-struct DwarfCie;
-
-enum DwarfLocationEnum : uint8_t {
- DWARF_LOCATION_INVALID = 0,
- DWARF_LOCATION_UNDEFINED,
- DWARF_LOCATION_OFFSET,
- DWARF_LOCATION_VAL_OFFSET,
- DWARF_LOCATION_REGISTER,
- DWARF_LOCATION_EXPRESSION,
- DWARF_LOCATION_VAL_EXPRESSION,
- DWARF_LOCATION_PSEUDO_REGISTER,
-};
-
-struct DwarfLocation {
- DwarfLocationEnum type;
- uint64_t values[2];
-};
-
-struct DwarfLocations : public std::unordered_map<uint32_t, DwarfLocation> {
- const DwarfCie* cie;
- // The range of PCs where the locations are valid (end is exclusive).
- uint64_t pc_start = 0;
- uint64_t pc_end = 0;
-};
-typedef DwarfLocations dwarf_loc_regs_t;
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_LOCATION_H
diff --git a/libunwindstack/include/unwindstack/DwarfMemory.h b/libunwindstack/include/unwindstack/DwarfMemory.h
deleted file mode 100644
index c45699a..0000000
--- a/libunwindstack/include/unwindstack/DwarfMemory.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_MEMORY_H
-#define _LIBUNWINDSTACK_DWARF_MEMORY_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-
-class DwarfMemory {
- public:
- DwarfMemory(Memory* memory) : memory_(memory) {}
- virtual ~DwarfMemory() = default;
-
- bool ReadBytes(void* dst, size_t num_bytes);
-
- template <typename SignedType>
- bool ReadSigned(uint64_t* value);
-
- bool ReadULEB128(uint64_t* value);
-
- bool ReadSLEB128(int64_t* value);
-
- template <typename AddressType>
- size_t GetEncodedSize(uint8_t encoding);
-
- bool AdjustEncodedValue(uint8_t encoding, uint64_t* value);
-
- template <typename AddressType>
- bool ReadEncodedValue(uint8_t encoding, uint64_t* value);
-
- uint64_t cur_offset() { return cur_offset_; }
- void set_cur_offset(uint64_t cur_offset) { cur_offset_ = cur_offset; }
-
- void set_pc_offset(int64_t offset) { pc_offset_ = offset; }
- void clear_pc_offset() { pc_offset_ = INT64_MAX; }
-
- void set_data_offset(uint64_t offset) { data_offset_ = offset; }
- void clear_data_offset() { data_offset_ = static_cast<uint64_t>(-1); }
-
- void set_func_offset(uint64_t offset) { func_offset_ = offset; }
- void clear_func_offset() { func_offset_ = static_cast<uint64_t>(-1); }
-
- void set_text_offset(uint64_t offset) { text_offset_ = offset; }
- void clear_text_offset() { text_offset_ = static_cast<uint64_t>(-1); }
-
- private:
- Memory* memory_;
- uint64_t cur_offset_ = 0;
-
- int64_t pc_offset_ = INT64_MAX;
- uint64_t data_offset_ = static_cast<uint64_t>(-1);
- uint64_t func_offset_ = static_cast<uint64_t>(-1);
- uint64_t text_offset_ = static_cast<uint64_t>(-1);
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_MEMORY_H
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
deleted file mode 100644
index af823da..0000000
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_SECTION_H
-#define _LIBUNWINDSTACK_DWARF_SECTION_H
-
-#include <stdint.h>
-
-#include <iterator>
-#include <map>
-#include <unordered_map>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/DwarfStructs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-enum ArchEnum : uint8_t;
-class Memory;
-class Regs;
-template <typename AddressType>
-struct RegsInfo;
-
-class DwarfSection {
- public:
- DwarfSection(Memory* memory);
- virtual ~DwarfSection() = default;
-
- class iterator : public std::iterator<std::bidirectional_iterator_tag, DwarfFde*> {
- public:
- iterator(DwarfSection* section, size_t index) : index_(index) {
- section->GetFdes(&fdes_);
- if (index_ == static_cast<size_t>(-1)) {
- index_ = fdes_.size();
- }
- }
-
- iterator& operator++() {
- index_++;
- return *this;
- }
- iterator& operator++(int increment) {
- index_ += increment;
- return *this;
- }
- iterator& operator--() {
- index_--;
- return *this;
- }
- iterator& operator--(int decrement) {
- index_ -= decrement;
- return *this;
- }
-
- bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
- bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
-
- const DwarfFde* operator*() {
- if (index_ > fdes_.size()) return nullptr;
- return fdes_[index_];
- }
-
- private:
- std::vector<const DwarfFde*> fdes_;
- size_t index_ = 0;
- };
-
- iterator begin() { return iterator(this, 0); }
- iterator end() { return iterator(this, static_cast<size_t>(-1)); }
-
- DwarfErrorCode LastErrorCode() { return last_error_.code; }
- uint64_t LastErrorAddress() { return last_error_.address; }
-
- virtual bool Init(uint64_t offset, uint64_t size, int64_t section_bias) = 0;
-
- virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0;
-
- virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) = 0;
-
- virtual void GetFdes(std::vector<const DwarfFde*>* fdes) = 0;
-
- virtual const DwarfFde* GetFdeFromPc(uint64_t pc) = 0;
-
- virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs,
- ArchEnum arch) = 0;
-
- virtual uint64_t GetCieOffsetFromFde32(uint32_t pointer) = 0;
-
- virtual uint64_t GetCieOffsetFromFde64(uint64_t pointer) = 0;
-
- virtual uint64_t AdjustPcFromFde(uint64_t pc) = 0;
-
- bool Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished);
-
- protected:
- DwarfMemory memory_;
- DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
-
- uint32_t cie32_value_ = 0;
- uint64_t cie64_value_ = 0;
-
- std::unordered_map<uint64_t, DwarfFde> fde_entries_;
- std::unordered_map<uint64_t, DwarfCie> cie_entries_;
- std::unordered_map<uint64_t, dwarf_loc_regs_t> cie_loc_regs_;
- std::map<uint64_t, dwarf_loc_regs_t> loc_regs_; // Single row indexed by pc_end.
-};
-
-template <typename AddressType>
-class DwarfSectionImpl : public DwarfSection {
- public:
- DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {}
- virtual ~DwarfSectionImpl() = default;
-
- bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
-
- const DwarfCie* GetCieFromOffset(uint64_t offset);
-
- const DwarfFde* GetFdeFromOffset(uint64_t offset);
-
- const DwarfFde* GetFdeFromPc(uint64_t pc) override;
-
- void GetFdes(std::vector<const DwarfFde*>* fdes) override;
-
- bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
-
- bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
- Regs* regs, bool* finished) override;
-
- bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs,
- ArchEnum arch) override;
-
- bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) override;
-
- protected:
- bool GetNextCieOrFde(const DwarfFde** fde_entry);
-
- bool FillInCieHeader(DwarfCie* cie);
-
- bool FillInCie(DwarfCie* cie);
-
- bool FillInFdeHeader(DwarfFde* fde);
-
- bool FillInFde(DwarfFde* fde);
-
- bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
- RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
-
- void InsertFde(const DwarfFde* fde);
-
- int64_t section_bias_ = 0;
- uint64_t entries_offset_ = 0;
- uint64_t entries_end_ = 0;
- uint64_t next_entries_offset_ = 0;
- uint64_t pc_offset_ = 0;
-
- std::map<uint64_t, std::pair<uint64_t, const DwarfFde*>> fdes_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_SECTION_H
diff --git a/libunwindstack/include/unwindstack/DwarfStructs.h b/libunwindstack/include/unwindstack/DwarfStructs.h
deleted file mode 100644
index 4b481f0..0000000
--- a/libunwindstack/include/unwindstack/DwarfStructs.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_DWARF_STRUCTS_H
-#define _LIBUNWINDSTACK_DWARF_STRUCTS_H
-
-#include <stdint.h>
-
-#include <vector>
-
-namespace unwindstack {
-
-struct DwarfCie {
- uint8_t version = 0;
- uint8_t fde_address_encoding = 0;
- uint8_t lsda_encoding = 0;
- uint8_t segment_size = 0;
- std::vector<char> augmentation_string;
- uint64_t personality_handler = 0;
- uint64_t cfa_instructions_offset = 0;
- uint64_t cfa_instructions_end = 0;
- uint64_t code_alignment_factor = 0;
- int64_t data_alignment_factor = 0;
- uint64_t return_address_register = 0;
-};
-
-struct DwarfFde {
- uint64_t cie_offset = 0;
- uint64_t cfa_instructions_offset = 0;
- uint64_t cfa_instructions_end = 0;
- uint64_t pc_start = 0;
- uint64_t pc_end = 0;
- uint64_t lsda_address = 0;
- const DwarfCie* cie = nullptr;
-};
-
-constexpr uint16_t CFA_REG = static_cast<uint16_t>(-1);
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DWARF_STRUCTS_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
deleted file mode 100644
index 472ed92..0000000
--- a/libunwindstack/include/unwindstack/Elf.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_ELF_H
-#define _LIBUNWINDSTACK_ELF_H
-
-#include <stddef.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-#include <unordered_map>
-#include <utility>
-
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Memory.h>
-
-#if !defined(EM_AARCH64)
-#define EM_AARCH64 183
-#endif
-
-namespace unwindstack {
-
-// Forward declaration.
-struct MapInfo;
-class Regs;
-
-enum ArchEnum : uint8_t {
- ARCH_UNKNOWN = 0,
- ARCH_ARM,
- ARCH_ARM64,
- ARCH_X86,
- ARCH_X86_64,
- ARCH_MIPS,
- ARCH_MIPS64,
-};
-
-class Elf {
- public:
- Elf(Memory* memory) : memory_(memory) {}
- virtual ~Elf() = default;
-
- bool Init();
-
- void InitGnuDebugdata();
-
- void Invalidate();
-
- std::string GetSoname();
-
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
-
- bool GetGlobalVariableOffset(const std::string& name, uint64_t* memory_offset);
-
- uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
-
- bool StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory);
-
- bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
-
- ElfInterface* CreateInterfaceFromMemory(Memory* memory);
-
- std::string GetBuildID();
-
- int64_t GetLoadBias() { return load_bias_; }
-
- bool IsValidPc(uint64_t pc);
-
- void GetLastError(ErrorData* data);
- ErrorCode GetLastErrorCode();
- uint64_t GetLastErrorAddress();
-
- bool valid() { return valid_; }
-
- uint32_t machine_type() { return machine_type_; }
-
- uint8_t class_type() { return class_type_; }
-
- ArchEnum arch() { return arch_; }
-
- Memory* memory() { return memory_.get(); }
-
- ElfInterface* interface() { return interface_.get(); }
-
- ElfInterface* gnu_debugdata_interface() { return gnu_debugdata_interface_.get(); }
-
- static bool IsValidElf(Memory* memory);
-
- static bool GetInfo(Memory* memory, uint64_t* size);
-
- static int64_t GetLoadBias(Memory* memory);
-
- static std::string GetBuildID(Memory* memory);
-
- static void SetCachingEnabled(bool enable);
- static bool CachingEnabled() { return cache_enabled_; }
-
- static void CacheLock();
- static void CacheUnlock();
- static void CacheAdd(MapInfo* info);
- static bool CacheGet(MapInfo* info);
- static bool CacheAfterCreateMemory(MapInfo* info);
-
- protected:
- bool valid_ = false;
- int64_t load_bias_ = 0;
- std::unique_ptr<ElfInterface> interface_;
- std::unique_ptr<Memory> memory_;
- uint32_t machine_type_;
- uint8_t class_type_;
- ArchEnum arch_;
- // Protect calls that can modify internal state of the interface object.
- std::mutex lock_;
-
- std::unique_ptr<Memory> gnu_debugdata_memory_;
- std::unique_ptr<ElfInterface> gnu_debugdata_interface_;
-
- static bool cache_enabled_;
- static std::unordered_map<std::string, std::pair<std::shared_ptr<Elf>, bool>>* cache_;
- static std::mutex* cache_lock_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ELF_H
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
deleted file mode 100644
index 0c39b23..0000000
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_ELF_INTERFACE_H
-#define _LIBUNWINDSTACK_ELF_INTERFACE_H
-
-#include <elf.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/Error.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-class Regs;
-class Symbols;
-
-struct LoadInfo {
- uint64_t offset;
- uint64_t table_offset;
- size_t table_size;
-};
-
-enum : uint8_t {
- SONAME_UNKNOWN = 0,
- SONAME_VALID,
- SONAME_INVALID,
-};
-
-class ElfInterface {
- public:
- ElfInterface(Memory* memory) : memory_(memory) {}
- virtual ~ElfInterface();
-
- virtual bool Init(int64_t* load_bias) = 0;
-
- virtual void InitHeaders() = 0;
-
- virtual std::string GetSoname() = 0;
-
- virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0;
-
- virtual bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) = 0;
-
- virtual std::string GetBuildID() = 0;
-
- virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished);
-
- virtual bool IsValidPc(uint64_t pc);
-
- Memory* CreateGnuDebugdataMemory();
-
- Memory* memory() { return memory_; }
-
- const std::unordered_map<uint64_t, LoadInfo>& pt_loads() { return pt_loads_; }
-
- void SetGnuDebugdataInterface(ElfInterface* interface) { gnu_debugdata_interface_ = interface; }
-
- uint64_t dynamic_offset() { return dynamic_offset_; }
- uint64_t dynamic_vaddr_start() { return dynamic_vaddr_start_; }
- uint64_t dynamic_vaddr_end() { return dynamic_vaddr_end_; }
- uint64_t data_offset() { return data_offset_; }
- uint64_t data_vaddr_start() { return data_vaddr_start_; }
- uint64_t data_vaddr_end() { return data_vaddr_end_; }
- uint64_t eh_frame_hdr_offset() { return eh_frame_hdr_offset_; }
- int64_t eh_frame_hdr_section_bias() { return eh_frame_hdr_section_bias_; }
- uint64_t eh_frame_hdr_size() { return eh_frame_hdr_size_; }
- uint64_t eh_frame_offset() { return eh_frame_offset_; }
- int64_t eh_frame_section_bias() { return eh_frame_section_bias_; }
- uint64_t eh_frame_size() { return eh_frame_size_; }
- uint64_t debug_frame_offset() { return debug_frame_offset_; }
- int64_t debug_frame_section_bias() { return debug_frame_section_bias_; }
- uint64_t debug_frame_size() { return debug_frame_size_; }
- uint64_t gnu_debugdata_offset() { return gnu_debugdata_offset_; }
- uint64_t gnu_debugdata_size() { return gnu_debugdata_size_; }
- uint64_t gnu_build_id_offset() { return gnu_build_id_offset_; }
- uint64_t gnu_build_id_size() { return gnu_build_id_size_; }
-
- DwarfSection* eh_frame() { return eh_frame_.get(); }
- DwarfSection* debug_frame() { return debug_frame_.get(); }
-
- const ErrorData& last_error() { return last_error_; }
- ErrorCode LastErrorCode() { return last_error_.code; }
- uint64_t LastErrorAddress() { return last_error_.address; }
-
- template <typename EhdrType, typename PhdrType>
- static int64_t GetLoadBias(Memory* memory);
-
- template <typename EhdrType, typename ShdrType, typename NhdrType>
- static std::string ReadBuildIDFromMemory(Memory* memory);
-
- protected:
- template <typename AddressType>
- void InitHeadersWithTemplate();
-
- template <typename EhdrType, typename PhdrType, typename ShdrType>
- bool ReadAllHeaders(int64_t* load_bias);
-
- template <typename EhdrType, typename PhdrType>
- void ReadProgramHeaders(const EhdrType& ehdr, int64_t* load_bias);
-
- template <typename EhdrType, typename ShdrType>
- void ReadSectionHeaders(const EhdrType& ehdr);
-
- template <typename DynType>
- std::string GetSonameWithTemplate();
-
- template <typename SymType>
- bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset);
-
- template <typename SymType>
- bool GetGlobalVariableWithTemplate(const std::string& name, uint64_t* memory_address);
-
- virtual void HandleUnknownType(uint32_t, uint64_t, uint64_t) {}
-
- template <typename EhdrType>
- static void GetMaxSizeWithTemplate(Memory* memory, uint64_t* size);
-
- template <typename NhdrType>
- std::string ReadBuildID();
-
- Memory* memory_;
- std::unordered_map<uint64_t, LoadInfo> pt_loads_;
-
- // Stored elf data.
- uint64_t dynamic_offset_ = 0;
- uint64_t dynamic_vaddr_start_ = 0;
- uint64_t dynamic_vaddr_end_ = 0;
-
- uint64_t data_offset_ = 0;
- uint64_t data_vaddr_start_ = 0;
- uint64_t data_vaddr_end_ = 0;
-
- uint64_t eh_frame_hdr_offset_ = 0;
- int64_t eh_frame_hdr_section_bias_ = 0;
- uint64_t eh_frame_hdr_size_ = 0;
-
- uint64_t eh_frame_offset_ = 0;
- int64_t eh_frame_section_bias_ = 0;
- uint64_t eh_frame_size_ = 0;
-
- uint64_t debug_frame_offset_ = 0;
- int64_t debug_frame_section_bias_ = 0;
- uint64_t debug_frame_size_ = 0;
-
- uint64_t gnu_debugdata_offset_ = 0;
- uint64_t gnu_debugdata_size_ = 0;
-
- uint64_t gnu_build_id_offset_ = 0;
- uint64_t gnu_build_id_size_ = 0;
-
- uint8_t soname_type_ = SONAME_UNKNOWN;
- std::string soname_;
-
- ErrorData last_error_{ERROR_NONE, 0};
-
- std::unique_ptr<DwarfSection> eh_frame_;
- std::unique_ptr<DwarfSection> debug_frame_;
- // The Elf object owns the gnu_debugdata interface object.
- ElfInterface* gnu_debugdata_interface_ = nullptr;
-
- std::vector<Symbols*> symbols_;
- std::vector<std::pair<uint64_t, uint64_t>> strtabs_;
-};
-
-class ElfInterface32 : public ElfInterface {
- public:
- ElfInterface32(Memory* memory) : ElfInterface(memory) {}
- virtual ~ElfInterface32() = default;
-
- bool Init(int64_t* load_bias) override {
- return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(load_bias);
- }
-
- void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); }
-
- std::string GetSoname() override { return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(); }
-
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
- return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset);
- }
-
- bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) override {
- return ElfInterface::GetGlobalVariableWithTemplate<Elf32_Sym>(name, memory_address);
- }
-
- std::string GetBuildID() override { return ElfInterface::ReadBuildID<Elf32_Nhdr>(); }
-
- static void GetMaxSize(Memory* memory, uint64_t* size) {
- GetMaxSizeWithTemplate<Elf32_Ehdr>(memory, size);
- }
-};
-
-class ElfInterface64 : public ElfInterface {
- public:
- ElfInterface64(Memory* memory) : ElfInterface(memory) {}
- virtual ~ElfInterface64() = default;
-
- bool Init(int64_t* load_bias) override {
- return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(load_bias);
- }
-
- void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); }
-
- std::string GetSoname() override { return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(); }
-
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override {
- return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset);
- }
-
- bool GetGlobalVariable(const std::string& name, uint64_t* memory_address) override {
- return ElfInterface::GetGlobalVariableWithTemplate<Elf64_Sym>(name, memory_address);
- }
-
- std::string GetBuildID() override { return ElfInterface::ReadBuildID<Elf64_Nhdr>(); }
-
- static void GetMaxSize(Memory* memory, uint64_t* size) {
- GetMaxSizeWithTemplate<Elf64_Ehdr>(memory, size);
- }
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ELF_INTERFACE_H
diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h
deleted file mode 100644
index 66fefe7..0000000
--- a/libunwindstack/include/unwindstack/Error.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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_ERROR_H
-#define _LIBUNWINDSTACK_ERROR_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-// A bit map of warnings, multiple warnings can be set at the same time.
-enum WarningCode : uint64_t {
- WARNING_NONE = 0,
- WARNING_DEX_PC_NOT_IN_MAP = 0x1, // A dex pc was found, but it doesn't exist
- // in any valid map.
-};
-
-enum ErrorCode : uint8_t {
- ERROR_NONE, // No error.
- ERROR_MEMORY_INVALID, // Memory read failed.
- ERROR_UNWIND_INFO, // Unable to use unwind information to unwind.
- ERROR_UNSUPPORTED, // Encountered unsupported feature.
- ERROR_INVALID_MAP, // Unwind in an invalid map.
- ERROR_MAX_FRAMES_EXCEEDED, // The number of frames exceed the total allowed.
- ERROR_REPEATED_FRAME, // The last frame has the same pc/sp as the next.
- ERROR_INVALID_ELF, // Unwind in an invalid elf.
-};
-
-struct ErrorData {
- ErrorCode code;
- uint64_t address; // Only valid when code is ERROR_MEMORY_INVALID.
- // Indicates the failing address.
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_ERROR_H
diff --git a/libunwindstack/include/unwindstack/Global.h b/libunwindstack/include/unwindstack/Global.h
deleted file mode 100644
index b9bb141..0000000
--- a/libunwindstack/include/unwindstack/Global.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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_GLOBAL_H
-#define _LIBUNWINDSTACK_GLOBAL_H
-
-#include <stdint.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Maps;
-struct MapInfo;
-
-class Global {
- public:
- explicit Global(std::shared_ptr<Memory>& memory);
- Global(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
- virtual ~Global() = default;
-
- void SetArch(ArchEnum arch);
-
- ArchEnum arch() { return arch_; }
-
- protected:
- bool Searchable(const std::string& name);
- void FindAndReadVariable(Maps* maps, const char* variable);
-
- virtual bool ReadVariableData(uint64_t offset) = 0;
-
- virtual void ProcessArch() = 0;
-
- ArchEnum arch_ = ARCH_UNKNOWN;
-
- std::shared_ptr<Memory> memory_;
- std::vector<std::string> search_libs_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_GLOBAL_H
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
deleted file mode 100644
index 8b7b4b5..0000000
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2017 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_JIT_DEBUG_H
-#define _LIBUNWINDSTACK_JIT_DEBUG_H
-
-#include <stdint.h>
-
-#include <memory>
-#include <mutex>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Global.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Elf;
-class Maps;
-enum ArchEnum : uint8_t;
-
-class JitDebug : public Global {
- public:
- explicit JitDebug(std::shared_ptr<Memory>& memory);
- JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
- virtual ~JitDebug();
-
- Elf* GetElf(Maps* maps, uint64_t pc);
-
- 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
-
-#endif // _LIBUNWINDSTACK_JIT_DEBUG_H
diff --git a/libunwindstack/include/unwindstack/LocalUnwinder.h b/libunwindstack/include/unwindstack/LocalUnwinder.h
deleted file mode 100644
index 80bb53e..0000000
--- a/libunwindstack/include/unwindstack/LocalUnwinder.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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_LOCAL_UNWINDER_H
-#define _LIBUNWINDSTACK_LOCAL_UNWINDER_H
-
-#include <pthread.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/Error.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Elf;
-struct MapInfo;
-
-struct LocalFrameData {
- LocalFrameData(MapInfo* map_info, uint64_t pc, uint64_t rel_pc, const std::string& function_name,
- uint64_t function_offset)
- : map_info(map_info),
- pc(pc),
- rel_pc(rel_pc),
- function_name(function_name),
- function_offset(function_offset) {}
-
- MapInfo* map_info;
- uint64_t pc;
- uint64_t rel_pc;
- std::string function_name;
- uint64_t function_offset;
-};
-
-// This is a specialized class that should only be used for doing local unwinds.
-// The Unwind call can be made as multiple times on the same object, and it can
-// be called by multiple threads at the same time.
-// It is designed to be used in debugging circumstances to get a stack trace
-// as fast as possible.
-class LocalUnwinder {
- public:
- LocalUnwinder() = default;
- LocalUnwinder(const std::vector<std::string>& skip_libraries) : skip_libraries_(skip_libraries) {}
- ~LocalUnwinder() = default;
-
- bool Init();
-
- bool Unwind(std::vector<LocalFrameData>* frame_info, size_t max_frames);
-
- bool ShouldSkipLibrary(const std::string& map_name);
-
- MapInfo* GetMapInfo(uint64_t pc);
-
- ErrorCode LastErrorCode() { return last_error_.code; }
- uint64_t LastErrorAddress() { return last_error_.address; }
-
- private:
- pthread_rwlock_t maps_rwlock_;
- std::unique_ptr<LocalUpdatableMaps> maps_ = nullptr;
- std::shared_ptr<Memory> process_memory_;
- std::vector<std::string> skip_libraries_;
- ErrorData last_error_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_LOCAL_UNWINDER_H
diff --git a/libunwindstack/include/unwindstack/Log.h b/libunwindstack/include/unwindstack/Log.h
deleted file mode 100644
index aa1219c..0000000
--- a/libunwindstack/include/unwindstack/Log.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_LOG_H
-#define _LIBUNWINDSTACK_LOG_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-void log_to_stdout(bool enable);
-void log(uint8_t indent, const char* format, ...);
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_LOG_H
diff --git a/libunwindstack/include/unwindstack/MachineArm.h b/libunwindstack/include/unwindstack/MachineArm.h
deleted file mode 100644
index 3f902b1..0000000
--- a/libunwindstack/include/unwindstack/MachineArm.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 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_MACHINE_ARM_H
-#define _LIBUNWINDSTACK_MACHINE_ARM_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum ArmReg : uint16_t {
- ARM_REG_R0 = 0,
- ARM_REG_R1,
- ARM_REG_R2,
- ARM_REG_R3,
- ARM_REG_R4,
- ARM_REG_R5,
- ARM_REG_R6,
- ARM_REG_R7,
- ARM_REG_R8,
- ARM_REG_R9,
- ARM_REG_R10,
- ARM_REG_R11,
- ARM_REG_R12,
- ARM_REG_R13,
- ARM_REG_R14,
- ARM_REG_R15,
- ARM_REG_LAST,
-
- ARM_REG_SP = ARM_REG_R13,
- ARM_REG_LR = ARM_REG_R14,
- ARM_REG_PC = ARM_REG_R15,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_ARM_H
diff --git a/libunwindstack/include/unwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h
deleted file mode 100644
index 358e3d9..0000000
--- a/libunwindstack/include/unwindstack/MachineArm64.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 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_MACHINE_ARM64_H
-#define _LIBUNWINDSTACK_MACHINE_ARM64_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum Arm64Reg : uint16_t {
- ARM64_REG_R0 = 0,
- ARM64_REG_R1,
- ARM64_REG_R2,
- ARM64_REG_R3,
- ARM64_REG_R4,
- ARM64_REG_R5,
- ARM64_REG_R6,
- ARM64_REG_R7,
- ARM64_REG_R8,
- ARM64_REG_R9,
- ARM64_REG_R10,
- ARM64_REG_R11,
- ARM64_REG_R12,
- ARM64_REG_R13,
- ARM64_REG_R14,
- ARM64_REG_R15,
- ARM64_REG_R16,
- ARM64_REG_R17,
- ARM64_REG_R18,
- ARM64_REG_R19,
- ARM64_REG_R20,
- ARM64_REG_R21,
- ARM64_REG_R22,
- ARM64_REG_R23,
- ARM64_REG_R24,
- ARM64_REG_R25,
- ARM64_REG_R26,
- ARM64_REG_R27,
- ARM64_REG_R28,
- ARM64_REG_R29,
- ARM64_REG_R30,
- ARM64_REG_R31,
- ARM64_REG_PC,
- ARM64_REG_PSTATE,
- ARM64_REG_LAST,
-
- ARM64_REG_SP = ARM64_REG_R31,
- ARM64_REG_LR = ARM64_REG_R30,
-
- // Pseudo registers. These are not machine registers.
-
- // AARCH64 Return address signed state pseudo-register
- ARM64_PREG_RA_SIGN_STATE = 34,
- ARM64_PREG_FIRST = ARM64_PREG_RA_SIGN_STATE,
- ARM64_PREG_LAST,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_ARM64_H
diff --git a/libunwindstack/include/unwindstack/MachineMips.h b/libunwindstack/include/unwindstack/MachineMips.h
deleted file mode 100644
index 2dfb1e9..0000000
--- a/libunwindstack/include/unwindstack/MachineMips.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 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_MACHINE_MIPS_H
-#define _LIBUNWINDSTACK_MACHINE_MIPS_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum MipsReg : uint16_t {
- MIPS_REG_R0 = 0,
- MIPS_REG_R1,
- MIPS_REG_R2,
- MIPS_REG_R3,
- MIPS_REG_R4,
- MIPS_REG_R5,
- MIPS_REG_R6,
- MIPS_REG_R7,
- MIPS_REG_R8,
- MIPS_REG_R9,
- MIPS_REG_R10,
- MIPS_REG_R11,
- MIPS_REG_R12,
- MIPS_REG_R13,
- MIPS_REG_R14,
- MIPS_REG_R15,
- MIPS_REG_R16,
- MIPS_REG_R17,
- MIPS_REG_R18,
- MIPS_REG_R19,
- MIPS_REG_R20,
- MIPS_REG_R21,
- MIPS_REG_R22,
- MIPS_REG_R23,
- MIPS_REG_R24,
- MIPS_REG_R25,
- MIPS_REG_R26,
- MIPS_REG_R27,
- MIPS_REG_R28,
- MIPS_REG_R29,
- MIPS_REG_R30,
- MIPS_REG_R31,
- MIPS_REG_PC,
- MIPS_REG_LAST,
-
- MIPS_REG_SP = MIPS_REG_R29,
- MIPS_REG_RA = MIPS_REG_R31,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_MIPS_H
\ No newline at end of file
diff --git a/libunwindstack/include/unwindstack/MachineMips64.h b/libunwindstack/include/unwindstack/MachineMips64.h
deleted file mode 100644
index 34addf2..0000000
--- a/libunwindstack/include/unwindstack/MachineMips64.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2017 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_MACHINE_MIPS64_H
-#define _LIBUNWINDSTACK_MACHINE_MIPS64_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-enum Mips64Reg : uint16_t {
- MIPS64_REG_R0 = 0,
- MIPS64_REG_R1,
- MIPS64_REG_R2,
- MIPS64_REG_R3,
- MIPS64_REG_R4,
- MIPS64_REG_R5,
- MIPS64_REG_R6,
- MIPS64_REG_R7,
- MIPS64_REG_R8,
- MIPS64_REG_R9,
- MIPS64_REG_R10,
- MIPS64_REG_R11,
- MIPS64_REG_R12,
- MIPS64_REG_R13,
- MIPS64_REG_R14,
- MIPS64_REG_R15,
- MIPS64_REG_R16,
- MIPS64_REG_R17,
- MIPS64_REG_R18,
- MIPS64_REG_R19,
- MIPS64_REG_R20,
- MIPS64_REG_R21,
- MIPS64_REG_R22,
- MIPS64_REG_R23,
- MIPS64_REG_R24,
- MIPS64_REG_R25,
- MIPS64_REG_R26,
- MIPS64_REG_R27,
- MIPS64_REG_R28,
- MIPS64_REG_R29,
- MIPS64_REG_R30,
- MIPS64_REG_R31,
- MIPS64_REG_PC,
- MIPS64_REG_LAST,
-
- MIPS64_REG_SP = MIPS64_REG_R29,
- MIPS64_REG_RA = MIPS64_REG_R31,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_MIPS64_H
\ No newline at end of file
diff --git a/libunwindstack/include/unwindstack/MachineX86.h b/libunwindstack/include/unwindstack/MachineX86.h
deleted file mode 100644
index 02adb98..0000000
--- a/libunwindstack/include/unwindstack/MachineX86.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2017 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_MACHINE_X86_H
-#define _LIBUNWINDSTACK_MACHINE_X86_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86Reg : uint16_t {
- X86_REG_EAX = 0,
- X86_REG_ECX = 1,
- X86_REG_EDX = 2,
- X86_REG_EBX = 3,
- X86_REG_ESP = 4,
- X86_REG_EBP = 5,
- X86_REG_ESI = 6,
- X86_REG_EDI = 7,
- X86_REG_EIP = 8,
- X86_REG_EFL = 9,
- X86_REG_CS = 10,
- X86_REG_SS = 11,
- X86_REG_DS = 12,
- X86_REG_ES = 13,
- X86_REG_FS = 14,
- X86_REG_GS = 15,
- X86_REG_LAST,
-
- X86_REG_SP = X86_REG_ESP,
- X86_REG_PC = X86_REG_EIP,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_X86_H
diff --git a/libunwindstack/include/unwindstack/MachineX86_64.h b/libunwindstack/include/unwindstack/MachineX86_64.h
deleted file mode 100644
index af33fea..0000000
--- a/libunwindstack/include/unwindstack/MachineX86_64.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 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_MACHINE_X86_64_H
-#define _LIBUNWINDSTACK_MACHINE_X86_64_H
-
-#include <stdint.h>
-
-namespace unwindstack {
-
-// Matches the numbers for the registers as generated by compilers.
-// If this is changed, then unwinding will fail.
-enum X86_64Reg : uint16_t {
- X86_64_REG_RAX = 0,
- X86_64_REG_RDX = 1,
- X86_64_REG_RCX = 2,
- X86_64_REG_RBX = 3,
- X86_64_REG_RSI = 4,
- X86_64_REG_RDI = 5,
- X86_64_REG_RBP = 6,
- X86_64_REG_RSP = 7,
- X86_64_REG_R8 = 8,
- X86_64_REG_R9 = 9,
- X86_64_REG_R10 = 10,
- X86_64_REG_R11 = 11,
- X86_64_REG_R12 = 12,
- X86_64_REG_R13 = 13,
- X86_64_REG_R14 = 14,
- X86_64_REG_R15 = 15,
- X86_64_REG_RIP = 16,
- X86_64_REG_LAST,
-
- X86_64_REG_SP = X86_64_REG_RSP,
- X86_64_REG_PC = X86_64_REG_RIP,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MACHINE_X86_64_H
diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h
deleted file mode 100644
index 052e79f..0000000
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_MAP_INFO_H
-#define _LIBUNWINDSTACK_MAP_INFO_H
-
-#include <stdint.h>
-
-#include <atomic>
-#include <memory>
-#include <mutex>
-#include <string>
-
-#include <unwindstack/Elf.h>
-
-namespace unwindstack {
-
-class MemoryFileAtOffset;
-
-struct MapInfo {
- MapInfo(MapInfo* prev_map, MapInfo* prev_real_map, uint64_t start, uint64_t end, uint64_t offset,
- uint64_t flags, const char* name)
- : start(start),
- end(end),
- offset(offset),
- flags(flags),
- name(name),
- prev_map(prev_map),
- prev_real_map(prev_real_map),
- load_bias(INT64_MAX),
- build_id(0) {}
- MapInfo(MapInfo* prev_map, MapInfo* prev_real_map, uint64_t start, uint64_t end, uint64_t offset,
- uint64_t flags, const std::string& name)
- : start(start),
- end(end),
- offset(offset),
- flags(flags),
- name(name),
- prev_map(prev_map),
- prev_real_map(prev_real_map),
- load_bias(INT64_MAX),
- build_id(0) {}
- ~MapInfo();
-
- uint64_t start = 0;
- uint64_t end = 0;
- uint64_t offset = 0;
- uint16_t flags = 0;
- std::string name;
- std::shared_ptr<Elf> elf;
- // The offset of the beginning of this mapping to the beginning of the
- // ELF file.
- // elf_offset == offset - elf_start_offset.
- // This value is only non-zero if the offset is non-zero but there is
- // no elf signature found at that offset.
- uint64_t elf_offset = 0;
- // This value is the offset into the file of the map in memory that is the
- // start of the elf. This is not equal to offset when the linker splits
- // shared libraries into a read-only and read-execute map.
- uint64_t elf_start_offset = 0;
-
- MapInfo* prev_map = nullptr;
- // This is the previous map that is not empty with a 0 offset. For
- // example, this set of maps:
- // 1000-2000 r--p 000000 00:00 0 libc.so
- // 2000-3000 ---p 000000 00:00 0 libc.so
- // 3000-4000 r-xp 003000 00:00 0 libc.so
- // The last map's prev_map would point to the 2000-3000 map, while the
- // prev_real_map would point to the 1000-2000 map.
- MapInfo* prev_real_map = nullptr;
-
- std::atomic_int64_t load_bias;
-
- // This is a pointer to a new'd std::string.
- // Using an atomic value means that we don't need to lock and will
- // make it easier to move to a fine grained lock in the future.
- std::atomic_uintptr_t build_id;
-
- // Set to true if the elf file data is coming from memory.
- bool memory_backed_elf = false;
-
- // This function guarantees it will never return nullptr.
- Elf* GetElf(const std::shared_ptr<Memory>& process_memory, ArchEnum expected_arch);
-
- uint64_t GetLoadBias(const std::shared_ptr<Memory>& process_memory);
-
- Memory* CreateMemory(const std::shared_ptr<Memory>& process_memory);
-
- bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset);
-
- // Returns the raw build id read from the elf data.
- std::string GetBuildID();
-
- // Returns the printable version of the build id (hex dump of raw data).
- std::string GetPrintableBuildID();
-
- inline bool IsBlank() { return offset == 0 && flags == 0 && name.empty(); }
-
- private:
- MapInfo(const MapInfo&) = delete;
- void operator=(const MapInfo&) = delete;
-
- Memory* GetFileMemory();
- bool InitFileMemoryFromPreviousReadOnlyMap(MemoryFileAtOffset* memory);
-
- // Protect the creation of the elf object.
- std::mutex mutex_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MAP_INFO_H
diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h
deleted file mode 100644
index e53f367..0000000
--- a/libunwindstack/include/unwindstack/Maps.h
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_MAPS_H
-#define _LIBUNWINDSTACK_MAPS_H
-
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/MapInfo.h>
-
-namespace unwindstack {
-
-// Special flag to indicate a map is in /dev/. However, a map in
-// /dev/ashmem/... does not set this flag.
-static constexpr int MAPS_FLAGS_DEVICE_MAP = 0x8000;
-// Special flag to indicate that this map represents an elf file
-// created by ART for use with the gdb jit debug interface.
-// This should only ever appear in offline maps data.
-static constexpr int MAPS_FLAGS_JIT_SYMFILE_MAP = 0x4000;
-
-class Maps {
- public:
- virtual ~Maps() = default;
-
- Maps() = default;
-
- // Maps are not copyable but movable, because they own pointers to MapInfo
- // objects.
- Maps(const Maps&) = delete;
- Maps& operator=(const Maps&) = delete;
- Maps(Maps&&) = default;
- Maps& operator=(Maps&&) = default;
-
- MapInfo* Find(uint64_t pc);
-
- virtual bool Parse();
-
- virtual const std::string GetMapsFile() const { return ""; }
-
- void Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const std::string& name,
- uint64_t load_bias);
-
- void Sort();
-
- typedef std::vector<std::unique_ptr<MapInfo>>::iterator iterator;
- iterator begin() { return maps_.begin(); }
- iterator end() { return maps_.end(); }
-
- typedef std::vector<std::unique_ptr<MapInfo>>::const_iterator const_iterator;
- const_iterator begin() const { return maps_.begin(); }
- const_iterator end() const { return maps_.end(); }
-
- size_t Total() { return maps_.size(); }
-
- MapInfo* Get(size_t index) {
- if (index >= maps_.size()) return nullptr;
- return maps_[index].get();
- }
-
- protected:
- std::vector<std::unique_ptr<MapInfo>> maps_;
-};
-
-class RemoteMaps : public Maps {
- public:
- RemoteMaps(pid_t pid) : pid_(pid) {}
- virtual ~RemoteMaps() = default;
-
- virtual const std::string GetMapsFile() const override;
-
- private:
- pid_t pid_;
-};
-
-class LocalMaps : public RemoteMaps {
- public:
- LocalMaps() : RemoteMaps(getpid()) {}
- virtual ~LocalMaps() = default;
-};
-
-class LocalUpdatableMaps : public Maps {
- public:
- LocalUpdatableMaps() : Maps() {}
- virtual ~LocalUpdatableMaps() = default;
-
- bool Reparse();
-
- const std::string GetMapsFile() const override;
-
- protected:
- std::vector<std::unique_ptr<MapInfo>> saved_maps_;
-};
-
-class BufferMaps : public Maps {
- public:
- BufferMaps(const char* buffer) : buffer_(buffer) {}
- virtual ~BufferMaps() = default;
-
- bool Parse() override;
-
- private:
- const char* buffer_;
-};
-
-class FileMaps : public Maps {
- public:
- FileMaps(const std::string& file) : file_(file) {}
- virtual ~FileMaps() = default;
-
- const std::string GetMapsFile() const override { return file_; }
-
- protected:
- const std::string file_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MAPS_H
diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h
deleted file mode 100644
index 3d81878..0000000
--- a/libunwindstack/include/unwindstack/Memory.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_MEMORY_H
-#define _LIBUNWINDSTACK_MEMORY_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-
-namespace unwindstack {
-
-class Memory {
- public:
- Memory() = default;
- virtual ~Memory() = default;
-
- static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
- static std::shared_ptr<Memory> CreateProcessMemoryCached(pid_t pid);
- static std::shared_ptr<Memory> CreateOfflineMemory(const uint8_t* data, uint64_t start,
- uint64_t end);
- static std::unique_ptr<Memory> CreateFileMemory(const std::string& path, uint64_t offset);
-
- virtual bool ReadString(uint64_t addr, std::string* dst, size_t max_read);
-
- virtual void Clear() {}
-
- virtual bool IsLocal() const { return false; }
-
- virtual size_t Read(uint64_t addr, void* dst, size_t size) = 0;
- virtual long ReadTag(uint64_t) { return -1; }
-
- bool ReadFully(uint64_t addr, void* dst, size_t size);
-
- inline bool Read32(uint64_t addr, uint32_t* dst) {
- return ReadFully(addr, dst, sizeof(uint32_t));
- }
-
- inline bool Read64(uint64_t addr, uint64_t* dst) {
- return ReadFully(addr, dst, sizeof(uint64_t));
- }
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_MEMORY_H
diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h
deleted file mode 100644
index 5f42565..0000000
--- a/libunwindstack/include/unwindstack/Regs.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_REGS_H
-#define _LIBUNWINDSTACK_REGS_H
-
-#include <stdint.h>
-#include <unistd.h>
-
-#include <functional>
-#include <string>
-#include <vector>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Elf;
-enum ArchEnum : uint8_t;
-class Memory;
-
-class Regs {
- public:
- enum LocationEnum : uint8_t {
- LOCATION_UNKNOWN = 0,
- LOCATION_REGISTER,
- LOCATION_SP_OFFSET,
- };
-
- struct Location {
- Location(LocationEnum type, int16_t value) : type(type), value(value) {}
-
- LocationEnum type;
- int16_t value;
- };
-
- Regs(uint16_t total_regs, const Location& return_loc)
- : total_regs_(total_regs), return_loc_(return_loc) {}
- virtual ~Regs() = default;
-
- virtual ArchEnum Arch() = 0;
-
- virtual bool Is32Bit() = 0;
-
- virtual void* RawData() = 0;
- virtual uint64_t pc() = 0;
- virtual uint64_t sp() = 0;
-
- virtual void set_pc(uint64_t pc) = 0;
- virtual void set_sp(uint64_t sp) = 0;
-
- uint64_t dex_pc() { return dex_pc_; }
- void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
-
- virtual void ResetPseudoRegisters() {}
- virtual bool SetPseudoRegister(uint16_t, uint64_t) { return false; }
- virtual bool GetPseudoRegister(uint16_t, uint64_t*) { return false; }
-
- virtual bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) = 0;
-
- virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0;
-
- virtual void IterateRegisters(std::function<void(const char*, uint64_t)>) = 0;
-
- uint16_t total_regs() { return total_regs_; }
-
- virtual Regs* Clone() = 0;
-
- static ArchEnum CurrentArch();
- static Regs* RemoteGet(pid_t pid);
- static Regs* CreateFromUcontext(ArchEnum arch, void* ucontext);
- static Regs* CreateFromLocal();
-
- protected:
- uint16_t total_regs_;
- Location return_loc_;
- uint64_t dex_pc_ = 0;
-};
-
-template <typename AddressType>
-class RegsImpl : public Regs {
- public:
- RegsImpl(uint16_t total_regs, Location return_loc)
- : Regs(total_regs, return_loc), regs_(total_regs) {}
- virtual ~RegsImpl() = default;
-
- bool Is32Bit() override { return sizeof(AddressType) == sizeof(uint32_t); }
-
- inline AddressType& operator[](size_t reg) { return regs_[reg]; }
-
- void* RawData() override { return regs_.data(); }
-
- virtual void IterateRegisters(std::function<void(const char*, uint64_t)> fn) override {
- for (size_t i = 0; i < regs_.size(); ++i) {
- fn(std::to_string(i).c_str(), regs_[i]);
- }
- }
-
- protected:
- std::vector<AddressType> regs_;
-};
-
-uint64_t GetPcAdjustment(uint64_t rel_pc, Elf* elf, ArchEnum arch);
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_H
diff --git a/libunwindstack/include/unwindstack/RegsArm.h b/libunwindstack/include/unwindstack/RegsArm.h
deleted file mode 100644
index fbb34e7..0000000
--- a/libunwindstack/include/unwindstack/RegsArm.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_REGS_ARM_H
-#define _LIBUNWINDSTACK_REGS_ARM_H
-
-#include <stdint.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-
-class RegsArm : public RegsImpl<uint32_t> {
- public:
- RegsArm();
- virtual ~RegsArm() = default;
-
- ArchEnum Arch() override final;
-
- bool SetPcFromReturnAddress(Memory* process_memory) override;
-
- bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
-
- void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-
- uint64_t pc() override;
- uint64_t sp() override;
-
- void set_pc(uint64_t pc) override;
- void set_sp(uint64_t sp) override;
-
- Regs* Clone() override final;
-
- static Regs* Read(void* data);
-
- static Regs* CreateFromUcontext(void* ucontext);
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_ARM_H
diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h
deleted file mode 100644
index bf7ab15..0000000
--- a/libunwindstack/include/unwindstack/RegsArm64.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_REGS_ARM64_H
-#define _LIBUNWINDSTACK_REGS_ARM64_H
-
-#include <stdint.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineArm64.h>
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-
-class RegsArm64 : public RegsImpl<uint64_t> {
- public:
- RegsArm64();
- virtual ~RegsArm64() = default;
-
- ArchEnum Arch() override final;
-
- bool SetPcFromReturnAddress(Memory* process_memory) override;
-
- bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
-
- void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-
- uint64_t pc() override;
- uint64_t sp() override;
-
- void set_pc(uint64_t pc) override;
- void set_sp(uint64_t sp) override;
-
- void ResetPseudoRegisters() override;
-
- bool SetPseudoRegister(uint16_t id, uint64_t value) override;
-
- bool GetPseudoRegister(uint16_t id, uint64_t* value) override;
-
- bool IsRASigned();
-
- void SetPACMask(uint64_t mask);
-
- Regs* Clone() override final;
-
- static Regs* Read(void* data);
-
- static Regs* CreateFromUcontext(void* ucontext);
-
- protected:
- uint64_t pseudo_regs_[Arm64Reg::ARM64_PREG_LAST - Arm64Reg::ARM64_PREG_FIRST];
- uint64_t pac_mask_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_ARM64_H
diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h
deleted file mode 100644
index 300a3ec..0000000
--- a/libunwindstack/include/unwindstack/RegsGetLocal.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_REGS_GET_LOCAL_H
-#define _LIBUNWINDSTACK_REGS_GET_LOCAL_H
-
-namespace unwindstack {
-
-#if defined(__arm__)
-
-inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
- asm volatile(
- ".align 2\n"
- "bx pc\n"
- "nop\n"
- ".code 32\n"
- "stmia %[base], {r0-r12}\n"
- "add %[base], #52\n"
- "mov r1, r13\n"
- "mov r2, r14\n"
- "mov r3, r15\n"
- "stmia %[base], {r1-r3}\n"
- "orr %[base], pc, #1\n"
- "bx %[base]\n"
- : [base] "+r"(reg_data)
- :
- : "memory");
-}
-
-#elif defined(__aarch64__)
-
-inline __attribute__((__always_inline__)) void AsmGetRegs(void* reg_data) {
- asm volatile(
- "1:\n"
- "stp x0, x1, [%[base], #0]\n"
- "stp x2, x3, [%[base], #16]\n"
- "stp x4, x5, [%[base], #32]\n"
- "stp x6, x7, [%[base], #48]\n"
- "stp x8, x9, [%[base], #64]\n"
- "stp x10, x11, [%[base], #80]\n"
- "stp x12, x13, [%[base], #96]\n"
- "stp x14, x15, [%[base], #112]\n"
- "stp x16, x17, [%[base], #128]\n"
- "stp x18, x19, [%[base], #144]\n"
- "stp x20, x21, [%[base], #160]\n"
- "stp x22, x23, [%[base], #176]\n"
- "stp x24, x25, [%[base], #192]\n"
- "stp x26, x27, [%[base], #208]\n"
- "stp x28, x29, [%[base], #224]\n"
- "str x30, [%[base], #240]\n"
- "mov x12, sp\n"
- "adr x13, 1b\n"
- "stp x12, x13, [%[base], #248]\n"
- : [base] "+r"(reg_data)
- :
- : "x12", "x13", "memory");
-}
-
-#elif defined(__i386__) || defined(__x86_64__)
-
-extern "C" void AsmGetRegs(void* regs);
-
-#endif
-
-inline __attribute__((__always_inline__)) void RegsGetLocal(Regs* regs) {
- AsmGetRegs(regs->RawData());
-}
-
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_GET_LOCAL_H
diff --git a/libunwindstack/include/unwindstack/RegsMips.h b/libunwindstack/include/unwindstack/RegsMips.h
deleted file mode 100644
index dc09b83..0000000
--- a/libunwindstack/include/unwindstack/RegsMips.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 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_REGS_MIPS_H
-#define _LIBUNWINDSTACK_REGS_MIPS_H
-
-#include <stdint.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-
-class RegsMips : public RegsImpl<uint32_t> {
- public:
- RegsMips();
- virtual ~RegsMips() = default;
-
- ArchEnum Arch() override final;
-
- bool SetPcFromReturnAddress(Memory* process_memory) override;
-
- bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
-
- void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-
- uint64_t pc() override;
- uint64_t sp() override;
-
- void set_pc(uint64_t pc) override;
- void set_sp(uint64_t sp) override;
-
- Regs* Clone() override final;
-
- static Regs* Read(void* data);
-
- static Regs* CreateFromUcontext(void* ucontext);
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_MIPS_H
diff --git a/libunwindstack/include/unwindstack/RegsMips64.h b/libunwindstack/include/unwindstack/RegsMips64.h
deleted file mode 100644
index 64a80dc..0000000
--- a/libunwindstack/include/unwindstack/RegsMips64.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2017 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_REGS_MIPS64_H
-#define _LIBUNWINDSTACK_REGS_MIPS64_H
-
-#include <stdint.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-
-class RegsMips64 : public RegsImpl<uint64_t> {
- public:
- RegsMips64();
- virtual ~RegsMips64() = default;
-
- ArchEnum Arch() override final;
-
- bool SetPcFromReturnAddress(Memory* process_memory) override;
-
- bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
-
- void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-
- uint64_t pc() override;
- uint64_t sp() override;
-
- void set_pc(uint64_t pc) override;
- void set_sp(uint64_t sp) override;
-
- Regs* Clone() override final;
-
- static Regs* Read(void* data);
-
- static Regs* CreateFromUcontext(void* ucontext);
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/RegsX86.h b/libunwindstack/include/unwindstack/RegsX86.h
deleted file mode 100644
index cfbdda6..0000000
--- a/libunwindstack/include/unwindstack/RegsX86.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_REGS_X86_H
-#define _LIBUNWINDSTACK_REGS_X86_H
-
-#include <stdint.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-struct x86_ucontext_t;
-
-class RegsX86 : public RegsImpl<uint32_t> {
- public:
- RegsX86();
- virtual ~RegsX86() = default;
-
- ArchEnum Arch() override final;
-
- bool SetPcFromReturnAddress(Memory* process_memory) override;
-
- bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
-
- void SetFromUcontext(x86_ucontext_t* ucontext);
-
- void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-
- uint64_t pc() override;
- uint64_t sp() override;
-
- void set_pc(uint64_t pc) override;
- void set_sp(uint64_t sp) override;
-
- Regs* Clone() override final;
-
- static Regs* Read(void* data);
-
- static Regs* CreateFromUcontext(void* ucontext);
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_X86_H
diff --git a/libunwindstack/include/unwindstack/RegsX86_64.h b/libunwindstack/include/unwindstack/RegsX86_64.h
deleted file mode 100644
index a11aef0..0000000
--- a/libunwindstack/include/unwindstack/RegsX86_64.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_REGS_X86_64_H
-#define _LIBUNWINDSTACK_REGS_X86_64_H
-
-#include <stdint.h>
-
-#include <functional>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Memory;
-struct x86_64_ucontext_t;
-
-class RegsX86_64 : public RegsImpl<uint64_t> {
- public:
- RegsX86_64();
- virtual ~RegsX86_64() = default;
-
- ArchEnum Arch() override final;
-
- bool SetPcFromReturnAddress(Memory* process_memory) override;
-
- bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) override;
-
- void SetFromUcontext(x86_64_ucontext_t* ucontext);
-
- void IterateRegisters(std::function<void(const char*, uint64_t)>) override final;
-
- uint64_t pc() override;
- uint64_t sp() override;
-
- void set_pc(uint64_t pc) override;
- void set_sp(uint64_t sp) override;
-
- Regs* Clone() override final;
-
- static Regs* Read(void* data);
-
- static Regs* CreateFromUcontext(void* ucontext);
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_REGS_X86_64_H
diff --git a/libunwindstack/include/unwindstack/UcontextArm.h b/libunwindstack/include/unwindstack/UcontextArm.h
deleted file mode 100644
index 7d1ec3b..0000000
--- a/libunwindstack/include/unwindstack/UcontextArm.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM_H
-#define _LIBUNWINDSTACK_UCONTEXT_ARM_H
-
-#include <stdint.h>
-
-#include <unwindstack/MachineArm.h>
-
-namespace unwindstack {
-
-struct arm_stack_t {
- uint32_t ss_sp; // void __user*
- int32_t ss_flags; // int
- uint32_t ss_size; // size_t
-};
-
-struct arm_mcontext_t {
- uint32_t trap_no; // unsigned long
- uint32_t error_code; // unsigned long
- uint32_t oldmask; // unsigned long
- uint32_t regs[ARM_REG_LAST]; // unsigned long
- uint32_t cpsr; // unsigned long
- uint32_t fault_address; // unsigned long
-};
-
-struct arm_ucontext_t {
- uint32_t uc_flags; // unsigned long
- uint32_t uc_link; // struct ucontext*
- arm_stack_t uc_stack;
- arm_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_ARM_H
diff --git a/libunwindstack/include/unwindstack/UcontextArm64.h b/libunwindstack/include/unwindstack/UcontextArm64.h
deleted file mode 100644
index a68be3b..0000000
--- a/libunwindstack/include/unwindstack/UcontextArm64.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_ARM64_H
-#define _LIBUNWINDSTACK_UCONTEXT_ARM64_H
-
-#include <stdint.h>
-
-#include <unwindstack/MachineArm64.h>
-
-namespace unwindstack {
-
-struct arm64_stack_t {
- uint64_t ss_sp; // void __user*
- int32_t ss_flags; // int
- uint64_t ss_size; // size_t
-};
-
-struct arm64_sigset_t {
- uint64_t sig; // unsigned long
-};
-
-struct arm64_mcontext_t {
- uint64_t fault_address; // __u64
- uint64_t regs[ARM64_REG_LAST]; // __u64
- uint64_t pstate; // __u64
- // Nothing else is used, so don't define it.
-};
-
-struct arm64_ucontext_t {
- uint64_t uc_flags; // unsigned long
- uint64_t uc_link; // struct ucontext*
- arm64_stack_t uc_stack;
- arm64_sigset_t uc_sigmask;
- // The kernel adds extra padding after uc_sigmask to match glibc sigset_t on ARM64.
- char __padding[128 - sizeof(arm64_sigset_t)];
- // The full structure requires 16 byte alignment, but our partial structure
- // doesn't, so force the alignment.
- arm64_mcontext_t uc_mcontext __attribute__((aligned(16)));
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_ARM64_H
diff --git a/libunwindstack/include/unwindstack/UcontextMips.h b/libunwindstack/include/unwindstack/UcontextMips.h
deleted file mode 100644
index 02e33b6..0000000
--- a/libunwindstack/include/unwindstack/UcontextMips.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS_H
-#define _LIBUNWINDSTACK_UCONTEXT_MIPS_H
-
-#include <stdint.h>
-
-#include <unwindstack/MachineMips.h>
-
-namespace unwindstack {
-
-struct mips_stack_t {
- uint32_t ss_sp; // void __user*
- uint32_t ss_size; // size_t
- int32_t ss_flags; // int
-};
-
-struct mips_mcontext_t {
- uint32_t sc_regmask;
- uint32_t sc_status;
- uint64_t sc_pc;
- uint64_t sc_regs[32];
- // Nothing else is used, so don't define it.
-};
-
-struct mips_ucontext_t {
- uint32_t uc_flags; // unsigned long
- uint32_t uc_link; // struct ucontext*
- mips_stack_t uc_stack;
- mips_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS_H
diff --git a/libunwindstack/include/unwindstack/UcontextMips64.h b/libunwindstack/include/unwindstack/UcontextMips64.h
deleted file mode 100644
index 5b92a55..0000000
--- a/libunwindstack/include/unwindstack/UcontextMips64.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
-#define _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
-
-#include <stdint.h>
-
-#include <unwindstack/MachineMips64.h>
-
-namespace unwindstack {
-
-struct mips64_stack_t {
- uint64_t ss_sp; // void __user*
- uint64_t ss_size; // size_t
- int32_t ss_flags; // int
-};
-
-struct mips64_mcontext_t {
- uint64_t sc_regs[32];
- uint64_t sc_fpregs[32];
- uint64_t sc_mdhi;
- uint64_t sc_hi1;
- uint64_t sc_hi2;
- uint64_t sc_hi3;
- uint64_t sc_mdlo;
- uint64_t sc_lo1;
- uint64_t sc_lo2;
- uint64_t sc_lo3;
- uint64_t sc_pc;
- // Nothing else is used, so don't define it.
-};
-
-struct mips64_ucontext_t {
- uint64_t uc_flags; // unsigned long
- uint64_t uc_link; // struct ucontext*
- mips64_stack_t uc_stack;
- mips64_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/UcontextX86.h b/libunwindstack/include/unwindstack/UcontextX86.h
deleted file mode 100644
index c96ebb7..0000000
--- a/libunwindstack/include/unwindstack/UcontextX86.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_H
-#define _LIBUNWINDSTACK_UCONTEXT_X86_H
-
-#include <stdint.h>
-
-#include <unwindstack/MachineX86.h>
-
-namespace unwindstack {
-
-struct x86_stack_t {
- uint32_t ss_sp; // void __user*
- int32_t ss_flags; // int
- uint32_t ss_size; // size_t
-};
-
-struct x86_mcontext_t {
- uint32_t gs;
- uint32_t fs;
- uint32_t es;
- uint32_t ds;
- uint32_t edi;
- uint32_t esi;
- uint32_t ebp;
- uint32_t esp;
- uint32_t ebx;
- uint32_t edx;
- uint32_t ecx;
- uint32_t eax;
- uint32_t trapno;
- uint32_t err;
- uint32_t eip;
- uint32_t cs;
- uint32_t efl;
- uint32_t uesp;
- uint32_t ss;
- // Only care about the registers, skip everything else.
-};
-
-struct x86_ucontext_t {
- uint32_t uc_flags; // unsigned long
- uint32_t uc_link; // struct ucontext*
- x86_stack_t uc_stack;
- x86_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_X86_H
diff --git a/libunwindstack/include/unwindstack/UcontextX86_64.h b/libunwindstack/include/unwindstack/UcontextX86_64.h
deleted file mode 100644
index 4e163e5..0000000
--- a/libunwindstack/include/unwindstack/UcontextX86_64.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_UCONTEXT_X86_64_H
-#define _LIBUNWINDSTACK_UCONTEXT_X86_64_H
-
-#include <stdint.h>
-
-#include <unwindstack/MachineX86_64.h>
-
-namespace unwindstack {
-
-struct x86_64_stack_t {
- uint64_t ss_sp; // void __user*
- int32_t ss_flags; // int
- int32_t pad;
- uint64_t ss_size; // size_t
-};
-
-struct x86_64_mcontext_t {
- uint64_t r8;
- uint64_t r9;
- uint64_t r10;
- uint64_t r11;
- uint64_t r12;
- uint64_t r13;
- uint64_t r14;
- uint64_t r15;
- uint64_t rdi;
- uint64_t rsi;
- uint64_t rbp;
- uint64_t rbx;
- uint64_t rdx;
- uint64_t rax;
- uint64_t rcx;
- uint64_t rsp;
- uint64_t rip;
- uint64_t efl;
- uint64_t csgsfs;
- uint64_t err;
- uint64_t trapno;
- uint64_t oldmask;
- uint64_t cr2;
- // Only care about the registers, skip everything else.
-};
-
-struct x86_64_ucontext_t {
- uint64_t uc_flags; // unsigned long
- uint64_t uc_link; // struct ucontext*
- x86_64_stack_t uc_stack;
- x86_64_mcontext_t uc_mcontext;
- // Nothing else is used, so don't define it.
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UCONTEXT_X86_64_H
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
deleted file mode 100644
index a974b63..0000000
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2017 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_UNWINDER_H
-#define _LIBUNWINDSTACK_UNWINDER_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <unwindstack/DexFiles.h>
-#include <unwindstack/Error.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-namespace unwindstack {
-
-// Forward declarations.
-class Elf;
-enum ArchEnum : uint8_t;
-
-struct FrameData {
- size_t num;
-
- uint64_t rel_pc;
- uint64_t pc;
- uint64_t sp;
-
- std::string function_name;
- uint64_t function_offset = 0;
-
- std::string map_name;
- // The offset from the first map representing the frame. When there are
- // two maps (read-only and read-execute) this will be the offset from
- // the read-only map. When there is only one map, this will be the
- // same as the actual offset of the map and match map_exact_offset.
- uint64_t map_elf_start_offset = 0;
- // The actual offset from the map where the pc lies.
- uint64_t map_exact_offset = 0;
- uint64_t map_start = 0;
- uint64_t map_end = 0;
- uint64_t map_load_bias = 0;
- int map_flags = 0;
-};
-
-class Unwinder {
- public:
- 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)
- : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) {
- frames_.reserve(max_frames);
- }
-
- virtual ~Unwinder() = default;
-
- void Unwind(const std::vector<std::string>* initial_map_names_to_skip = nullptr,
- const std::vector<std::string>* map_suffixes_to_ignore = nullptr);
-
- size_t NumFrames() const { return frames_.size(); }
-
- const std::vector<FrameData>& frames() { return frames_; }
-
- std::vector<FrameData> ConsumeFrames() {
- std::vector<FrameData> frames = std::move(frames_);
- frames_.clear();
- return frames;
- }
-
- std::string FormatFrame(size_t frame_num) const;
- std::string FormatFrame(const FrameData& frame) const;
-
- 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_; }
-
- // Disabling the resolving of names results in the function name being
- // set to an empty string and the function offset being set to zero.
- void SetResolveNames(bool resolve) { resolve_names_ = resolve; }
-
- // Enable/disable soname printing the soname for a map name if the elf is
- // embedded in a file. This is enabled by default.
- // NOTE: This does nothing unless resolving names is enabled.
- void SetEmbeddedSoname(bool embedded_soname) { embedded_soname_ = embedded_soname; }
-
- void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
-
- void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
-
- bool elf_from_memory_not_file() { return elf_from_memory_not_file_; }
-
- ErrorCode LastErrorCode() { return last_error_.code; }
- uint64_t LastErrorAddress() { return last_error_.address; }
- uint64_t warnings() { return warnings_; }
-
- // Builds a frame for symbolization using the maps from this unwinder. The
- // constructed frame contains just enough information to be used to symbolize
- // frames collected by frame-pointer unwinding that's done outside of
- // libunwindstack. This is used by tombstoned to symbolize frame pointer-based
- // stack traces that are collected by tools such as GWP-ASan and MTE.
- FrameData BuildFrameFromPcOnly(uint64_t pc);
-
- protected:
- Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); }
-
- void FillInDexFrame();
- FrameData* FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t pc_adjustment);
-
- size_t max_frames_;
- Maps* maps_;
- Regs* regs_;
- std::vector<FrameData> frames_;
- std::shared_ptr<Memory> process_memory_;
- JitDebug* jit_debug_ = nullptr;
- DexFiles* dex_files_ = nullptr;
- bool resolve_names_ = true;
- bool embedded_soname_ = true;
- bool display_build_id_ = false;
- // True if at least one elf file is coming from memory and not the related
- // file. This is only true if there is an actual file backing up the elf.
- bool elf_from_memory_not_file_ = false;
- ErrorData last_error_;
- uint64_t warnings_;
-};
-
-class UnwinderFromPid : public Unwinder {
- public:
- UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
- virtual ~UnwinderFromPid() = default;
-
- bool Init(ArchEnum arch);
-
- private:
- pid_t pid_;
- std::unique_ptr<Maps> maps_ptr_;
- std::unique_ptr<JitDebug> jit_debug_ptr_;
- std::unique_ptr<DexFiles> dex_files_ptr_;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_UNWINDER_H
diff --git a/libunwindstack/include/unwindstack/UserArm.h b/libunwindstack/include/unwindstack/UserArm.h
deleted file mode 100644
index 7388c03..0000000
--- a/libunwindstack/include/unwindstack/UserArm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_USER_ARM_H
-#define _LIBUNWINDSTACK_USER_ARM_H
-
-namespace unwindstack {
-
-struct arm_user_regs {
- uint32_t regs[18];
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_ARM_H
diff --git a/libunwindstack/include/unwindstack/UserArm64.h b/libunwindstack/include/unwindstack/UserArm64.h
deleted file mode 100644
index d74983f..0000000
--- a/libunwindstack/include/unwindstack/UserArm64.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_USER_ARM64_H
-#define _LIBUNWINDSTACK_USER_ARM64_H
-
-namespace unwindstack {
-
-struct arm64_user_regs {
- uint64_t regs[31];
- uint64_t sp;
- uint64_t pc;
- uint64_t pstate;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_ARM64_H
diff --git a/libunwindstack/include/unwindstack/UserMips.h b/libunwindstack/include/unwindstack/UserMips.h
deleted file mode 100644
index 184be4f..0000000
--- a/libunwindstack/include/unwindstack/UserMips.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_USER_MIPS_H
-#define _LIBUNWINDSTACK_USER_MIPS_H
-
-namespace unwindstack {
-
-enum Mips32UserReg : uint16_t {
- MIPS32_EF_R0 = 6,
- MIPS32_EF_CP0_EPC = 40,
-};
-
-struct mips_user_regs {
- uint32_t regs[45];
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_MIPS_H
diff --git a/libunwindstack/include/unwindstack/UserMips64.h b/libunwindstack/include/unwindstack/UserMips64.h
deleted file mode 100644
index c46befd..0000000
--- a/libunwindstack/include/unwindstack/UserMips64.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_USER_MIPS64_H
-#define _LIBUNWINDSTACK_USER_MIPS64_H
-
-namespace unwindstack {
-
-enum Mips64UserReg : uint16_t {
- MIPS64_EF_R0 = 0,
- MIPS64_EF_CP0_EPC = 34,
-};
-
-struct mips64_user_regs {
- uint64_t regs[45];
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_MIPS64_H
diff --git a/libunwindstack/include/unwindstack/UserX86.h b/libunwindstack/include/unwindstack/UserX86.h
deleted file mode 100644
index a040560..0000000
--- a/libunwindstack/include/unwindstack/UserX86.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_USER_X86_H
-#define _LIBUNWINDSTACK_USER_X86_H
-
-namespace unwindstack {
-
-struct x86_user_regs {
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- uint32_t esi;
- uint32_t edi;
- uint32_t ebp;
- uint32_t eax;
- uint32_t xds;
- uint32_t xes;
- uint32_t xfs;
- uint32_t xgs;
- uint32_t orig_eax;
- uint32_t eip;
- uint32_t xcs;
- uint32_t eflags;
- uint32_t esp;
- uint32_t xss;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_X86_H
diff --git a/libunwindstack/include/unwindstack/UserX86_64.h b/libunwindstack/include/unwindstack/UserX86_64.h
deleted file mode 100644
index b80d201..0000000
--- a/libunwindstack/include/unwindstack/UserX86_64.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBUNWINDSTACK_USER_X86_64_H
-#define _LIBUNWINDSTACK_USER_X86_64_H
-
-namespace unwindstack {
-
-struct x86_64_user_regs {
- uint64_t r15;
- uint64_t r14;
- uint64_t r13;
- uint64_t r12;
- uint64_t rbp;
- uint64_t rbx;
- uint64_t r11;
- uint64_t r10;
- uint64_t r9;
- uint64_t r8;
- uint64_t rax;
- uint64_t rcx;
- uint64_t rdx;
- uint64_t rsi;
- uint64_t rdi;
- uint64_t orig_rax;
- uint64_t rip;
- uint64_t cs;
- uint64_t eflags;
- uint64_t rsp;
- uint64_t ss;
- uint64_t fs_base;
- uint64_t gs_base;
- uint64_t ds;
- uint64_t es;
- uint64_t fs;
- uint64_t gs;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_USER_X86_64_H
diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
deleted file mode 100644
index 69a7816..0000000
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ /dev/null
@@ -1,1668 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <deque>
-#include <ios>
-#include <memory>
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Log.h>
-#include <unwindstack/RegsArm.h>
-
-#include "ArmExidx.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class ArmExidxDecodeTest : public ::testing::TestWithParam<std::string> {
- protected:
- void Init(Memory* process_memory = nullptr) {
- if (process_memory == nullptr) {
- process_memory = &process_memory_;
- }
-
- regs_arm_.reset(new RegsArm());
- for (size_t i = 0; i < regs_arm_->total_regs(); i++) {
- (*regs_arm_)[i] = 0;
- }
- regs_arm_->set_pc(0);
- regs_arm_->set_sp(0);
-
- exidx_.reset(new ArmExidx(regs_arm_.get(), &elf_memory_, process_memory));
- if (log_ != ARM_LOG_NONE) {
- exidx_->set_log(log_);
- exidx_->set_log_indent(0);
- exidx_->set_log_skip_execution(false);
- }
- data_ = exidx_->data();
- exidx_->set_cfa(0x10000);
- }
-
- void SetUp() override {
- if (GetParam() == "no_logging") {
- log_ = ARM_LOG_NONE;
- } else if (GetParam() == "register_logging") {
- log_ = ARM_LOG_BY_REG;
- } else {
- log_ = ARM_LOG_FULL;
- }
- elf_memory_.Clear();
- process_memory_.Clear();
- ResetExidx();
- }
-
- void ResetExidx() {
- ResetLogs();
- Init();
- }
-
- std::unique_ptr<ArmExidx> exidx_;
- std::unique_ptr<RegsArm> regs_arm_;
- std::deque<uint8_t>* data_;
-
- MemoryFake elf_memory_;
- MemoryFake process_memory_;
- ArmLogType log_;
-};
-
-TEST_P(ArmExidxDecodeTest, vsp_incr) {
- // 00xxxxxx: vsp = vsp + (xxxxxx << 2) + 4
- data_->push_back(0x00);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp + 4\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 + 4\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10004U, exidx_->cfa());
-
- ResetExidx();
- data_->clear();
- data_->push_back(0x01);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp + 8\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 + 8\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
-
- ResetExidx();
- data_->clear();
- data_->push_back(0x3f);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp + 256\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 + 256\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10100U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, vsp_decr) {
- // 01xxxxxx: vsp = vsp - (xxxxxx << 2) + 4
- data_->push_back(0x40);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp - 4\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 - 4\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0xfffcU, exidx_->cfa());
-
- ResetExidx();
- data_->clear();
- data_->push_back(0x41);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp - 8\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 - 8\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0xfff8U, exidx_->cfa());
-
- ResetExidx();
- data_->clear();
- data_->push_back(0x7f);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp - 256\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 - 256\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0xff00U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, refuse_unwind) {
- // 10000000 00000000: Refuse to unwind
- data_->push_back(0x80);
- data_->push_back(0x00);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Refuse to unwind\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(ARM_STATUS_NO_UNWIND, exidx_->status());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_up_to_12) {
- // 1000iiii iiiiiiii: Pop up to 12 integer registers
- data_->push_back(0x88);
- data_->push_back(0x00);
- process_memory_.SetData32(0x10000, 0x10);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_TRUE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r15}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 4\n"
- "4 unwind r15 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10004U, exidx_->cfa());
- ASSERT_EQ(0x10U, (*exidx_->regs())[15]);
-
- ResetExidx();
- data_->push_back(0x8f);
- data_->push_back(0xff);
- for (size_t i = 0; i < 12; i++) {
- process_memory_.SetData32(0x10000 + i * 4, i + 0x20);
- }
- exidx_->set_pc_set(false);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_TRUE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15}\n",
- GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 48\n"
- "4 unwind r4 = [cfa - 48]\n"
- "4 unwind r5 = [cfa - 44]\n"
- "4 unwind r6 = [cfa - 40]\n"
- "4 unwind r7 = [cfa - 36]\n"
- "4 unwind r8 = [cfa - 32]\n"
- "4 unwind r9 = [cfa - 28]\n"
- "4 unwind r10 = [cfa - 24]\n"
- "4 unwind r11 = [cfa - 20]\n"
- "4 unwind r12 = [cfa - 16]\n"
- "4 unwind r13 = [cfa - 12]\n"
- "4 unwind r14 = [cfa - 8]\n"
- "4 unwind r15 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- // Popping r13 results in a modified cfa.
- ASSERT_EQ(0x29U, exidx_->cfa());
-
- ASSERT_EQ(0x20U, (*exidx_->regs())[4]);
- ASSERT_EQ(0x21U, (*exidx_->regs())[5]);
- ASSERT_EQ(0x22U, (*exidx_->regs())[6]);
- ASSERT_EQ(0x23U, (*exidx_->regs())[7]);
- ASSERT_EQ(0x24U, (*exidx_->regs())[8]);
- ASSERT_EQ(0x25U, (*exidx_->regs())[9]);
- ASSERT_EQ(0x26U, (*exidx_->regs())[10]);
- ASSERT_EQ(0x27U, (*exidx_->regs())[11]);
- ASSERT_EQ(0x28U, (*exidx_->regs())[12]);
- ASSERT_EQ(0x29U, (*exidx_->regs())[13]);
- ASSERT_EQ(0x2aU, (*exidx_->regs())[14]);
- ASSERT_EQ(0x2bU, (*exidx_->regs())[15]);
-
- ResetExidx();
- exidx_->set_cfa(0x10034);
- data_->push_back(0x81);
- data_->push_back(0x28);
- process_memory_.SetData32(0x10034, 0x11);
- process_memory_.SetData32(0x10038, 0x22);
- process_memory_.SetData32(0x1003c, 0x33);
- exidx_->set_pc_set(false);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r7, r9, r12}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 12\n"
- "4 unwind r7 = [cfa - 12]\n"
- "4 unwind r9 = [cfa - 8]\n"
- "4 unwind r12 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10040U, exidx_->cfa());
- ASSERT_EQ(0x11U, (*exidx_->regs())[7]);
- ASSERT_EQ(0x22U, (*exidx_->regs())[9]);
- ASSERT_EQ(0x33U, (*exidx_->regs())[12]);
-}
-
-TEST_P(ArmExidxDecodeTest, set_vsp_from_register) {
- // 1001nnnn: Set vsp = r[nnnn] (nnnn != 13, 15)
- exidx_->set_cfa(0x100);
- for (size_t i = 0; i < 15; i++) {
- (*regs_arm_)[i] = i + 1;
- }
-
- data_->push_back(0x90);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = r0\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r0\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(1U, exidx_->cfa());
-
- ResetExidx();
- exidx_->set_cfa(0x100);
- for (size_t i = 0; i < 15; i++) {
- (*regs_arm_)[i] = i + 1;
- }
- data_->push_back(0x93);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = r3\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r3\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(4U, exidx_->cfa());
-
- ResetExidx();
- exidx_->set_cfa(0x100);
- for (size_t i = 0; i < 15; i++) {
- (*regs_arm_)[i] = i + 1;
- }
- data_->push_back(0x9e);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = r14\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r14\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(15U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, reserved_prefix) {
- // 10011101: Reserved as prefix for ARM register to register moves
- data_->push_back(0x9d);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind [Reserved]\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(ARM_STATUS_RESERVED, exidx_->status());
-
- // 10011111: Reserved as prefix for Intel Wireless MMX register to register moves
- ResetExidx();
- data_->push_back(0x9f);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind [Reserved]\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(ARM_STATUS_RESERVED, exidx_->status());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_registers) {
- // 10100nnn: Pop r4-r[4+nnn]
- data_->push_back(0xa0);
- process_memory_.SetData32(0x10000, 0x14);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r4}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 4\n"
- "4 unwind r4 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10004U, exidx_->cfa());
- ASSERT_EQ(0x14U, (*exidx_->regs())[4]);
-
- ResetExidx();
- data_->push_back(0xa3);
- process_memory_.SetData32(0x10000, 0x20);
- process_memory_.SetData32(0x10004, 0x30);
- process_memory_.SetData32(0x10008, 0x40);
- process_memory_.SetData32(0x1000c, 0x50);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r4-r7}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 16\n"
- "4 unwind r4 = [cfa - 16]\n"
- "4 unwind r5 = [cfa - 12]\n"
- "4 unwind r6 = [cfa - 8]\n"
- "4 unwind r7 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10010U, exidx_->cfa());
- ASSERT_EQ(0x20U, (*exidx_->regs())[4]);
- ASSERT_EQ(0x30U, (*exidx_->regs())[5]);
- ASSERT_EQ(0x40U, (*exidx_->regs())[6]);
- ASSERT_EQ(0x50U, (*exidx_->regs())[7]);
-
- ResetExidx();
- data_->push_back(0xa7);
- process_memory_.SetData32(0x10000, 0x41);
- process_memory_.SetData32(0x10004, 0x51);
- process_memory_.SetData32(0x10008, 0x61);
- process_memory_.SetData32(0x1000c, 0x71);
- process_memory_.SetData32(0x10010, 0x81);
- process_memory_.SetData32(0x10014, 0x91);
- process_memory_.SetData32(0x10018, 0xa1);
- process_memory_.SetData32(0x1001c, 0xb1);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r4-r11}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 32\n"
- "4 unwind r4 = [cfa - 32]\n"
- "4 unwind r5 = [cfa - 28]\n"
- "4 unwind r6 = [cfa - 24]\n"
- "4 unwind r7 = [cfa - 20]\n"
- "4 unwind r8 = [cfa - 16]\n"
- "4 unwind r9 = [cfa - 12]\n"
- "4 unwind r10 = [cfa - 8]\n"
- "4 unwind r11 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10020U, exidx_->cfa());
- ASSERT_EQ(0x41U, (*exidx_->regs())[4]);
- ASSERT_EQ(0x51U, (*exidx_->regs())[5]);
- ASSERT_EQ(0x61U, (*exidx_->regs())[6]);
- ASSERT_EQ(0x71U, (*exidx_->regs())[7]);
- ASSERT_EQ(0x81U, (*exidx_->regs())[8]);
- ASSERT_EQ(0x91U, (*exidx_->regs())[9]);
- ASSERT_EQ(0xa1U, (*exidx_->regs())[10]);
- ASSERT_EQ(0xb1U, (*exidx_->regs())[11]);
-}
-
-TEST_P(ArmExidxDecodeTest, pop_registers_with_r14) {
- // 10101nnn: Pop r4-r[4+nnn], r14
- data_->push_back(0xa8);
- process_memory_.SetData32(0x10000, 0x12);
- process_memory_.SetData32(0x10004, 0x22);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r4, r14}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 8\n"
- "4 unwind r4 = [cfa - 8]\n"
- "4 unwind r14 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
- ASSERT_EQ(0x12U, (*exidx_->regs())[4]);
- ASSERT_EQ(0x22U, (*exidx_->regs())[14]);
-
- ResetExidx();
- data_->push_back(0xab);
- process_memory_.SetData32(0x10000, 0x1);
- process_memory_.SetData32(0x10004, 0x2);
- process_memory_.SetData32(0x10008, 0x3);
- process_memory_.SetData32(0x1000c, 0x4);
- process_memory_.SetData32(0x10010, 0x5);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r4-r7, r14}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 20\n"
- "4 unwind r4 = [cfa - 20]\n"
- "4 unwind r5 = [cfa - 16]\n"
- "4 unwind r6 = [cfa - 12]\n"
- "4 unwind r7 = [cfa - 8]\n"
- "4 unwind r14 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10014U, exidx_->cfa());
- ASSERT_EQ(0x1U, (*exidx_->regs())[4]);
- ASSERT_EQ(0x2U, (*exidx_->regs())[5]);
- ASSERT_EQ(0x3U, (*exidx_->regs())[6]);
- ASSERT_EQ(0x4U, (*exidx_->regs())[7]);
- ASSERT_EQ(0x5U, (*exidx_->regs())[14]);
-
- ResetExidx();
- data_->push_back(0xaf);
- process_memory_.SetData32(0x10000, 0x1a);
- process_memory_.SetData32(0x10004, 0x2a);
- process_memory_.SetData32(0x10008, 0x3a);
- process_memory_.SetData32(0x1000c, 0x4a);
- process_memory_.SetData32(0x10010, 0x5a);
- process_memory_.SetData32(0x10014, 0x6a);
- process_memory_.SetData32(0x10018, 0x7a);
- process_memory_.SetData32(0x1001c, 0x8a);
- process_memory_.SetData32(0x10020, 0x9a);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r4-r11, r14}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 36\n"
- "4 unwind r4 = [cfa - 36]\n"
- "4 unwind r5 = [cfa - 32]\n"
- "4 unwind r6 = [cfa - 28]\n"
- "4 unwind r7 = [cfa - 24]\n"
- "4 unwind r8 = [cfa - 20]\n"
- "4 unwind r9 = [cfa - 16]\n"
- "4 unwind r10 = [cfa - 12]\n"
- "4 unwind r11 = [cfa - 8]\n"
- "4 unwind r14 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10024U, exidx_->cfa());
- ASSERT_EQ(0x1aU, (*exidx_->regs())[4]);
- ASSERT_EQ(0x2aU, (*exidx_->regs())[5]);
- ASSERT_EQ(0x3aU, (*exidx_->regs())[6]);
- ASSERT_EQ(0x4aU, (*exidx_->regs())[7]);
- ASSERT_EQ(0x5aU, (*exidx_->regs())[8]);
- ASSERT_EQ(0x6aU, (*exidx_->regs())[9]);
- ASSERT_EQ(0x7aU, (*exidx_->regs())[10]);
- ASSERT_EQ(0x8aU, (*exidx_->regs())[11]);
- ASSERT_EQ(0x9aU, (*exidx_->regs())[14]);
-}
-
-TEST_P(ArmExidxDecodeTest, finish) {
- // 10110000: Finish
- data_->push_back(0xb0);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind finish\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa());
- ASSERT_EQ(ARM_STATUS_FINISH, exidx_->status());
-}
-
-TEST_P(ArmExidxDecodeTest, spare) {
- // 10110001 00000000: Spare
- data_->push_back(0xb1);
- data_->push_back(0x00);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa());
- ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status());
-
- // 10110001 xxxxyyyy: Spare (xxxx != 0000)
- for (size_t x = 1; x < 16; x++) {
- for (size_t y = 0; y < 16; y++) {
- ResetExidx();
- data_->push_back(0xb1);
- data_->push_back((x << 4) | y);
- ASSERT_FALSE(exidx_->Decode()) << "x, y = " << x << ", " << y;
- ASSERT_EQ("", GetFakeLogBuf()) << "x, y = " << x << ", " << y;
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y;
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa()) << "x, y = " << x << ", " << y;
- ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status());
- }
- }
-
- // 101101nn: Spare
- for (size_t n = 0; n < 4; n++) {
- ResetExidx();
- data_->push_back(0xb4 | n);
- ASSERT_FALSE(exidx_->Decode()) << "n = " << n;
- ASSERT_EQ("", GetFakeLogBuf()) << "n = " << n;
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "n = " << n;
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa()) << "n = " << n;
- ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status());
- }
-
- // 11000111 00000000: Spare
- ResetExidx();
- data_->push_back(0xc7);
- data_->push_back(0x00);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa());
- ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status());
-
- // 11000111 xxxxyyyy: Spare (xxxx != 0000)
- for (size_t x = 1; x < 16; x++) {
- for (size_t y = 0; y < 16; y++) {
- ResetExidx();
- data_->push_back(0xc7);
- data_->push_back(0x10);
- ASSERT_FALSE(exidx_->Decode()) << "x, y = " << x << ", " << y;
- ASSERT_EQ("", GetFakeLogBuf()) << "x, y = " << x << ", " << y;
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y;
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa()) << "x, y = " << x << ", " << y;
- ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status());
- }
- }
-
- // 11001yyy: Spare (yyy != 000, 001)
- for (size_t y = 2; y < 8; y++) {
- ResetExidx();
- data_->push_back(0xc8 | y);
- ASSERT_FALSE(exidx_->Decode()) << "y = " << y;
- ASSERT_EQ("", GetFakeLogBuf()) << "y = " << y;
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "y = " << y;
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa()) << "y = " << y;
- ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status());
- }
-
- // 11xxxyyy: Spare (xxx != 000, 001, 010)
- for (size_t x = 3; x < 8; x++) {
- for (size_t y = 0; y < 8; y++) {
- ResetExidx();
- data_->push_back(0xc0 | (x << 3) | y);
- ASSERT_FALSE(exidx_->Decode()) << "x, y = " << x << ", " << y;
- ASSERT_EQ("", GetFakeLogBuf()) << "x, y = " << x << ", " << y;
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Spare\n", GetFakeLogPrint()) << "x, y = " << x << ", " << y;
- break;
- }
- ASSERT_EQ(0x10000U, exidx_->cfa()) << "x, y = " << x << ", " << y;
- ASSERT_EQ(ARM_STATUS_SPARE, exidx_->status());
- }
- }
-}
-
-TEST_P(ArmExidxDecodeTest, pop_registers_under_mask) {
- // 10110001 0000iiii: Pop integer registers {r0, r1, r2, r3}
- data_->push_back(0xb1);
- data_->push_back(0x01);
- process_memory_.SetData32(0x10000, 0x45);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r0}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 4\n"
- "4 unwind r0 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10004U, exidx_->cfa());
- ASSERT_EQ(0x45U, (*exidx_->regs())[0]);
-
- ResetExidx();
- data_->push_back(0xb1);
- data_->push_back(0x0a);
- process_memory_.SetData32(0x10000, 0x23);
- process_memory_.SetData32(0x10004, 0x24);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r1, r3}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 8\n"
- "4 unwind r1 = [cfa - 8]\n"
- "4 unwind r3 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
- ASSERT_EQ(0x23U, (*exidx_->regs())[1]);
- ASSERT_EQ(0x24U, (*exidx_->regs())[3]);
-
- ResetExidx();
- data_->push_back(0xb1);
- data_->push_back(0x0f);
- process_memory_.SetData32(0x10000, 0x65);
- process_memory_.SetData32(0x10004, 0x54);
- process_memory_.SetData32(0x10008, 0x43);
- process_memory_.SetData32(0x1000c, 0x32);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {r0, r1, r2, r3}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 16\n"
- "4 unwind r0 = [cfa - 16]\n"
- "4 unwind r1 = [cfa - 12]\n"
- "4 unwind r2 = [cfa - 8]\n"
- "4 unwind r3 = [cfa - 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10010U, exidx_->cfa());
- ASSERT_EQ(0x65U, (*exidx_->regs())[0]);
- ASSERT_EQ(0x54U, (*exidx_->regs())[1]);
- ASSERT_EQ(0x43U, (*exidx_->regs())[2]);
- ASSERT_EQ(0x32U, (*exidx_->regs())[3]);
-}
-
-TEST_P(ArmExidxDecodeTest, vsp_large_incr) {
- // 10110010 uleb128: vsp = vsp + 0x204 + (uleb128 << 2)
- data_->push_back(0xb2);
- data_->push_back(0x7f);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp + 1024\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 + 1024\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10400U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xb2);
- data_->push_back(0xff);
- data_->push_back(0x02);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp + 2048\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 + 2048\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10800U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xb2);
- data_->push_back(0xff);
- data_->push_back(0x82);
- data_->push_back(0x30);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind vsp = vsp + 3147776\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 + 3147776\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x310800U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_vfp_fstmfdx) {
- // 10110011 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX
- data_->push_back(0xb3);
- data_->push_back(0x00);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d0}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x1000cU, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xb3);
- data_->push_back(0x48);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d4-d12}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x1004cU, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_vfp8_fstmfdx) {
- // 10111nnn: Pop VFP double precision registers D[8]-D[8+nnn] by FSTMFDX
- data_->push_back(0xb8);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d8}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x1000cU, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xbb);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d8-d11}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10024U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xbf);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d8-d15}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10044U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_mmx_wr10) {
- // 11000nnn: Intel Wireless MMX pop wR[10]-wR[10+nnn] (nnn != 6, 7)
- data_->push_back(0xc0);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wR10}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc2);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wR10-wR12}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10018U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc5);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wR10-wR15}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10030U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_mmx_wr) {
- // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc]
- data_->push_back(0xc6);
- data_->push_back(0x00);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wR0}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc6);
- data_->push_back(0x25);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wR2-wR7}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10030U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc6);
- data_->push_back(0xff);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wR15-wR30}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wRX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10080U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_mmx_wcgr) {
- // 11000111 0000iiii: Intel Wireless MMX pop wCGR registes {wCGR0,1,2,3}
- data_->push_back(0xc7);
- data_->push_back(0x01);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wCGR0}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wCGR register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10004U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc7);
- data_->push_back(0x0a);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wCGR1, wCGR3}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wCGR register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc7);
- data_->push_back(0x0f);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {wCGR0, wCGR1, wCGR2, wCGR3}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported wCGR register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10010U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_vfp16_vpush) {
- // 11001000 sssscccc: Pop VFP double precision registers d[16+ssss]-D[16+ssss+cccc] by VPUSH
- data_->push_back(0xc8);
- data_->push_back(0x00);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d16}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc8);
- data_->push_back(0x14);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d17-d21}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10028U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc8);
- data_->push_back(0xff);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d31-d46}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10080U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_vfp_vpush) {
- // 11001001 sssscccc: Pop VFP double precision registers d[ssss]-D[ssss+cccc] by VPUSH
- data_->push_back(0xc9);
- data_->push_back(0x00);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d0}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc9);
- data_->push_back(0x23);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d2-d5}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10020U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xc9);
- data_->push_back(0xff);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d15-d30}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10080U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, pop_vfp8_vpush) {
- // 11010nnn: Pop VFP double precision registers D[8]-D[8+nnn] by VPUSH
- data_->push_back(0xd0);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d8}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10008U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xd2);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d8-d10}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10018U, exidx_->cfa());
-
- ResetExidx();
- data_->push_back(0xd7);
- ASSERT_TRUE(exidx_->Decode());
- ASSERT_FALSE(exidx_->pc_set());
- ASSERT_EQ("", GetFakeLogBuf());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ("4 unwind pop {d8-d15}\n", GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- ASSERT_EQ("4 unwind Unsupported DX register display\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10040U, exidx_->cfa());
-}
-
-TEST_P(ArmExidxDecodeTest, expect_truncated) {
- // This test verifies that any op that requires extra ops will
- // fail if the data is not present.
- data_->push_back(0x80);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-
- data_->clear();
- data_->push_back(0xb1);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-
- data_->clear();
- data_->push_back(0xb2);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-
- data_->clear();
- data_->push_back(0xb3);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-
- data_->clear();
- data_->push_back(0xc6);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-
- data_->clear();
- data_->push_back(0xc7);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-
- data_->clear();
- data_->push_back(0xc8);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-
- data_->clear();
- data_->push_back(0xc9);
- ASSERT_FALSE(exidx_->Decode());
- ASSERT_EQ(ARM_STATUS_TRUNCATED, exidx_->status());
-}
-
-TEST_P(ArmExidxDecodeTest, verify_no_truncated) {
- // This test verifies that no pattern results in a crash or truncation.
- MemoryFakeAlwaysReadZero memory_zero;
- Init(&memory_zero);
-
- for (size_t x = 0; x < 256; x++) {
- if (x == 0xb2) {
- // This opcode is followed by an uleb128, so just skip this one.
- continue;
- }
- for (size_t y = 0; y < 256; y++) {
- data_->clear();
- data_->push_back(x);
- data_->push_back(y);
- if (!exidx_->Decode()) {
- ASSERT_NE(ARM_STATUS_TRUNCATED, exidx_->status())
- << "x y = 0x" << std::hex << x << " 0x" << y;
- ASSERT_NE(ARM_STATUS_READ_FAILED, exidx_->status())
- << "x y = 0x" << std::hex << x << " 0x" << y;
- }
- }
- }
-}
-
-TEST_P(ArmExidxDecodeTest, eval_multiple_decodes) {
- // vsp = vsp + 4
- data_->push_back(0x00);
- // vsp = vsp + 12
- data_->push_back(0x02);
- // Finish
- data_->push_back(0xb0);
-
- ASSERT_TRUE(exidx_->Eval());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ(
- "4 unwind vsp = vsp + 4\n"
- "4 unwind vsp = vsp + 12\n"
- "4 unwind finish\n",
- GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ("4 unwind cfa = r13 + 16\n", GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10010U, exidx_->cfa());
- ASSERT_FALSE(exidx_->pc_set());
-}
-
-TEST_P(ArmExidxDecodeTest, eval_vsp_add_after_pop) {
- // Pop {r15}
- data_->push_back(0x88);
- data_->push_back(0x00);
- // vsp = vsp + 12
- data_->push_back(0x02);
- // Finish
- data_->push_back(0xb0);
- process_memory_.SetData32(0x10000, 0x10);
-
- ASSERT_TRUE(exidx_->Eval());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ(
- "4 unwind pop {r15}\n"
- "4 unwind vsp = vsp + 12\n"
- "4 unwind finish\n",
- GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 16\n"
- "4 unwind r15 = [cfa - 16]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10010U, exidx_->cfa());
- ASSERT_TRUE(exidx_->pc_set());
- ASSERT_EQ(0x10U, (*exidx_->regs())[15]);
-}
-
-TEST_P(ArmExidxDecodeTest, eval_vsp_add_large_after_pop) {
- // Pop {r15}
- data_->push_back(0x88);
- data_->push_back(0x00);
- // vsp = vsp + 1024
- data_->push_back(0xb2);
- data_->push_back(0x7f);
- // Finish
- data_->push_back(0xb0);
- process_memory_.SetData32(0x10000, 0x10);
-
- ASSERT_TRUE(exidx_->Eval());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ(
- "4 unwind pop {r15}\n"
- "4 unwind vsp = vsp + 1024\n"
- "4 unwind finish\n",
- GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 1028\n"
- "4 unwind r15 = [cfa - 1028]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10404U, exidx_->cfa());
- ASSERT_TRUE(exidx_->pc_set());
- ASSERT_EQ(0x10U, (*exidx_->regs())[15]);
-}
-
-TEST_P(ArmExidxDecodeTest, eval_vsp_sub_after_pop) {
- // Pop {r15}
- data_->push_back(0x88);
- data_->push_back(0x00);
- // vsp = vsp - 4
- data_->push_back(0x41);
- // Finish
- data_->push_back(0xb0);
- process_memory_.SetData32(0x10000, 0x10);
-
- ASSERT_TRUE(exidx_->Eval());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ(
- "4 unwind pop {r15}\n"
- "4 unwind vsp = vsp - 8\n"
- "4 unwind finish\n",
- GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 - 4\n"
- "4 unwind r15 = [cfa + 4]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0xfffcU, exidx_->cfa());
- ASSERT_TRUE(exidx_->pc_set());
- ASSERT_EQ(0x10U, (*exidx_->regs())[15]);
-}
-
-TEST_P(ArmExidxDecodeTest, eval_pc_set) {
- // vsp = vsp + 4
- data_->push_back(0x00);
- // vsp = vsp + 12
- data_->push_back(0x02);
- // Pop {r15}
- data_->push_back(0x88);
- data_->push_back(0x00);
- // vsp = vsp + 12
- data_->push_back(0x02);
- // Finish
- data_->push_back(0xb0);
-
- process_memory_.SetData32(0x10010, 0x10);
-
- ASSERT_TRUE(exidx_->Eval());
- switch (log_) {
- case ARM_LOG_NONE:
- ASSERT_EQ("", GetFakeLogPrint());
- break;
- case ARM_LOG_FULL:
- ASSERT_EQ(
- "4 unwind vsp = vsp + 4\n"
- "4 unwind vsp = vsp + 12\n"
- "4 unwind pop {r15}\n"
- "4 unwind vsp = vsp + 12\n"
- "4 unwind finish\n",
- GetFakeLogPrint());
- break;
- case ARM_LOG_BY_REG:
- exidx_->LogByReg();
- ASSERT_EQ(
- "4 unwind cfa = r13 + 32\n"
- "4 unwind r15 = [cfa - 16]\n",
- GetFakeLogPrint());
- break;
- }
- ASSERT_EQ(0x10020U, exidx_->cfa());
- ASSERT_TRUE(exidx_->pc_set());
- ASSERT_EQ(0x10U, (*exidx_->regs())[15]);
-}
-
-INSTANTIATE_TEST_SUITE_P(Unwindstack, ArmExidxDecodeTest,
- ::testing::Values("logging", "register_logging", "no_logging"));
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ArmExidxExtractTest.cpp b/libunwindstack/tests/ArmExidxExtractTest.cpp
deleted file mode 100644
index 79c799c..0000000
--- a/libunwindstack/tests/ArmExidxExtractTest.cpp
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <deque>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Log.h>
-
-#include "ArmExidx.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class ArmExidxExtractTest : public ::testing::Test {
- protected:
- void SetUp() override {
- ResetLogs();
- elf_memory_.Clear();
- exidx_ = new ArmExidx(nullptr, &elf_memory_, nullptr);
- data_ = exidx_->data();
- data_->clear();
- }
-
- void TearDown() override {
- delete exidx_;
- }
-
- ArmExidx* exidx_ = nullptr;
- std::deque<uint8_t>* data_;
- MemoryFake elf_memory_;
-};
-
-TEST_F(ArmExidxExtractTest, bad_alignment) {
- ASSERT_FALSE(exidx_->ExtractEntryData(0x1001));
- ASSERT_EQ(ARM_STATUS_INVALID_ALIGNMENT, exidx_->status());
- ASSERT_TRUE(data_->empty());
-}
-
-TEST_F(ArmExidxExtractTest, cant_unwind) {
- elf_memory_.SetData32(0x1000, 0x7fff2340);
- elf_memory_.SetData32(0x1004, 1);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x1000));
- ASSERT_EQ(ARM_STATUS_NO_UNWIND, exidx_->status());
- ASSERT_TRUE(data_->empty());
-}
-
-TEST_F(ArmExidxExtractTest, compact) {
- elf_memory_.SetData32(0x4000, 0x7ffa3000);
- elf_memory_.SetData32(0x4004, 0x80a8b0b0);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x4000));
- ASSERT_EQ(3U, data_->size());
- ASSERT_EQ(0xa8, data_->at(0));
- ASSERT_EQ(0xb0, data_->at(1));
- ASSERT_EQ(0xb0, data_->at(2));
-
- // Missing finish gets added.
- elf_memory_.Clear();
- elf_memory_.SetData32(0x534, 0x7ffa3000);
- elf_memory_.SetData32(0x538, 0x80a1a2a3);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x534));
- ASSERT_EQ(4U, data_->size());
- ASSERT_EQ(0xa1, data_->at(0));
- ASSERT_EQ(0xa2, data_->at(1));
- ASSERT_EQ(0xa3, data_->at(2));
- ASSERT_EQ(0xb0, data_->at(3));
-}
-
-TEST_F(ArmExidxExtractTest, compact_non_zero_personality) {
- elf_memory_.SetData32(0x4000, 0x7ffa3000);
-
- uint32_t compact_value = 0x80a8b0b0;
- for (size_t i = 1; i < 16; i++) {
- elf_memory_.SetData32(0x4004, compact_value | (i << 24));
- ASSERT_FALSE(exidx_->ExtractEntryData(0x4000));
- ASSERT_EQ(ARM_STATUS_INVALID_PERSONALITY, exidx_->status());
- }
-}
-
-TEST_F(ArmExidxExtractTest, second_read_compact_personality_1_2) {
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x8100f3b0);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(2U, data_->size());
- ASSERT_EQ(0xf3, data_->at(0));
- ASSERT_EQ(0xb0, data_->at(1));
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x8200f3f4);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(3U, data_->size());
- ASSERT_EQ(0xf3, data_->at(0));
- ASSERT_EQ(0xf4, data_->at(1));
- ASSERT_EQ(0xb0, data_->at(2));
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x8201f3f4);
- elf_memory_.SetData32(0x6238, 0x102030b0);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(6U, data_->size());
- ASSERT_EQ(0xf3, data_->at(0));
- ASSERT_EQ(0xf4, data_->at(1));
- ASSERT_EQ(0x10, data_->at(2));
- ASSERT_EQ(0x20, data_->at(3));
- ASSERT_EQ(0x30, data_->at(4));
- ASSERT_EQ(0xb0, data_->at(5));
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x8103f3f4);
- elf_memory_.SetData32(0x6238, 0x10203040);
- elf_memory_.SetData32(0x623c, 0x50607080);
- elf_memory_.SetData32(0x6240, 0x90a0c0d0);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(15U, data_->size());
- ASSERT_EQ(0xf3, data_->at(0));
- ASSERT_EQ(0xf4, data_->at(1));
- ASSERT_EQ(0x10, data_->at(2));
- ASSERT_EQ(0x20, data_->at(3));
- ASSERT_EQ(0x30, data_->at(4));
- ASSERT_EQ(0x40, data_->at(5));
- ASSERT_EQ(0x50, data_->at(6));
- ASSERT_EQ(0x60, data_->at(7));
- ASSERT_EQ(0x70, data_->at(8));
- ASSERT_EQ(0x80, data_->at(9));
- ASSERT_EQ(0x90, data_->at(10));
- ASSERT_EQ(0xa0, data_->at(11));
- ASSERT_EQ(0xc0, data_->at(12));
- ASSERT_EQ(0xd0, data_->at(13));
- ASSERT_EQ(0xb0, data_->at(14));
-}
-
-TEST_F(ArmExidxExtractTest, second_read_compact_personality_illegal) {
- elf_memory_.SetData32(0x5000, 0x7ffa1e48);
- elf_memory_.SetData32(0x5004, 0x1230);
- elf_memory_.SetData32(0x6234, 0x832132b0);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_INVALID_PERSONALITY, exidx_->status());
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x7ffa1e48);
- elf_memory_.SetData32(0x5004, 0x1230);
- elf_memory_.SetData32(0x6234, 0x842132b0);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_INVALID_PERSONALITY, exidx_->status());
-}
-
-TEST_F(ArmExidxExtractTest, second_read_offset_is_negative) {
- elf_memory_.SetData32(0x5000, 0x7ffa1e48);
- elf_memory_.SetData32(0x5004, 0x7fffb1e0);
- elf_memory_.SetData32(0x1e4, 0x842132b0);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_INVALID_PERSONALITY, exidx_->status());
-}
-
-TEST_F(ArmExidxExtractTest, second_read_not_compact) {
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x1);
- elf_memory_.SetData32(0x6238, 0x001122b0);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(3U, data_->size());
- ASSERT_EQ(0x11, data_->at(0));
- ASSERT_EQ(0x22, data_->at(1));
- ASSERT_EQ(0xb0, data_->at(2));
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x2);
- elf_memory_.SetData32(0x6238, 0x00112233);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(4U, data_->size());
- ASSERT_EQ(0x11, data_->at(0));
- ASSERT_EQ(0x22, data_->at(1));
- ASSERT_EQ(0x33, data_->at(2));
- ASSERT_EQ(0xb0, data_->at(3));
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x3);
- elf_memory_.SetData32(0x6238, 0x01112233);
- elf_memory_.SetData32(0x623c, 0x445566b0);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(7U, data_->size());
- ASSERT_EQ(0x11, data_->at(0));
- ASSERT_EQ(0x22, data_->at(1));
- ASSERT_EQ(0x33, data_->at(2));
- ASSERT_EQ(0x44, data_->at(3));
- ASSERT_EQ(0x55, data_->at(4));
- ASSERT_EQ(0x66, data_->at(5));
- ASSERT_EQ(0xb0, data_->at(6));
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x3);
- elf_memory_.SetData32(0x6238, 0x05112233);
- elf_memory_.SetData32(0x623c, 0x01020304);
- elf_memory_.SetData32(0x6240, 0x05060708);
- elf_memory_.SetData32(0x6244, 0x090a0b0c);
- elf_memory_.SetData32(0x6248, 0x0d0e0f10);
- elf_memory_.SetData32(0x624c, 0x11121314);
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(24U, data_->size());
- ASSERT_EQ(0x11, data_->at(0));
- ASSERT_EQ(0x22, data_->at(1));
- ASSERT_EQ(0x33, data_->at(2));
- ASSERT_EQ(0x01, data_->at(3));
- ASSERT_EQ(0x02, data_->at(4));
- ASSERT_EQ(0x03, data_->at(5));
- ASSERT_EQ(0x04, data_->at(6));
- ASSERT_EQ(0x05, data_->at(7));
- ASSERT_EQ(0x06, data_->at(8));
- ASSERT_EQ(0x07, data_->at(9));
- ASSERT_EQ(0x08, data_->at(10));
- ASSERT_EQ(0x09, data_->at(11));
- ASSERT_EQ(0x0a, data_->at(12));
- ASSERT_EQ(0x0b, data_->at(13));
- ASSERT_EQ(0x0c, data_->at(14));
- ASSERT_EQ(0x0d, data_->at(15));
- ASSERT_EQ(0x0e, data_->at(16));
- ASSERT_EQ(0x0f, data_->at(17));
- ASSERT_EQ(0x10, data_->at(18));
- ASSERT_EQ(0x11, data_->at(19));
- ASSERT_EQ(0x12, data_->at(20));
- ASSERT_EQ(0x13, data_->at(21));
- ASSERT_EQ(0x14, data_->at(22));
- ASSERT_EQ(0xb0, data_->at(23));
-}
-
-TEST_F(ArmExidxExtractTest, read_failures) {
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
- EXPECT_EQ(0x5004U, exidx_->status_address());
-
- elf_memory_.SetData32(0x5000, 0x100);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
- EXPECT_EQ(0x5004U, exidx_->status_address());
-
- elf_memory_.SetData32(0x5004, 0x100);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
- EXPECT_EQ(0x5104U, exidx_->status_address());
-
- elf_memory_.SetData32(0x5104, 0x1);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
- EXPECT_EQ(0x5108U, exidx_->status_address());
-
- elf_memory_.SetData32(0x5108, 0x01010203);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_READ_FAILED, exidx_->status());
- EXPECT_EQ(0x510cU, exidx_->status_address());
-}
-
-TEST_F(ArmExidxExtractTest, malformed) {
- elf_memory_.SetData32(0x5000, 0x100);
- elf_memory_.SetData32(0x5004, 0x100);
- elf_memory_.SetData32(0x5104, 0x1);
- elf_memory_.SetData32(0x5108, 0x06010203);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_MALFORMED, exidx_->status());
-
- elf_memory_.Clear();
- elf_memory_.SetData32(0x5000, 0x100);
- elf_memory_.SetData32(0x5004, 0x100);
- elf_memory_.SetData32(0x5104, 0x1);
- elf_memory_.SetData32(0x5108, 0x81060203);
- ASSERT_FALSE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ(ARM_STATUS_MALFORMED, exidx_->status());
-}
-
-TEST_F(ArmExidxExtractTest, cant_unwind_log) {
- elf_memory_.SetData32(0x1000, 0x7fff2340);
- elf_memory_.SetData32(0x1004, 1);
-
- exidx_->set_log(ARM_LOG_FULL);
- exidx_->set_log_indent(0);
- exidx_->set_log_skip_execution(false);
-
- ASSERT_FALSE(exidx_->ExtractEntryData(0x1000));
- ASSERT_EQ(ARM_STATUS_NO_UNWIND, exidx_->status());
-
- ASSERT_EQ("4 unwind Raw Data: 0x00 0x00 0x00 0x01\n"
- "4 unwind [cantunwind]\n", GetFakeLogPrint());
-}
-
-TEST_F(ArmExidxExtractTest, raw_data_compact) {
- elf_memory_.SetData32(0x4000, 0x7ffa3000);
- elf_memory_.SetData32(0x4004, 0x80a8b0b0);
-
- exidx_->set_log(ARM_LOG_FULL);
- exidx_->set_log_indent(0);
- exidx_->set_log_skip_execution(false);
-
- ASSERT_TRUE(exidx_->ExtractEntryData(0x4000));
- ASSERT_EQ("4 unwind Raw Data: 0xa8 0xb0 0xb0\n", GetFakeLogPrint());
-}
-
-TEST_F(ArmExidxExtractTest, raw_data_non_compact) {
- elf_memory_.SetData32(0x5000, 0x1234);
- elf_memory_.SetData32(0x5004, 0x00001230);
- elf_memory_.SetData32(0x6234, 0x2);
- elf_memory_.SetData32(0x6238, 0x00112233);
-
- exidx_->set_log(ARM_LOG_FULL);
- exidx_->set_log_indent(0);
- exidx_->set_log_skip_execution(false);
-
- ASSERT_TRUE(exidx_->ExtractEntryData(0x5000));
- ASSERT_EQ("4 unwind Raw Data: 0x11 0x22 0x33 0xb0\n", GetFakeLogPrint());
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DexFileData.h b/libunwindstack/tests/DexFileData.h
deleted file mode 100644
index 6975c68..0000000
--- a/libunwindstack/tests/DexFileData.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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_DEXFILESDATA_H
-#define _LIBUNWINDSTACK_DEXFILESDATA_H
-
-namespace unwindstack {
-
-// Borrowed from art/dex/dex_file_test.cc.
-static constexpr uint32_t kDexData[] = {
- 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
- 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
- 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
- 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
- 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
- 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
- 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
- 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
- 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
- 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
- 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
- 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
- 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
- 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
- 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
- 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
- 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_DEXFILESDATA_H
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
deleted file mode 100644
index 1deba01..0000000
--- a/libunwindstack/tests/DexFileTest.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * 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 <malloc.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <unordered_map>
-
-#include <MemoryLocal.h>
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Memory.h>
-
-#include "DexFile.h"
-#include "DexFileData.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-TEST(DexFileTest, from_file_open_non_exist) {
- EXPECT_TRUE(DexFileFromFile::Create(0, "/file/does/not/exist") == nullptr);
-}
-
-TEST(DexFileTest, from_file_open_too_small) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(size_t{10}, static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, 10))));
-
- // Header too small.
- EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
-
- // Header correct, file too small.
- ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData) - 1,
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 1))));
- EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
-}
-
-TEST(DexFileTest, from_file_open) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr);
-}
-
-TEST(DexFileTest, from_file_open_non_zero_offset) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- EXPECT_TRUE(DexFileFromFile::Create(0x100, tf.path) != nullptr);
-}
-
-static constexpr size_t kNumLeakLoops = 5000;
-static constexpr size_t kMaxAllowedLeakBytes = 1024;
-
-static void CheckForLeak(size_t loop, size_t* first_allocated_bytes, size_t* last_allocated_bytes) {
- size_t allocated_bytes = mallinfo().uordblks;
- if (*first_allocated_bytes == 0) {
- *first_allocated_bytes = allocated_bytes;
- } else if (*last_allocated_bytes > *first_allocated_bytes) {
- // Check that the total memory did not increase too much over the first loop.
- ASSERT_LE(*last_allocated_bytes - *first_allocated_bytes, kMaxAllowedLeakBytes)
- << "Failed in loop " << loop << " first_allocated_bytes " << *first_allocated_bytes
- << " last_allocated_bytes " << *last_allocated_bytes;
- }
- *last_allocated_bytes = allocated_bytes;
-}
-
-TEST(DexFileTest, from_file_no_leak) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- size_t first_allocated_bytes = 0;
- size_t last_allocated_bytes = 0;
- for (size_t i = 0; i < kNumLeakLoops; i++) {
- EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr);
- ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
- }
-}
-
-TEST(DexFileTest, from_memory_fail_too_small_for_header) {
- MemoryFake memory;
-
- memory.SetMemory(0x1000, kDexData, 10);
-
- EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) == nullptr);
-}
-
-TEST(DexFileTest, from_memory_fail_too_small_for_data) {
- MemoryFake memory;
-
- memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2);
-
- EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) == nullptr);
-}
-
-TEST(DexFileTest, from_memory_open) {
- MemoryFake memory;
-
- memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
-
- EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) != nullptr);
-}
-
-TEST(DexFileTest, from_memory_no_leak) {
- MemoryFake memory;
-
- memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
-
- size_t first_allocated_bytes = 0;
- size_t last_allocated_bytes = 0;
- for (size_t i = 0; i < kNumLeakLoops; i++) {
- EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "", sizeof(kDexData)) != nullptr);
- ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
- }
-}
-
-TEST(DexFileTest, create_using_file) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- MemoryFake memory;
- MapInfo info(nullptr, nullptr, 0, 0x10000, 0, 0x5, tf.path);
- EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr);
-}
-
-TEST(DexFileTest, create_using_file_non_zero_start) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- MemoryFake memory;
- MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0, 0x5, tf.path);
- EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr);
-}
-
-TEST(DexFileTest, create_using_file_non_zero_offset) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
- ASSERT_EQ(sizeof(kDexData),
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
-
- MemoryFake memory;
- MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path);
- EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr);
-}
-
-TEST(DexFileTest, create_using_memory_empty_file) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
- EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
-}
-
-TEST(DexFileTest, create_using_memory_file_does_not_exist) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
- EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
-}
-
-TEST(DexFileTest, create_using_memory_file_is_malformed) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_EQ(sizeof(kDexData) - 10,
- static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
-
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- MapInfo info(nullptr, nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
- std::unique_ptr<DexFile> dex_file = DexFile::Create(0x4000, &memory, &info);
- ASSERT_TRUE(dex_file != nullptr);
-
- // Check it came from memory by clearing memory and verifying it fails.
- memory.Clear();
- dex_file = DexFile::Create(0x4000, &memory, &info);
- EXPECT_TRUE(dex_file == nullptr);
-}
-
-TEST(DexFileTest, create_using_memory_size_too_small) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- MapInfo info(nullptr, nullptr, 0x100, sizeof(kDexData) - 2, 0x200, 0x5, "/does/not/exist");
- EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr);
-}
-
-class MemoryLocalFake : public MemoryLocal {
- public:
- MemoryLocalFake(size_t memory_size) : backing_(memory_size) {}
- virtual ~MemoryLocalFake() = default;
-
- void* Data() { return backing_.data(); }
-
- private:
- std::vector<void*> backing_;
-};
-
-TEST(DexFileTest, create_using_local_memory) {
- MemoryLocalFake memory(sizeof(kDexData));
-
- memcpy(memory.Data(), kDexData, sizeof(kDexData));
- uint64_t start = reinterpret_cast<uint64_t>(memory.Data());
- MapInfo info(nullptr, nullptr, start, start + 0x1000, 0x200, 0x5, "/does/not/exist");
- EXPECT_TRUE(DexFile::Create(start, &memory, &info) != nullptr);
-}
-
-TEST(DexFileTest, create_using_local_memory_size_too_small) {
- MemoryLocalFake memory(sizeof(kDexData));
-
- memcpy(memory.Data(), kDexData, sizeof(kDexData));
- uint64_t start = reinterpret_cast<uint64_t>(memory.Data());
- MapInfo info(nullptr, nullptr, start, start + sizeof(kDexData) - 2, 0x200, 0x5,
- "/does/not/exist");
- EXPECT_TRUE(DexFile::Create(start, &memory, &info) == nullptr);
-}
-
-TEST(DexFileTest, get_method) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-
- std::string method;
- uint64_t 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->GetMethodInformation(0x118, &method, &method_offset));
- EXPECT_EQ("Main.main", method);
- EXPECT_EQ(0U, method_offset);
-}
-
-TEST(DexFileTest, get_method_empty) {
- MemoryFake memory;
- memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
- MapInfo info(nullptr, nullptr, 0x100, 0x10000, 0x200, 0x5, "");
- std::unique_ptr<DexFile> dex_file(DexFile::Create(0x4000, &memory, &info));
- ASSERT_TRUE(dex_file != nullptr);
-
- std::string method;
- uint64_t method_offset;
- EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &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
deleted file mode 100644
index 477cf8e..0000000
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * 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 <elf.h>
-#include <string.h>
-
-#include <memory>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DexFiles.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-#include "DexFileData.h"
-#include "ElfFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class DexFilesTest : public ::testing::Test {
- protected:
- void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset,
- uint64_t data_vaddr, uint64_t data_size) {
- MemoryFake* memory = new MemoryFake;
- ElfFake* elf = new ElfFake(memory);
- elf->FakeSetValid(true);
- ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
- elf->FakeSetInterface(interface);
-
- interface->FakeSetGlobalVariable("__dex_debug_descriptor", global_offset);
- interface->FakeSetDataOffset(data_offset);
- interface->FakeSetDataVaddrStart(data_vaddr);
- interface->FakeSetDataVaddrEnd(data_vaddr + data_size);
- map_info->elf.reset(elf);
- }
-
- void Init(ArchEnum arch) {
- 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"
- "4000-6000 r--s 00000000 00:00 0 /fake/elf\n"
- "6000-8000 -wxs 00002000 00:00 0 /fake/elf\n"
- "a000-c000 r--p 00000000 00:00 0 /fake/elf2\n"
- "c000-f000 rw-p 00002000 00:00 0 /fake/elf2\n"
- "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
- "100000-110000 rw-p 00f1000 00:00 0 /fake/elf3\n"
- "200000-210000 rw-p 0002000 00:00 0 /fake/elf3\n"
- "300000-400000 rw-p 0003000 00:00 0 /fake/elf3\n"
- "500000-501000 r--p 0000000 00:00 0 /fake/elf4\n"
- "501000-502000 ---p 0000000 00:00 0\n"
- "503000-510000 rw-p 0003000 00:00 0 /fake/elf4\n"
- "510000-520000 rw-p 0010000 00:00 0 /fake/elf4\n"));
- ASSERT_TRUE(maps_->Parse());
-
- // Global variable in a section that is not readable.
- MapInfo* map_info = maps_->Get(kMapGlobalNonReadable);
- ASSERT_TRUE(map_info != nullptr);
- CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
-
- // Global variable not set by default.
- map_info = maps_->Get(kMapGlobalSetToZero);
- ASSERT_TRUE(map_info != nullptr);
- CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
-
- // Global variable set in this map.
- map_info = maps_->Get(kMapGlobal);
- ASSERT_TRUE(map_info != nullptr);
- CreateFakeElf(map_info, 0xf1800, 0xf1000, 0xf1000, 0x10000);
-
- // Global variable set in this map, but there is an empty map before rw map.
- map_info = maps_->Get(kMapGlobalAfterEmpty);
- ASSERT_TRUE(map_info != nullptr);
- CreateFakeElf(map_info, 0x3800, 0x3000, 0x3000, 0xd000);
- }
-
- void SetUp() override {
- memory_ = new MemoryFake;
- process_memory_.reset(memory_);
-
- Init(ARCH_ARM);
- }
-
- 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;
- static constexpr size_t kMapGlobalSetToZero = 3;
- static constexpr size_t kMapGlobal = 5;
- static constexpr size_t kMapGlobalRw = 6;
- static constexpr size_t kMapDexFileEntries = 7;
- static constexpr size_t kMapDexFiles = 8;
- static constexpr size_t kMapGlobalAfterEmpty = 9;
- static constexpr size_t kMapDexFilesAfterEmpty = 12;
-
- std::shared_ptr<Memory> process_memory_;
- MemoryFake* memory_;
- std::unique_ptr<DexFiles> dex_files_;
- std::unique_ptr<BufferMaps> maps_;
-};
-
-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 head) {
- // void* first_entry_
- memory_->SetData64(addr + 16, head);
-}
-
-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(entry_addr, next);
- // uint32_t prev
- memory_->SetData32(entry_addr + 4, prev);
- // uint32_t dex_file
- memory_->SetData32(entry_addr + 8, dex_file);
-}
-
-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(entry_addr, next);
- // uint64_t prev
- memory_->SetData64(entry_addr + 8, prev);
- // uint64_t dex_file
- memory_->SetData64(entry_addr + 16, dex_file);
-}
-
-void DexFilesTest::WriteDex(uint64_t dex_file) {
- memory_->SetMemory(dex_file, kDexData, sizeof(kDexData) * sizeof(uint32_t));
-}
-
-TEST_F(DexFilesTest, get_method_information_invalid) {
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFileEntries);
-
- dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
- EXPECT_EQ("nothing", method_name);
- EXPECT_EQ(0x124U, method_offset);
-}
-
-TEST_F(DexFilesTest, get_method_information_32) {
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFiles);
-
- WriteDescriptor32(0x100800, 0x200000);
- WriteEntry32(0x200000, 0, 0, 0x300000);
- WriteDex(0x300000);
-
- dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
- EXPECT_EQ("Main.<init>", method_name);
- EXPECT_EQ(0U, method_offset);
-}
-
-TEST_F(DexFilesTest, get_method_information_64) {
- Init(ARCH_ARM64);
-
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFiles);
-
- WriteDescriptor64(0x100800, 0x200000);
- WriteEntry64(0x200000, 0, 0, 0x301000);
- WriteDex(0x301000);
-
- dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
- EXPECT_EQ("Main.<init>", method_name);
- EXPECT_EQ(2U, method_offset);
-}
-
-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(0x100800, 0x200000);
- WriteEntry32(0x200000, 0x200100, 0, 0x100000);
- WriteEntry32(0x200100, 0, 0x200000, 0x300000);
- WriteDex(0x300000);
-
- dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
- EXPECT_EQ("Main.<init>", method_name);
- EXPECT_EQ(4U, method_offset);
-}
-
-TEST_F(DexFilesTest, get_method_information_not_first_entry_64) {
- Init(ARCH_ARM64);
-
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFiles);
-
- WriteDescriptor64(0x100800, 0x200000);
- WriteEntry64(0x200000, 0x200100, 0, 0x100000);
- WriteEntry64(0x200100, 0, 0x200000, 0x300000);
- WriteDex(0x300000);
-
- dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
- EXPECT_EQ("Main.<init>", method_name);
- EXPECT_EQ(6U, method_offset);
-}
-
-TEST_F(DexFilesTest, get_method_information_cached) {
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFiles);
-
- WriteDescriptor32(0x100800, 0x200000);
- WriteEntry32(0x200000, 0, 0, 0x300000);
- WriteDex(0x300000);
-
- 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_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
- EXPECT_EQ("Main.<init>", method_name);
- EXPECT_EQ(0U, method_offset);
-}
-
-TEST_F(DexFilesTest, get_method_information_search_libs) {
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFiles);
-
- WriteDescriptor32(0x100800, 0x200000);
- 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_.reset(new DexFiles(process_memory_, libs));
- dex_files_->SetArch(ARCH_ARM);
-
- 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_.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";
- // Make sure that clearing out copy of the libs doesn't affect the
- // DexFiles object.
- libs.clear();
-
- dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
- EXPECT_EQ("Main.<init>", method_name);
- EXPECT_EQ(4U, method_offset);
-}
-
-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(0xc800, 0);
-
- WriteDescriptor32(0x100800, 0x200000);
- WriteEntry32(0x200000, 0, 0, 0x300000);
- WriteDex(0x300000);
-
- 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_.reset(new DexFiles(process_memory_));
- dex_files_->SetArch(ARCH_ARM);
- method_name = "fail";
- method_offset = 0x123;
- WriteDescriptor32(0xc800, 0x100000);
- dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
- EXPECT_EQ("fail", method_name);
- EXPECT_EQ(0x123U, method_offset);
-}
-
-TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) {
- Init(ARCH_ARM64);
-
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFiles);
-
- // First global variable found, but value is zero.
- WriteDescriptor64(0xc800, 0);
-
- WriteDescriptor64(0x100800, 0x200000);
- WriteEntry64(0x200000, 0, 0, 0x300000);
- WriteDex(0x300000);
-
- 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_.reset(new DexFiles(process_memory_));
- dex_files_->SetArch(ARCH_ARM64);
- method_name = "fail";
- method_offset = 0x123;
- WriteDescriptor64(0xc800, 0x100000);
- dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
- EXPECT_EQ("fail", method_name);
- EXPECT_EQ(0x123U, method_offset);
-}
-
-TEST_F(DexFilesTest, get_method_information_with_empty_map) {
- std::string method_name = "nothing";
- uint64_t method_offset = 0x124;
- MapInfo* info = maps_->Get(kMapDexFilesAfterEmpty);
-
- WriteDescriptor32(0x503800, 0x506000);
- WriteEntry32(0x506000, 0, 0, 0x510000);
- WriteDex(0x510000);
-
- dex_files_->GetMethodInformation(maps_.get(), info, 0x510100, &method_name, &method_offset);
- EXPECT_EQ("Main.<init>", method_name);
- EXPECT_EQ(0U, method_offset);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp
deleted file mode 100644
index 2b5a8dc..0000000
--- a/libunwindstack/tests/DwarfCfaLogTest.cpp
+++ /dev/null
@@ -1,801 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <memory>
-#include <type_traits>
-#include <unordered_map>
-
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/DwarfStructs.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/Log.h>
-
-#include "DwarfCfa.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class DwarfCfaLogTest : public ::testing::Test {
- protected:
- void SetUp() override {
- ResetLogs();
- memory_.Clear();
-
- dmem_.reset(new DwarfMemory(&memory_));
-
- cie_.cfa_instructions_offset = 0x1000;
- cie_.cfa_instructions_end = 0x1030;
- // These two values should be different to distinguish between
- // operations that deal with code versus data.
- cie_.code_alignment_factor = 4;
- cie_.data_alignment_factor = 8;
-
- fde_.cfa_instructions_offset = 0x2000;
- fde_.cfa_instructions_end = 0x2030;
- fde_.pc_start = 0x2000;
- fde_.pc_end = 0x2000;
- fde_.pc_end = 0x10000;
- fde_.cie = &cie_;
- cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_, ARCH_UNKNOWN));
- }
-
- MemoryFake memory_;
- std::unique_ptr<DwarfMemory> dmem_;
- std::unique_ptr<DwarfCfa<TypeParam>> cfa_;
- DwarfCie cie_;
- DwarfFde fde_;
-};
-TYPED_TEST_SUITE_P(DwarfCfaLogTest);
-
-// NOTE: All class variable references have to be prefaced with this->.
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_illegal) {
- for (uint8_t i = 0x17; i < 0x3f; i++) {
- if (i == 0x2d || i == 0x2e || i == 0x2f) {
- // Skip gnu extension ops and aarch64 specialized op.
- continue;
- }
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i});
-
- ResetLogs();
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
- std::string expected = "4 unwind Illegal\n";
- expected += android::base::StringPrintf("4 unwind Raw Data: 0x%02x\n", i);
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
- }
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_nop) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x00});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
- std::string expected =
- "4 unwind DW_CFA_nop\n"
- "4 unwind Raw Data: 0x00\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_offset) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x83, 0x04});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2002));
- std::string expected =
- "4 unwind DW_CFA_offset register(3) 4\n"
- "4 unwind Raw Data: 0x83 0x04\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x83, 0x84, 0x01});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2100, 0x2103));
- expected =
- "4 unwind DW_CFA_offset register(3) 132\n"
- "4 unwind Raw Data: 0x83 0x84 0x01\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x05, 0x03, 0x02});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x503));
- std::string expected =
- "4 unwind DW_CFA_offset_extended register(3) 2\n"
- "4 unwind Raw Data: 0x05 0x03 0x02\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x05, 0x81, 0x01, 0x82, 0x12});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1500, 0x1505));
- expected =
- "4 unwind DW_CFA_offset_extended register(129) 2306\n"
- "4 unwind Raw Data: 0x05 0x81 0x01 0x82 0x12\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_offset_extended_sf) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x11, 0x05, 0x10});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x503));
- std::string expected =
- "4 unwind DW_CFA_offset_extended_sf register(5) 16\n"
- "4 unwind Raw Data: 0x11 0x05 0x10\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Check a negative value for the offset.
- ResetLogs();
- this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x11, 0x86, 0x01, 0xff, 0x7f});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1500, 0x1505));
- expected =
- "4 unwind DW_CFA_offset_extended_sf register(134) -1\n"
- "4 unwind Raw Data: 0x11 0x86 0x01 0xff 0x7f\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_restore) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0xc2});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
- std::string expected =
- "4 unwind DW_CFA_restore register(2)\n"
- "4 unwind Raw Data: 0xc2\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x82, 0x04, 0xc2});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x3000, 0x3003));
- expected =
- "4 unwind DW_CFA_offset register(2) 4\n"
- "4 unwind Raw Data: 0x82 0x04\n"
- "4 unwind DW_CFA_restore register(2)\n"
- "4 unwind Raw Data: 0xc2\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_restore_extended) {
- this->memory_.SetMemory(0x4000, std::vector<uint8_t>{0x06, 0x08});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x4000, 0x4002));
- std::string expected =
- "4 unwind DW_CFA_restore_extended register(8)\n"
- "4 unwind Raw Data: 0x06 0x08\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x05, 0x82, 0x02, 0x04, 0x06, 0x82, 0x02});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x5000, 0x5007));
- expected =
- "4 unwind DW_CFA_offset_extended register(258) 4\n"
- "4 unwind Raw Data: 0x05 0x82 0x02 0x04\n"
- "4 unwind DW_CFA_restore_extended register(258)\n"
- "4 unwind Raw Data: 0x06 0x82 0x02\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_set_loc) {
- uint8_t buffer[1 + sizeof(TypeParam)];
- buffer[0] = 0x1;
- TypeParam address;
- std::string raw_data("Raw Data: 0x01 ");
- std::string address_str;
- if (std::is_same<TypeParam, uint32_t>::value) {
- address = 0x81234578U;
- address_str = "0x81234578";
- raw_data += "0x78 0x45 0x23 0x81";
- } else {
- address = 0x8123456712345678ULL;
- address_str = "0x8123456712345678";
- raw_data += "0x78 0x56 0x34 0x12 0x67 0x45 0x23 0x81";
- }
- memcpy(&buffer[1], &address, sizeof(address));
-
- this->memory_.SetMemory(0x50, buffer, sizeof(buffer));
- ResetLogs();
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam)));
- std::string expected = "4 unwind DW_CFA_set_loc " + address_str + "\n";
- expected += "4 unwind " + raw_data + "\n";
- expected += "4 unwind \n";
- expected += "4 unwind PC " + address_str + "\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Check for a set going back.
- ResetLogs();
- this->fde_.pc_start = address + 0x10;
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam)));
- expected = "4 unwind DW_CFA_set_loc " + address_str + "\n";
- expected += "4 unwind " + raw_data + "\n";
- expected += "4 unwind \n";
- expected += "4 unwind PC " + address_str + "\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc) {
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x44});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x201));
- std::string expected =
- "4 unwind DW_CFA_advance_loc 4\n"
- "4 unwind Raw Data: 0x44\n"
- "4 unwind \n"
- "4 unwind PC 0x2010\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc1) {
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x02, 0x04});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x202));
- std::string expected =
- "4 unwind DW_CFA_advance_loc1 4\n"
- "4 unwind Raw Data: 0x02 0x04\n"
- "4 unwind \n"
- "4 unwind PC 0x2004\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc2) {
- this->memory_.SetMemory(0x600, std::vector<uint8_t>{0x03, 0x04, 0x03});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x600, 0x603));
- std::string expected =
- "4 unwind DW_CFA_advance_loc2 772\n"
- "4 unwind Raw Data: 0x03 0x04 0x03\n"
- "4 unwind \n"
- "4 unwind PC 0x2304\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_advance_loc4) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x04, 0x04, 0x03, 0x02, 0x01});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x505));
- std::string expected =
- "4 unwind DW_CFA_advance_loc4 16909060\n"
- "4 unwind Raw Data: 0x04 0x04 0x03 0x02 0x01\n"
- "4 unwind \n"
- "4 unwind PC 0x1022304\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_undefined) {
- this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x07, 0x09});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0xa00, 0xa02));
- std::string expected =
- "4 unwind DW_CFA_undefined register(9)\n"
- "4 unwind Raw Data: 0x07 0x09\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- dwarf_loc_regs_t cie_loc_regs;
- this->memory_.SetMemory(0x1a00, std::vector<uint8_t>{0x07, 0x81, 0x01});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1a00, 0x1a03));
- expected =
- "4 unwind DW_CFA_undefined register(129)\n"
- "4 unwind Raw Data: 0x07 0x81 0x01\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_same) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x08, 0x7f});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
- std::string expected =
- "4 unwind DW_CFA_same_value register(127)\n"
- "4 unwind Raw Data: 0x08 0x7f\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x08, 0xff, 0x01});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2100, 0x2103));
- expected =
- "4 unwind DW_CFA_same_value register(255)\n"
- "4 unwind Raw Data: 0x08 0xff 0x01\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_register) {
- this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x300, 0x303));
- std::string expected =
- "4 unwind DW_CFA_register register(2) register(1)\n"
- "4 unwind Raw Data: 0x09 0x02 0x01\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x09, 0xff, 0x01, 0xff, 0x03});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x4300, 0x4305));
- expected =
- "4 unwind DW_CFA_register register(255) register(511)\n"
- "4 unwind Raw Data: 0x09 0xff 0x01 0xff 0x03\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_state) {
- this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x0a});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x300, 0x301));
-
- std::string expected =
- "4 unwind DW_CFA_remember_state\n"
- "4 unwind Raw Data: 0x0a\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x0b});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x4300, 0x4301));
-
- expected =
- "4 unwind DW_CFA_restore_state\n"
- "4 unwind Raw Data: 0x0b\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_state_cfa_offset_restore) {
- this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x0a, 0x0e, 0x40, 0x0b});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x3000, 0x3004));
-
- std::string expected =
- "4 unwind DW_CFA_remember_state\n"
- "4 unwind Raw Data: 0x0a\n"
- "4 unwind DW_CFA_def_cfa_offset 64\n"
- "4 unwind Raw Data: 0x0e 0x40\n"
- "4 unwind DW_CFA_restore_state\n"
- "4 unwind Raw Data: 0x0b\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0c, 0x7f, 0x74});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
-
- std::string expected =
- "4 unwind DW_CFA_def_cfa register(127) 116\n"
- "4 unwind Raw Data: 0x0c 0x7f 0x74\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0c, 0xff, 0x02, 0xf4, 0x04});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x205));
-
- expected =
- "4 unwind DW_CFA_def_cfa register(383) 628\n"
- "4 unwind Raw Data: 0x0c 0xff 0x02 0xf4 0x04\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_sf) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x12, 0x30, 0x25});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
-
- std::string expected =
- "4 unwind DW_CFA_def_cfa_sf register(48) 37\n"
- "4 unwind Raw Data: 0x12 0x30 0x25\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Test a negative value.
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x12, 0xa3, 0x01, 0xfa, 0x7f});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x205));
-
- expected =
- "4 unwind DW_CFA_def_cfa_sf register(163) -6\n"
- "4 unwind Raw Data: 0x12 0xa3 0x01 0xfa 0x7f\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_register) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0d, 0x72});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
-
- std::string expected =
- "4 unwind DW_CFA_def_cfa_register register(114)\n"
- "4 unwind Raw Data: 0x0d 0x72\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0d, 0xf9, 0x20});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x203));
-
- expected =
- "4 unwind DW_CFA_def_cfa_register register(4217)\n"
- "4 unwind Raw Data: 0x0d 0xf9 0x20\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0e, 0x59});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
-
- std::string expected =
- "4 unwind DW_CFA_def_cfa_offset 89\n"
- "4 unwind Raw Data: 0x0e 0x59\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
-
- expected =
- "4 unwind DW_CFA_def_cfa_offset 89\n"
- "4 unwind Raw Data: 0x0e 0x59\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0e, 0xd4, 0x0a});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x203));
-
- expected =
- "4 unwind DW_CFA_def_cfa_offset 1364\n"
- "4 unwind Raw Data: 0x0e 0xd4 0x0a\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_offset_sf) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x13, 0x23});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
-
- std::string expected =
- "4 unwind DW_CFA_def_cfa_offset_sf 35\n"
- "4 unwind Raw Data: 0x13 0x23\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x102));
-
- expected =
- "4 unwind DW_CFA_def_cfa_offset_sf 35\n"
- "4 unwind Raw Data: 0x13 0x23\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Negative offset.
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x13, 0xf6, 0x7f});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x203));
-
- expected =
- "4 unwind DW_CFA_def_cfa_offset_sf -10\n"
- "4 unwind Raw Data: 0x13 0xf6 0x7f\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_def_cfa_expression) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0f, 0x04, 0x01, 0x02, 0x04, 0x05});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x106));
-
- std::string expected =
- "4 unwind DW_CFA_def_cfa_expression 4\n"
- "4 unwind Raw Data: 0x0f 0x04 0x01 0x02 0x04 0x05\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0x01\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0x02\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0x04\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0x05\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- std::vector<uint8_t> ops{0x0f, 0x81, 0x01};
- expected = "4 unwind Raw Data: 0x0f 0x81 0x01";
- std::string op_string;
- for (uint8_t i = 3; i < 132; i++) {
- ops.push_back(0x05);
- op_string +=
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0x05\n";
- expected += " 0x05";
- if (((i + 1) % 10) == 0) {
- expected += "\n4 unwind Raw Data:";
- }
- }
- expected += '\n';
- this->memory_.SetMemory(0x200, ops);
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x284));
-
- expected = "4 unwind DW_CFA_def_cfa_expression 129\n" + expected;
- ASSERT_EQ(expected + op_string, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_expression) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x10, 0x04, 0x02, 0xc0, 0xc1});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x105));
-
- std::string expected =
- "4 unwind DW_CFA_expression register(4) 2\n"
- "4 unwind Raw Data: 0x10 0x04 0x02 0xc0 0xc1\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0xc0\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0xc1\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- std::vector<uint8_t> ops{0x10, 0xff, 0x01, 0x82, 0x01};
- expected = "4 unwind Raw Data: 0x10 0xff 0x01 0x82 0x01";
- std::string op_string;
- for (uint8_t i = 5; i < 135; i++) {
- ops.push_back(0xa0 + (i - 5) % 96);
- op_string += "4 unwind Illegal\n";
- op_string += android::base::StringPrintf("4 unwind Raw Data: 0x%02x\n", ops.back());
- expected += android::base::StringPrintf(" 0x%02x", ops.back());
- if (((i + 1) % 10) == 0) {
- expected += "\n4 unwind Raw Data:";
- }
- }
- expected = "4 unwind DW_CFA_expression register(255) 130\n" + expected + "\n";
-
- this->memory_.SetMemory(0x200, ops);
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x200, 0x287));
-
- ASSERT_EQ(expected + op_string, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x14, 0x45, 0x54});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
-
- std::string expected =
- "4 unwind DW_CFA_val_offset register(69) 84\n"
- "4 unwind Raw Data: 0x14 0x45 0x54\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x400, std::vector<uint8_t>{0x14, 0xa2, 0x02, 0xb4, 0x05});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x400, 0x405));
-
- expected =
- "4 unwind DW_CFA_val_offset register(290) 692\n"
- "4 unwind Raw Data: 0x14 0xa2 0x02 0xb4 0x05\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_val_offset_sf) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x15, 0x56, 0x12});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x103));
-
- std::string expected =
- "4 unwind DW_CFA_val_offset_sf register(86) 18\n"
- "4 unwind Raw Data: 0x15 0x56 0x12\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Negative value.
- ResetLogs();
- this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x15, 0xff, 0x01, 0xc0, 0x7f});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0xa00, 0xa05));
-
- expected =
- "4 unwind DW_CFA_val_offset_sf register(255) -64\n"
- "4 unwind Raw Data: 0x15 0xff 0x01 0xc0 0x7f\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_val_expression) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x16, 0x05, 0x02, 0xb0, 0xb1});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x100, 0x105));
-
- std::string expected =
- "4 unwind DW_CFA_val_expression register(5) 2\n"
- "4 unwind Raw Data: 0x16 0x05 0x02 0xb0 0xb1\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0xb0\n"
- "4 unwind Illegal\n"
- "4 unwind Raw Data: 0xb1\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- std::vector<uint8_t> ops{0x16, 0x83, 0x10, 0xa8, 0x01};
- expected = "4 unwind Raw Data: 0x16 0x83 0x10 0xa8 0x01";
- std::string op_string;
- for (uint8_t i = 0; i < 168; i++) {
- ops.push_back(0xa0 + (i % 96));
- op_string += "4 unwind Illegal\n";
- op_string += android::base::StringPrintf("4 unwind Raw Data: 0x%02x\n", ops.back());
- expected += android::base::StringPrintf(" 0x%02x", ops.back());
- if (((i + 6) % 10) == 0) {
- expected += "\n4 unwind Raw Data:";
- }
- }
- expected = "4 unwind DW_CFA_val_expression register(2051) 168\n" + expected + "\n";
-
- this->memory_.SetMemory(0xa00, ops);
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0xa00, 0xaad));
-
- ASSERT_EQ(expected + op_string, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_args_size) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2e, 0x04});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2002));
-
- std::string expected =
- "4 unwind DW_CFA_GNU_args_size 4\n"
- "4 unwind Raw Data: 0x2e 0x04\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x2e, 0xa4, 0x80, 0x04});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x5000, 0x5004));
-
- expected =
- "4 unwind DW_CFA_GNU_args_size 65572\n"
- "4 unwind Raw Data: 0x2e 0xa4 0x80 0x04\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_gnu_negative_offset_extended) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x2f, 0x08, 0x10});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x500, 0x503));
-
- std::string expected =
- "4 unwind DW_CFA_GNU_negative_offset_extended register(8) 16\n"
- "4 unwind Raw Data: 0x2f 0x08 0x10\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x2f, 0x81, 0x02, 0xff, 0x01});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x1500, 0x1505));
-
- expected =
- "4 unwind DW_CFA_GNU_negative_offset_extended register(257) 255\n"
- "4 unwind Raw Data: 0x2f 0x81 0x02 0xff 0x01\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_register_override) {
- this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01, 0x09, 0x02, 0x04});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x300, 0x306));
-
- std::string expected =
- "4 unwind DW_CFA_register register(2) register(1)\n"
- "4 unwind Raw Data: 0x09 0x02 0x01\n"
- "4 unwind DW_CFA_register register(2) register(4)\n"
- "4 unwind Raw Data: 0x09 0x02 0x04\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaLogTest, cfa_aarch64_negate_ra_state) {
- // Verify that if the cfa op is handled properly depending on aarch.
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2d});
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
- std::string expected = "4 unwind Illegal (Only valid on aarch64)\n";
- expected += "4 unwind Raw Data: 0x2d\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->cfa_.reset(new DwarfCfa<TypeParam>(this->dmem_.get(), &this->fde_, ARCH_ARM64));
-
- ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001));
- expected = "4 unwind DW_CFA_AARCH64_negate_ra_state\n";
- expected += "4 unwind Raw Data: 0x2d\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-REGISTER_TYPED_TEST_SUITE_P(DwarfCfaLogTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended,
- cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc,
- cfa_advance_loc, cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4,
- cfa_undefined, cfa_same, cfa_register, cfa_state,
- cfa_state_cfa_offset_restore, cfa_def_cfa, cfa_def_cfa_sf,
- cfa_def_cfa_register, cfa_def_cfa_offset, cfa_def_cfa_offset_sf,
- cfa_def_cfa_expression, cfa_expression, cfa_val_offset,
- cfa_val_offset_sf, cfa_val_expression, cfa_gnu_args_size,
- cfa_gnu_negative_offset_extended, cfa_register_override,
- cfa_aarch64_negate_ra_state);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaLogTest, DwarfCfaLogTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp
deleted file mode 100644
index ea7e708..0000000
--- a/libunwindstack/tests/DwarfCfaTest.cpp
+++ /dev/null
@@ -1,1021 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <memory>
-#include <unordered_map>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/DwarfStructs.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/MachineArm64.h>
-
-#include "DwarfCfa.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class DwarfCfaTest : public ::testing::Test {
- protected:
- void SetUp() override {
- ResetLogs();
- memory_.Clear();
-
- dmem_.reset(new DwarfMemory(&memory_));
-
- cie_.cfa_instructions_offset = 0x1000;
- cie_.cfa_instructions_end = 0x1030;
- // These two values should be different to distinguish between
- // operations that deal with code versus data.
- cie_.code_alignment_factor = 4;
- cie_.data_alignment_factor = 8;
-
- fde_.cfa_instructions_offset = 0x2000;
- fde_.cfa_instructions_end = 0x2030;
- fde_.pc_start = 0x2000;
- fde_.cie = &cie_;
-
- cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_, ARCH_UNKNOWN));
- }
-
- MemoryFake memory_;
- std::unique_ptr<DwarfMemory> dmem_;
- std::unique_ptr<DwarfCfa<TypeParam>> cfa_;
- DwarfCie cie_;
- DwarfFde fde_;
-};
-TYPED_TEST_SUITE_P(DwarfCfaTest);
-
-// NOTE: All test class variables need to be referenced as this->.
-
-TYPED_TEST_P(DwarfCfaTest, cfa_illegal) {
- for (uint8_t i = 0x17; i < 0x3f; i++) {
- if (i == 0x2d || i == 0x2e || i == 0x2f) {
- // Skip gnu extension ops and aarch64 specialized op.
- continue;
- }
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode());
- ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
- }
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_nop) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x00});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-// This test needs to be examined.
-TYPED_TEST_P(DwarfCfaTest, cfa_offset) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x83, 0x04});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2002, &loc_regs));
- ASSERT_EQ(0x2002U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(3);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(32U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x83, 0x84, 0x01});
- loc_regs.clear();
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2100, 0x2103, &loc_regs));
- ASSERT_EQ(0x2103U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(3);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(1056U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_offset_extended) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x05, 0x03, 0x02});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x503, &loc_regs));
- ASSERT_EQ(0x503U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(3);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(2U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x05, 0x81, 0x01, 0x82, 0x12});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1500, 0x1505, &loc_regs));
- ASSERT_EQ(0x1505U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(129);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(2306U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_offset_extended_sf) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x11, 0x05, 0x10});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x503, &loc_regs));
- ASSERT_EQ(0x503U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(5);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(0x80U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Check a negative value for the offset.
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x11, 0x86, 0x01, 0xff, 0x7f});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1500, 0x1505, &loc_regs));
- ASSERT_EQ(0x1505U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(134);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(static_cast<uint64_t>(-8), location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_restore) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0xc2});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
- ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("4 unwind restore while processing cie\n", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- dwarf_loc_regs_t cie_loc_regs;
- cie_loc_regs[2] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
- this->cfa_->set_cie_loc_regs(&cie_loc_regs);
- this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x82, 0x04, 0xc2});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x3000, 0x3003, &loc_regs));
- ASSERT_EQ(0x3003U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(2);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_restore_extended) {
- this->memory_.SetMemory(0x4000, std::vector<uint8_t>{0x06, 0x08});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4000, 0x4002, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
- ASSERT_EQ(0x4002U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("4 unwind restore while processing cie\n", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x05, 0x82, 0x02, 0x04, 0x06, 0x82, 0x02});
- dwarf_loc_regs_t cie_loc_regs;
- cie_loc_regs[258] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
- this->cfa_->set_cie_loc_regs(&cie_loc_regs);
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x5000, 0x5007, &loc_regs));
- ASSERT_EQ(0x5007U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(258);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_set_loc) {
- uint8_t buffer[1 + sizeof(TypeParam)];
- buffer[0] = 0x1;
- TypeParam address;
- std::string raw_data("Raw Data: 0x01 ");
- std::string address_str;
- if (sizeof(TypeParam) == 4) {
- address = 0x81234578U;
- address_str = "0x81234578";
- raw_data += "0x78 0x45 0x23 0x81";
- } else {
- address = 0x8123456712345678ULL;
- address_str = "0x8123456712345678";
- raw_data += "0x78 0x56 0x34 0x12 0x67 0x45 0x23 0x81";
- }
- memcpy(&buffer[1], &address, sizeof(address));
-
- this->memory_.SetMemory(0x50, buffer, sizeof(buffer));
- ResetLogs();
- dwarf_loc_regs_t loc_regs;
- ASSERT_TRUE(
- this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam), &loc_regs));
- ASSERT_EQ(0x51 + sizeof(TypeParam), this->dmem_->cur_offset());
- ASSERT_EQ(address, this->cfa_->cur_pc());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Check for a set going back.
- ResetLogs();
- loc_regs.clear();
- this->fde_.pc_start = address + 0x10;
- ASSERT_TRUE(
- this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x50, 0x51 + sizeof(TypeParam), &loc_regs));
- ASSERT_EQ(0x51 + sizeof(TypeParam), this->dmem_->cur_offset());
- ASSERT_EQ(address, this->cfa_->cur_pc());
- ASSERT_EQ(0U, loc_regs.size());
-
- std::string cur_address_str(address_str);
- cur_address_str[cur_address_str.size() - 2] = '8';
- std::string expected = "4 unwind Warning: PC is moving backwards: old " + cur_address_str +
- " new " + address_str + "\n";
- ASSERT_EQ(expected, GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_advance_loc1) {
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x02, 0x04});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x202, &loc_regs));
- ASSERT_EQ(0x202U, this->dmem_->cur_offset());
- ASSERT_EQ(this->fde_.pc_start + 0x10, this->cfa_->cur_pc());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_advance_loc2) {
- this->memory_.SetMemory(0x600, std::vector<uint8_t>{0x03, 0x04, 0x03});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x600, 0x603, &loc_regs));
- ASSERT_EQ(0x603U, this->dmem_->cur_offset());
- ASSERT_EQ(this->fde_.pc_start + 0xc10U, this->cfa_->cur_pc());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_advance_loc4) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x04, 0x04, 0x03, 0x02, 0x01});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x505, &loc_regs));
- ASSERT_EQ(0x505U, this->dmem_->cur_offset());
- ASSERT_EQ(this->fde_.pc_start + 0x4080c10, this->cfa_->cur_pc());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_undefined) {
- this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x07, 0x09});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0xa00, 0xa02, &loc_regs));
- ASSERT_EQ(0xa02U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(9);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_UNDEFINED, location->second.type);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x1a00, std::vector<uint8_t>{0x07, 0x81, 0x01});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1a00, 0x1a03, &loc_regs));
- ASSERT_EQ(0x1a03U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(129);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_UNDEFINED, location->second.type);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_same) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x08, 0x7f});
- dwarf_loc_regs_t loc_regs;
-
- loc_regs[127] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(0x102U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ(0U, loc_regs.count(127));
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x2100, std::vector<uint8_t>{0x08, 0xff, 0x01});
-
- loc_regs[255] = {.type = DWARF_LOCATION_REGISTER, .values = {0, 0}};
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2100, 0x2103, &loc_regs));
- ASSERT_EQ(0x2103U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ(0U, loc_regs.count(255));
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_register) {
- this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x300, 0x303, &loc_regs));
- ASSERT_EQ(0x303U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(2);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
- ASSERT_EQ(1U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x09, 0xff, 0x01, 0xff, 0x03});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4300, 0x4305, &loc_regs));
- ASSERT_EQ(0x4305U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(255);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
- ASSERT_EQ(511U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_state) {
- this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x0a});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x300, 0x301, &loc_regs));
- ASSERT_EQ(0x301U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x4300, std::vector<uint8_t>{0x0b});
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x4300, 0x4301, &loc_regs));
- ASSERT_EQ(0x4301U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x85, 0x02, 0x0a, 0x86, 0x04, 0x0b});
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2005, &loc_regs));
- ASSERT_EQ(0x2005U, this->dmem_->cur_offset());
- ASSERT_EQ(2U, loc_regs.size());
- ASSERT_NE(loc_regs.end(), loc_regs.find(5));
- ASSERT_NE(loc_regs.end(), loc_regs.find(6));
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2006, &loc_regs));
- ASSERT_EQ(0x2006U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_NE(loc_regs.end(), loc_regs.find(5));
-
- ResetLogs();
- this->memory_.SetMemory(
- 0x6000, std::vector<uint8_t>{0x0a, 0x85, 0x02, 0x0a, 0x86, 0x04, 0x0a, 0x87, 0x01, 0x0a, 0x89,
- 0x05, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b});
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600c, &loc_regs));
- ASSERT_EQ(0x600cU, this->dmem_->cur_offset());
- ASSERT_EQ(4U, loc_regs.size());
- ASSERT_NE(loc_regs.end(), loc_regs.find(5));
- ASSERT_NE(loc_regs.end(), loc_regs.find(6));
- ASSERT_NE(loc_regs.end(), loc_regs.find(7));
- ASSERT_NE(loc_regs.end(), loc_regs.find(9));
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600d, &loc_regs));
- ASSERT_EQ(0x600dU, this->dmem_->cur_offset());
- ASSERT_EQ(3U, loc_regs.size());
- ASSERT_NE(loc_regs.end(), loc_regs.find(5));
- ASSERT_NE(loc_regs.end(), loc_regs.find(6));
- ASSERT_NE(loc_regs.end(), loc_regs.find(7));
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600e, &loc_regs));
- ASSERT_EQ(0x600eU, this->dmem_->cur_offset());
- ASSERT_EQ(2U, loc_regs.size());
- ASSERT_NE(loc_regs.end(), loc_regs.find(5));
- ASSERT_NE(loc_regs.end(), loc_regs.find(6));
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x600f, &loc_regs));
- ASSERT_EQ(0x600fU, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_NE(loc_regs.end(), loc_regs.find(5));
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x6010, &loc_regs));
- ASSERT_EQ(0x6010U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x6000, 0x6011, &loc_regs));
- ASSERT_EQ(0x6011U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-}
-
-// This test verifies that the cfa offset is saved and restored properly.
-// Even though the spec is not clear about whether the offset is also
-// restored, the gcc unwinder does, and libunwind does too.
-TYPED_TEST_P(DwarfCfaTest, cfa_state_cfa_offset_restore) {
- this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x0a, 0x0e, 0x40, 0x0b});
- dwarf_loc_regs_t loc_regs;
- loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {5, 100}};
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x3000, 0x3004, &loc_regs));
- ASSERT_EQ(0x3004U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(5U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(100U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0c, 0x7f, 0x74});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
- ASSERT_EQ(0x103U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(0x7fU, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(0x74U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0c, 0xff, 0x02, 0xf4, 0x04});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x205, &loc_regs));
- ASSERT_EQ(0x205U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(0x17fU, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(0x274U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_sf) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x12, 0x30, 0x25});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
- ASSERT_EQ(0x103U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(0x30U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(0x128U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Test a negative value.
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x12, 0xa3, 0x01, 0xfa, 0x7f});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x205, &loc_regs));
- ASSERT_EQ(0x205U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(0xa3U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(static_cast<uint64_t>(-48), loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_register) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0d, 0x72});
- dwarf_loc_regs_t loc_regs;
-
- // This fails because the cfa is not defined as a register.
- ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
-
- ASSERT_EQ("4 unwind Attempt to set new register, but cfa is not already set to a register.\n",
- GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3, 20}};
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(0x102U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(0x72U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(20U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0d, 0xf9, 0x20});
- loc_regs.clear();
- loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3, 60}};
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x203, &loc_regs));
- ASSERT_EQ(0x203U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(0x1079U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(60U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_offset) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0e, 0x59});
- dwarf_loc_regs_t loc_regs;
-
- // This fails because the cfa is not defined as a register.
- ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(0U, loc_regs.size());
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
-
- ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
- GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(0x102U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(0x59U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x0e, 0xd4, 0x0a});
- loc_regs.clear();
- loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x203, &loc_regs));
- ASSERT_EQ(0x203U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(0x554U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_offset_sf) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x13, 0x23});
- dwarf_loc_regs_t loc_regs;
-
- // This fails because the cfa is not defined as a register.
- ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->cfa_->LastErrorCode());
-
- ASSERT_EQ("4 unwind Attempt to set offset, but cfa is not set to a register.\n",
- GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x102, &loc_regs));
- ASSERT_EQ(0x102U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(0x118U, loc_regs[CFA_REG].values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Negative offset.
- ResetLogs();
- this->memory_.SetMemory(0x200, std::vector<uint8_t>{0x13, 0xf6, 0x7f});
- loc_regs.clear();
- loc_regs[CFA_REG] = {.type = DWARF_LOCATION_REGISTER, .values = {3}};
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x203, &loc_regs));
- ASSERT_EQ(0x203U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, loc_regs[CFA_REG].type);
- ASSERT_EQ(3U, loc_regs[CFA_REG].values[0]);
- ASSERT_EQ(static_cast<TypeParam>(-80), static_cast<TypeParam>(loc_regs[CFA_REG].values[1]));
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_def_cfa_expression) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x0f, 0x04, 0x01, 0x02, 0x03, 0x04});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x106, &loc_regs));
- ASSERT_EQ(0x106U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- std::vector<uint8_t> ops{0x0f, 0x81, 0x01};
- for (uint8_t i = 3; i < 132; i++) {
- ops.push_back(i - 1);
- }
- this->memory_.SetMemory(0x200, ops);
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x284, &loc_regs));
- ASSERT_EQ(0x284U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- ASSERT_EQ(DWARF_LOCATION_VAL_EXPRESSION, loc_regs[CFA_REG].type);
- ASSERT_EQ(0x81U, loc_regs[CFA_REG].values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_expression) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x10, 0x04, 0x02, 0x40, 0x20});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x105, &loc_regs));
- ASSERT_EQ(0x105U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(4);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_EXPRESSION, location->second.type);
- ASSERT_EQ(2U, location->second.values[0]);
- ASSERT_EQ(0x105U, location->second.values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- std::vector<uint8_t> ops{0x10, 0xff, 0x01, 0x82, 0x01};
- for (uint8_t i = 5; i < 135; i++) {
- ops.push_back(i - 4);
- }
-
- this->memory_.SetMemory(0x200, ops);
- loc_regs.clear();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x200, 0x287, &loc_regs));
- ASSERT_EQ(0x287U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(255);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_EXPRESSION, location->second.type);
- ASSERT_EQ(130U, location->second.values[0]);
- ASSERT_EQ(0x287U, location->second.values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_val_offset) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x14, 0x45, 0x54});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
- ASSERT_EQ(0x103U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(69);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
- ASSERT_EQ(0x2a0U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x400, std::vector<uint8_t>{0x14, 0xa2, 0x02, 0xb4, 0x05});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x400, 0x405, &loc_regs));
- ASSERT_EQ(0x405U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(290);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
- ASSERT_EQ(0x15a0U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_val_offset_sf) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x15, 0x56, 0x12});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x103, &loc_regs));
- ASSERT_EQ(0x103U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(86);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
- ASSERT_EQ(0x90U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Negative value.
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0xa00, std::vector<uint8_t>{0x15, 0xff, 0x01, 0xc0, 0x7f});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0xa00, 0xa05, &loc_regs));
- ASSERT_EQ(0xa05U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(255);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_VAL_OFFSET, location->second.type);
- ASSERT_EQ(static_cast<uint64_t>(-512), location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_val_expression) {
- this->memory_.SetMemory(0x100, std::vector<uint8_t>{0x16, 0x05, 0x02, 0x10, 0x20});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x100, 0x105, &loc_regs));
- ASSERT_EQ(0x105U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(5);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_VAL_EXPRESSION, location->second.type);
- ASSERT_EQ(2U, location->second.values[0]);
- ASSERT_EQ(0x105U, location->second.values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- std::vector<uint8_t> ops{0x16, 0x83, 0x10, 0xa8, 0x01};
- for (uint8_t i = 0; i < 168; i++) {
- ops.push_back(i);
- }
-
- this->memory_.SetMemory(0xa00, ops);
- loc_regs.clear();
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0xa00, 0xaad, &loc_regs));
- ASSERT_EQ(0xaadU, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(2051);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_VAL_EXPRESSION, location->second.type);
- ASSERT_EQ(168U, location->second.values[0]);
- ASSERT_EQ(0xaadU, location->second.values[1]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_gnu_args_size) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2e, 0x04});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2002, &loc_regs));
- ASSERT_EQ(0x2002U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x2e, 0xa4, 0x80, 0x04});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x5000, 0x5004, &loc_regs));
- ASSERT_EQ(0x5004U, this->dmem_->cur_offset());
- ASSERT_EQ(0U, loc_regs.size());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_gnu_negative_offset_extended) {
- this->memory_.SetMemory(0x500, std::vector<uint8_t>{0x2f, 0x08, 0x10});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x500, 0x503, &loc_regs));
- ASSERT_EQ(0x503U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(8);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(static_cast<uint64_t>(-16), location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- loc_regs.clear();
- this->memory_.SetMemory(0x1500, std::vector<uint8_t>{0x2f, 0x81, 0x02, 0xff, 0x01});
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x1500, 0x1505, &loc_regs));
- ASSERT_EQ(0x1505U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- location = loc_regs.find(257);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_OFFSET, location->second.type);
- ASSERT_EQ(static_cast<uint64_t>(-255), location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_register_override) {
- this->memory_.SetMemory(0x300, std::vector<uint8_t>{0x09, 0x02, 0x01, 0x09, 0x02, 0x04});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x300, 0x306, &loc_regs));
- ASSERT_EQ(0x306U, this->dmem_->cur_offset());
- ASSERT_EQ(1U, loc_regs.size());
- auto location = loc_regs.find(2);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_REGISTER, location->second.type);
- ASSERT_EQ(4U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-TYPED_TEST_P(DwarfCfaTest, cfa_aarch64_negate_ra_state) {
- this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2d});
- dwarf_loc_regs_t loc_regs;
-
- ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode());
- ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- ResetLogs();
- this->cfa_.reset(new DwarfCfa<TypeParam>(this->dmem_.get(), &this->fde_, ARCH_ARM64));
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
-
- auto location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type);
- ASSERT_EQ(1U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Verify that the value is set to 0 after another evaluation.
- ResetLogs();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
-
- location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type);
- ASSERT_EQ(0U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-
- // Verify that the value is set to 1 again after a third op.
- ResetLogs();
- ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs));
- ASSERT_EQ(0x2001U, this->dmem_->cur_offset());
-
- location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE);
- ASSERT_NE(loc_regs.end(), location);
- ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type);
- ASSERT_EQ(1U, location->second.values[0]);
-
- ASSERT_EQ("", GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-REGISTER_TYPED_TEST_SUITE_P(DwarfCfaTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended,
- cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc,
- cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4, cfa_undefined,
- cfa_same, cfa_register, cfa_state, cfa_state_cfa_offset_restore,
- cfa_def_cfa, cfa_def_cfa_sf, cfa_def_cfa_register, cfa_def_cfa_offset,
- cfa_def_cfa_offset_sf, cfa_def_cfa_expression, cfa_expression,
- cfa_val_offset, cfa_val_offset_sf, cfa_val_expression,
- cfa_gnu_args_size, cfa_gnu_negative_offset_extended,
- cfa_register_override, cfa_aarch64_negate_ra_state);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaTest, DwarfCfaTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
deleted file mode 100644
index fac8a0e..0000000
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ /dev/null
@@ -1,888 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfError.h>
-
-#include "DwarfDebugFrame.h"
-#include "DwarfEncoding.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class DwarfDebugFrameTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_.Clear();
- debug_frame_ = new DwarfDebugFrame<TypeParam>(&memory_);
- ResetLogs();
- }
-
- void TearDown() override { delete debug_frame_; }
-
- MemoryFake memory_;
- DwarfDebugFrame<TypeParam>* debug_frame_ = nullptr;
-};
-TYPED_TEST_SUITE_P(DwarfDebugFrameTest);
-
-// NOTE: All test class variables need to be referenced as this->.
-
-static void SetCie32(MemoryFake* memory, uint64_t offset, uint32_t length,
- std::vector<uint8_t> data) {
- memory->SetData32(offset, length);
- offset += 4;
- // Indicates this is a cie.
- memory->SetData32(offset, 0xffffffff);
- offset += 4;
- memory->SetMemory(offset, data);
-}
-
-static void SetCie64(MemoryFake* memory, uint64_t offset, uint64_t length,
- std::vector<uint8_t> data) {
- memory->SetData32(offset, 0xffffffff);
- offset += 4;
- memory->SetData64(offset, length);
- offset += 8;
- // Indicates this is a cie.
- memory->SetData64(offset, 0xffffffffffffffffUL);
- offset += 8;
- memory->SetMemory(offset, data);
-}
-
-static void SetFde32(MemoryFake* memory, uint64_t offset, uint32_t length, uint64_t cie_offset,
- uint32_t pc_start, uint32_t pc_length, uint64_t segment_length = 0,
- std::vector<uint8_t>* data = nullptr) {
- memory->SetData32(offset, length);
- offset += 4;
- memory->SetData32(offset, cie_offset);
- offset += 4 + segment_length;
- memory->SetData32(offset, pc_start);
- offset += 4;
- memory->SetData32(offset, pc_length);
- if (data != nullptr) {
- offset += 4;
- memory->SetMemory(offset, *data);
- }
-}
-
-static void SetFde64(MemoryFake* memory, uint64_t offset, uint64_t length, uint64_t cie_offset,
- uint64_t pc_start, uint64_t pc_length, uint64_t segment_length = 0,
- std::vector<uint8_t>* data = nullptr) {
- memory->SetData32(offset, 0xffffffff);
- offset += 4;
- memory->SetData64(offset, length);
- offset += 8;
- memory->SetData64(offset, cie_offset);
- offset += 8 + segment_length;
- memory->SetData64(offset, pc_start);
- offset += 8;
- memory->SetData64(offset, pc_length);
- if (data != nullptr) {
- offset += 8;
- memory->SetMemory(offset, *data);
- }
-}
-
-static void SetFourFdes32(MemoryFake* memory) {
- SetCie32(memory, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
-
- // FDE 32 information.
- SetFde32(memory, 0x5100, 0xfc, 0, 0x1500, 0x200);
- SetFde32(memory, 0x5200, 0xfc, 0, 0x2500, 0x300);
-
- // CIE 32 information.
- SetCie32(memory, 0x5300, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
-
- // FDE 32 information.
- SetFde32(memory, 0x5400, 0xfc, 0x300, 0x3500, 0x400);
- SetFde32(memory, 0x5500, 0xfc, 0x300, 0x4500, 0x500);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32) {
- SetFourFdes32(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- std::vector<const DwarfFde*> fdes;
- this->debug_frame_->GetFdes(&fdes);
-
- ASSERT_EQ(4U, fdes.size());
-
- EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
- EXPECT_EQ(0x5110U, fdes[0]->cfa_instructions_offset);
- EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
- EXPECT_EQ(0x1500U, fdes[0]->pc_start);
- EXPECT_EQ(0x1700U, fdes[0]->pc_end);
- EXPECT_EQ(0U, fdes[0]->lsda_address);
- EXPECT_TRUE(fdes[0]->cie != nullptr);
-
- EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
- EXPECT_EQ(0x5210U, fdes[1]->cfa_instructions_offset);
- EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
- EXPECT_EQ(0x2500U, fdes[1]->pc_start);
- EXPECT_EQ(0x2800U, fdes[1]->pc_end);
- EXPECT_EQ(0U, fdes[1]->lsda_address);
- EXPECT_TRUE(fdes[1]->cie != nullptr);
-
- EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
- EXPECT_EQ(0x5410U, fdes[2]->cfa_instructions_offset);
- EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
- EXPECT_EQ(0x3500U, fdes[2]->pc_start);
- EXPECT_EQ(0x3900U, fdes[2]->pc_end);
- EXPECT_EQ(0U, fdes[2]->lsda_address);
- EXPECT_TRUE(fdes[2]->cie != nullptr);
-
- EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
- EXPECT_EQ(0x5510U, fdes[3]->cfa_instructions_offset);
- EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
- EXPECT_EQ(0x4500U, fdes[3]->pc_start);
- EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
- EXPECT_EQ(0U, fdes[3]->lsda_address);
- EXPECT_TRUE(fdes[3]->cie != nullptr);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_after_GetFdeFromPc) {
- SetFourFdes32(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x3600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x3500U, fde->pc_start);
- EXPECT_EQ(0x3900U, fde->pc_end);
-
- std::vector<const DwarfFde*> fdes;
- this->debug_frame_->GetFdes(&fdes);
- ASSERT_EQ(4U, fdes.size());
-
- // Verify that they got added in the correct order.
- EXPECT_EQ(0x1500U, fdes[0]->pc_start);
- EXPECT_EQ(0x1700U, fdes[0]->pc_end);
- EXPECT_EQ(0x2500U, fdes[1]->pc_start);
- EXPECT_EQ(0x2800U, fdes[1]->pc_end);
- EXPECT_EQ(0x3500U, fdes[2]->pc_start);
- EXPECT_EQ(0x3900U, fdes[2]->pc_end);
- EXPECT_EQ(0x4500U, fdes[3]->pc_start);
- EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_not_in_section) {
- SetFourFdes32(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
-
- std::vector<const DwarfFde*> fdes;
- this->debug_frame_->GetFdes(&fdes);
-
- ASSERT_EQ(3U, fdes.size());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32) {
- SetFourFdes32(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x1500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x2600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x2500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x3600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x3500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x4500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0);
- ASSERT_TRUE(fde == nullptr);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_reverse) {
- SetFourFdes32(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x4500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x3600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x3500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x2600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x2500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x1600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x1500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0);
- ASSERT_TRUE(fde == nullptr);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_not_in_section) {
- SetFourFdes32(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde == nullptr);
-}
-
-static void SetFourFdes64(MemoryFake* memory) {
- // CIE 64 information.
- SetCie64(memory, 0x5000, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
-
- // FDE 64 information.
- SetFde64(memory, 0x5100, 0xf4, 0, 0x1500, 0x200);
- SetFde64(memory, 0x5200, 0xf4, 0, 0x2500, 0x300);
-
- // CIE 64 information.
- SetCie64(memory, 0x5300, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
-
- // FDE 64 information.
- SetFde64(memory, 0x5400, 0xf4, 0x300, 0x3500, 0x400);
- SetFde64(memory, 0x5500, 0xf4, 0x300, 0x4500, 0x500);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64) {
- SetFourFdes64(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- std::vector<const DwarfFde*> fdes;
- this->debug_frame_->GetFdes(&fdes);
-
- ASSERT_EQ(4U, fdes.size());
-
- EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
- EXPECT_EQ(0x5124U, fdes[0]->cfa_instructions_offset);
- EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
- EXPECT_EQ(0x1500U, fdes[0]->pc_start);
- EXPECT_EQ(0x1700U, fdes[0]->pc_end);
- EXPECT_EQ(0U, fdes[0]->lsda_address);
- EXPECT_TRUE(fdes[0]->cie != nullptr);
-
- EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
- EXPECT_EQ(0x5224U, fdes[1]->cfa_instructions_offset);
- EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
- EXPECT_EQ(0x2500U, fdes[1]->pc_start);
- EXPECT_EQ(0x2800U, fdes[1]->pc_end);
- EXPECT_EQ(0U, fdes[1]->lsda_address);
- EXPECT_TRUE(fdes[1]->cie != nullptr);
-
- EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
- EXPECT_EQ(0x5424U, fdes[2]->cfa_instructions_offset);
- EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
- EXPECT_EQ(0x3500U, fdes[2]->pc_start);
- EXPECT_EQ(0x3900U, fdes[2]->pc_end);
- EXPECT_EQ(0U, fdes[2]->lsda_address);
- EXPECT_TRUE(fdes[2]->cie != nullptr);
-
- EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
- EXPECT_EQ(0x5524U, fdes[3]->cfa_instructions_offset);
- EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
- EXPECT_EQ(0x4500U, fdes[3]->pc_start);
- EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
- EXPECT_EQ(0U, fdes[3]->lsda_address);
- EXPECT_TRUE(fdes[3]->cie != nullptr);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_after_GetFdeFromPc) {
- SetFourFdes64(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x2500U, fde->pc_start);
- EXPECT_EQ(0x2800U, fde->pc_end);
-
- std::vector<const DwarfFde*> fdes;
- this->debug_frame_->GetFdes(&fdes);
- ASSERT_EQ(4U, fdes.size());
-
- // Verify that they got added in the correct order.
- EXPECT_EQ(0x1500U, fdes[0]->pc_start);
- EXPECT_EQ(0x1700U, fdes[0]->pc_end);
- EXPECT_EQ(0x2500U, fdes[1]->pc_start);
- EXPECT_EQ(0x2800U, fdes[1]->pc_end);
- EXPECT_EQ(0x3500U, fdes[2]->pc_start);
- EXPECT_EQ(0x3900U, fdes[2]->pc_end);
- EXPECT_EQ(0x4500U, fdes[3]->pc_start);
- EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_not_in_section) {
- SetFourFdes64(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
-
- std::vector<const DwarfFde*> fdes;
- this->debug_frame_->GetFdes(&fdes);
-
- ASSERT_EQ(3U, fdes.size());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64) {
- SetFourFdes64(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x1500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x2600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x2500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x3600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x3500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x4500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0);
- ASSERT_TRUE(fde == nullptr);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_reverse) {
- SetFourFdes64(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x4500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x3600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x3500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x2600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x2500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0x1600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x1500U, fde->pc_start);
-
- fde = this->debug_frame_->GetFdeFromPc(0);
- ASSERT_TRUE(fde == nullptr);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_not_in_section) {
- SetFourFdes64(&this->memory_);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde == nullptr);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde32) {
- SetCie32(&this->memory_, 0xf000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
- SetFde32(&this->memory_, 0x14000, 0x20, 0xf000, 0x9000, 0x100);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x14000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x9000U, fde->pc_start);
- EXPECT_EQ(0x9100U, fde->pc_end);
- EXPECT_EQ(0xf000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0xf00dU, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0xf104U, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde64) {
- SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
- SetFde64(&this->memory_, 0x8000, 0x200, 0x6000, 0x5000, 0x300);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x8000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5300U, fde->pc_end);
- EXPECT_EQ(0x6000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata8, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0x6019U, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0x610cU, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
-}
-
-static void VerifyCieVersion(const DwarfCie* cie, uint8_t version, uint8_t segment_size,
- uint8_t fde_encoding, uint64_t return_address, uint64_t start_offset,
- uint64_t end_offset) {
- EXPECT_EQ(version, cie->version);
- EXPECT_EQ(fde_encoding, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(segment_size, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(return_address, cie->return_address_register);
- EXPECT_EQ(0x5000U + start_offset, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5000U + end_offset, cie->cfa_instructions_end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_cie_cached) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
-
- std::vector<uint8_t> zero(0x100, 0);
- this->memory_.SetMemory(0x5000, zero);
- cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_cie_cached) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
-
- std::vector<uint8_t> zero(0x100, 0);
- this->memory_.SetMemory(0x5000, zero);
- cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version1) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version1) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version3) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata4, 0x181, 0xe, 0x104);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version3) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata8, 0x181, 0x1a, 0x10c);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version4) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version4) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version5) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 0, 10, 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 5, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version5) {
- SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{5, '\0', 0, 10, 4, 8, 0x81, 3});
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- ASSERT_TRUE(cie != nullptr);
- VerifyCieVersion(cie, 5, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset_version_invalid) {
- SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
- ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
- SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
- ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x6000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
-
- SetCie32(&this->memory_, 0x7000, 0x100, std::vector<uint8_t>{6, '\0', 1, 2, 3, 4, 5, 6, 7});
- ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x7000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
- SetCie64(&this->memory_, 0x8000, 0x100, std::vector<uint8_t>{6, '\0', 1, 2, 3, 4, 5, 6, 7});
- ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x8000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
-}
-
-static void VerifyCieAugment(const DwarfCie* cie, uint64_t inst_offset, uint64_t inst_end) {
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_udata2, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_textrel | DW_EH_PE_udata2, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(5U, cie->augmentation_string.size());
- EXPECT_EQ('z', cie->augmentation_string[0]);
- EXPECT_EQ('L', cie->augmentation_string[1]);
- EXPECT_EQ('P', cie->augmentation_string[2]);
- EXPECT_EQ('R', cie->augmentation_string[3]);
- EXPECT_EQ('\0', cie->augmentation_string[4]);
- EXPECT_EQ(0x12345678U, cie->personality_handler);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x10U, cie->return_address_register);
- EXPECT_EQ(inst_offset, cie->cfa_instructions_offset);
- EXPECT_EQ(inst_end, cie->cfa_instructions_end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_augment) {
- SetCie32(&this->memory_, 0x5000, 0x100,
- std::vector<uint8_t>{/* version */ 1,
- /* augment string */ 'z', 'L', 'P', 'R', '\0',
- /* code alignment factor */ 4,
- /* data alignment factor */ 8,
- /* return address register */ 0x10,
- /* augment length */ 0xf,
- /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
- /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
- /* R data */ DW_EH_PE_udata2});
-
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- ASSERT_TRUE(cie != nullptr);
- VerifyCieAugment(cie, 0x5021, 0x5104);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_augment) {
- SetCie64(&this->memory_, 0x5000, 0x100,
- std::vector<uint8_t>{/* version */ 1,
- /* augment string */ 'z', 'L', 'P', 'R', '\0',
- /* code alignment factor */ 4,
- /* data alignment factor */ 8,
- /* return address register */ 0x10,
- /* augment length */ 0xf,
- /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
- /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
- /* R data */ DW_EH_PE_udata2});
-
- const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
- ASSERT_TRUE(cie != nullptr);
- VerifyCieAugment(cie, 0x502d, 0x510c);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_augment) {
- SetCie32(&this->memory_, 0x5000, 0xfc,
- std::vector<uint8_t>{/* version */ 4,
- /* augment string */ 'z', '\0',
- /* address size */ 8,
- /* segment size */ 0x10,
- /* code alignment factor */ 16,
- /* data alignment factor */ 32,
- /* return address register */ 10,
- /* augment length */ 0x0});
-
- std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
- SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(4U, fde->cie->version);
- EXPECT_EQ(0x5000U, fde->cie_offset);
- EXPECT_EQ(0x53a2U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
- EXPECT_EQ(0x4300U, fde->pc_start);
- EXPECT_EQ(0x4600U, fde->pc_end);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_augment) {
- SetCie64(&this->memory_, 0x5000, 0xfc,
- std::vector<uint8_t>{/* version */ 4,
- /* augment string */ 'z', '\0',
- /* address size */ 8,
- /* segment size */ 0x10,
- /* code alignment factor */ 16,
- /* data alignment factor */ 32,
- /* return address register */ 10,
- /* augment length */ 0x0});
-
- std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
- SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(4U, fde->cie->version);
- EXPECT_EQ(0x5000U, fde->cie_offset);
- EXPECT_EQ(0x53b6U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
- EXPECT_EQ(0x4300U, fde->pc_start);
- EXPECT_EQ(0x4600U, fde->pc_end);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_lsda_address) {
- SetCie32(&this->memory_, 0x5000, 0xfc,
- std::vector<uint8_t>{/* version */ 1,
- /* augment string */ 'z', 'L', '\0',
- /* address size */ 8,
- /* code alignment factor */ 16,
- /* data alignment factor */ 32,
- /* return address register */ 10,
- /* augment length */ 0x2,
- /* L data */ DW_EH_PE_udata2});
-
- std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
- /* lsda address */ 0x20, 0x45};
- SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(0x5000U, fde->cie_offset);
- EXPECT_EQ(0x5392U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
- EXPECT_EQ(0x4300U, fde->pc_start);
- EXPECT_EQ(0x4600U, fde->pc_end);
- EXPECT_EQ(0x4520U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_lsda_address) {
- SetCie64(&this->memory_, 0x5000, 0xfc,
- std::vector<uint8_t>{/* version */ 1,
- /* augment string */ 'z', 'L', '\0',
- /* address size */ 8,
- /* code alignment factor */ 16,
- /* data alignment factor */ 32,
- /* return address register */ 10,
- /* augment length */ 0x2,
- /* L data */ DW_EH_PE_udata2});
-
- std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
- /* lsda address */ 0x20, 0x45};
- SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(0x5000U, fde->cie_offset);
- EXPECT_EQ(0x53a6U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
- EXPECT_EQ(0x4300U, fde->pc_start);
- EXPECT_EQ(0x4600U, fde->pc_end);
- EXPECT_EQ(0x4520U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc_interleaved) {
- SetCie32(&this->memory_, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
-
- // FDE 0 (0x100 - 0x200)
- SetFde32(&this->memory_, 0x5100, 0xfc, 0, 0x100, 0x100);
- // FDE 1 (0x300 - 0x500)
- SetFde32(&this->memory_, 0x5200, 0xfc, 0, 0x300, 0x200);
- // FDE 2 (0x700 - 0x800)
- SetFde32(&this->memory_, 0x5300, 0xfc, 0, 0x700, 0x100);
- // FDE 3 (0xa00 - 0xb00)
- SetFde32(&this->memory_, 0x5400, 0xfc, 0, 0xa00, 0x100);
- // FDE 4 (0x100 - 0xb00)
- SetFde32(&this->memory_, 0x5500, 0xfc, 0, 0x150, 0xa00);
- // FDE 5 (0x50 - 0xa0)
- SetFde32(&this->memory_, 0x5600, 0xfc, 0, 0x50, 0x50);
- // FDE 6 (0x0 - 0x50)
- SetFde32(&this->memory_, 0x5700, 0xfc, 0, 0, 0x50);
-
- this->debug_frame_->Init(0x5000, 0x800, 0);
-
- // Force reading all entries so no entries are found.
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0xfffff);
- ASSERT_TRUE(fde == nullptr);
-
- // 0x50 - 0xa0 FDE 5
- fde = this->debug_frame_->GetFdeFromPc(0x60);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x50U, fde->pc_start);
- EXPECT_EQ(0xa0U, fde->pc_end);
-
- // 0x0 - 0x50 FDE 6
- fde = this->debug_frame_->GetFdeFromPc(0x10);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0U, fde->pc_start);
- EXPECT_EQ(0x50U, fde->pc_end);
-
- // 0x100 - 0x200 FDE 0
- fde = this->debug_frame_->GetFdeFromPc(0x170);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x100U, fde->pc_start);
- EXPECT_EQ(0x200U, fde->pc_end);
-
- // 0x200 - 0x300 FDE 4
- fde = this->debug_frame_->GetFdeFromPc(0x210);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x150U, fde->pc_start);
- EXPECT_EQ(0xb50U, fde->pc_end);
-
- // 0x300 - 0x500 FDE 1
- fde = this->debug_frame_->GetFdeFromPc(0x310);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x300U, fde->pc_start);
- EXPECT_EQ(0x500U, fde->pc_end);
-
- // 0x700 - 0x800 FDE 2
- fde = this->debug_frame_->GetFdeFromPc(0x790);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x700U, fde->pc_start);
- EXPECT_EQ(0x800U, fde->pc_end);
-
- // 0x800 - 0x900 FDE 4
- fde = this->debug_frame_->GetFdeFromPc(0x850);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x150U, fde->pc_start);
- EXPECT_EQ(0xb50U, fde->pc_end);
-
- // 0xa00 - 0xb00 FDE 3
- fde = this->debug_frame_->GetFdeFromPc(0xa35);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0xa00U, fde->pc_start);
- EXPECT_EQ(0xb00U, fde->pc_end);
-
- // 0xb00 - 0xb50 FDE 4
- fde = this->debug_frame_->GetFdeFromPc(0xb20);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x150U, fde->pc_start);
- EXPECT_EQ(0xb50U, fde->pc_end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc_overlap) {
- SetCie32(&this->memory_, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
-
- // FDE 0 (0x100 - 0x200)
- SetFde32(&this->memory_, 0x5100, 0xfc, 0, 0x100, 0x100);
- // FDE 1 (0x50 - 0x550)
- SetFde32(&this->memory_, 0x5200, 0xfc, 0, 0x50, 0x500);
- // FDE 2 (0x00 - 0x800)
- SetFde32(&this->memory_, 0x5300, 0xfc, 0, 0x0, 0x800);
-
- this->debug_frame_->Init(0x5000, 0x400, 0);
-
- // Force reading all entries so no entries are found.
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0xfffff);
- ASSERT_TRUE(fde == nullptr);
-
- // 0x0 - 0x50 FDE 2
- fde = this->debug_frame_->GetFdeFromPc(0x10);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x0U, fde->pc_start);
- EXPECT_EQ(0x800U, fde->pc_end);
-
- // 0x50 - 0x100 FDE 1
- fde = this->debug_frame_->GetFdeFromPc(0x60);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x50U, fde->pc_start);
- EXPECT_EQ(0x550U, fde->pc_end);
-
- // 0x100 - 0x200 FDE 0
- fde = this->debug_frame_->GetFdeFromPc(0x170);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x100U, fde->pc_start);
- EXPECT_EQ(0x200U, fde->pc_end);
-
- // 0x200 - 0x550 FDE 1
- fde = this->debug_frame_->GetFdeFromPc(0x210);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x50U, fde->pc_start);
- EXPECT_EQ(0x550U, fde->pc_end);
-
- // 0x550 - 0x800 FDE 2
- fde = this->debug_frame_->GetFdeFromPc(0x580);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x0U, fde->pc_start);
- EXPECT_EQ(0x800U, fde->pc_end);
-
- fde = this->debug_frame_->GetFdeFromPc(0x810);
- ASSERT_TRUE(fde == nullptr);
-}
-
-REGISTER_TYPED_TEST_SUITE_P(
- DwarfDebugFrameTest, GetFdes32, GetFdes32_after_GetFdeFromPc, GetFdes32_not_in_section,
- GetFdeFromPc32, GetFdeFromPc32_reverse, GetFdeFromPc32_not_in_section, GetFdes64,
- GetFdes64_after_GetFdeFromPc, GetFdes64_not_in_section, GetFdeFromPc64, GetFdeFromPc64_reverse,
- GetFdeFromPc64_not_in_section, GetCieFde32, GetCieFde64, GetCieFromOffset32_cie_cached,
- GetCieFromOffset64_cie_cached, GetCieFromOffset32_version1, GetCieFromOffset64_version1,
- GetCieFromOffset32_version3, GetCieFromOffset64_version3, GetCieFromOffset32_version4,
- GetCieFromOffset64_version4, GetCieFromOffset32_version5, GetCieFromOffset64_version5,
- GetCieFromOffset_version_invalid, GetCieFromOffset32_augment, GetCieFromOffset64_augment,
- GetFdeFromOffset32_augment, GetFdeFromOffset64_augment, GetFdeFromOffset32_lsda_address,
- GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved, GetFdeFromPc_overlap);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
deleted file mode 100644
index 46a25a4..0000000
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfError.h>
-
-#include "DwarfEhFrame.h"
-#include "DwarfEncoding.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class DwarfEhFrameTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_.Clear();
- eh_frame_ = new DwarfEhFrame<TypeParam>(&memory_);
- ResetLogs();
- }
-
- void TearDown() override { delete eh_frame_; }
-
- MemoryFake memory_;
- DwarfEhFrame<TypeParam>* eh_frame_ = nullptr;
-};
-TYPED_TEST_SUITE_P(DwarfEhFrameTest);
-
-// NOTE: All test class variables need to be referenced as this->.
-
-// Only verify different cie/fde format. All other DwarfSection corner
-// cases are tested in DwarfDebugFrameTest.cpp.
-
-TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset32) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- // Indicates this is a cie for eh_frame.
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 16, 32, 1});
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x104);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x5000U, fde->cie_offset);
- EXPECT_EQ(0x5110U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x5200U, fde->cfa_instructions_end);
- EXPECT_EQ(0x6608U, fde->pc_start);
- EXPECT_EQ(0x6808U, fde->pc_end);
- EXPECT_EQ(0U, fde->lsda_address);
-
- const DwarfCie* cie = fde->cie;
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x500dU, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5100U, cie->cfa_instructions_end);
- EXPECT_EQ(16U, cie->code_alignment_factor);
- EXPECT_EQ(32U, cie->data_alignment_factor);
- EXPECT_EQ(1U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset64) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xfc);
- // Indicates this is a cie for eh_frame.
- this->memory_.SetData64(0x500c, 0);
- this->memory_.SetMemory(0x5014, std::vector<uint8_t>{1, '\0', 16, 32, 1});
-
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xfc);
- this->memory_.SetData64(0x510c, 0x10c);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x5000U, fde->cie_offset);
- EXPECT_EQ(0x5124U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x5208U, fde->cfa_instructions_end);
- EXPECT_EQ(0x6618U, fde->pc_start);
- EXPECT_EQ(0x6818U, fde->pc_end);
- EXPECT_EQ(0U, fde->lsda_address);
-
- const DwarfCie* cie = fde->cie;
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x5019U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5108U, cie->cfa_instructions_end);
- EXPECT_EQ(16U, cie->code_alignment_factor);
- EXPECT_EQ(32U, cie->data_alignment_factor);
- EXPECT_EQ(1U, cie->return_address_register);
-}
-
-REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameTest, GetFdeCieFromOffset32, GetFdeCieFromOffset64);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfEhFrameTest, DwarfEhFrameTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
deleted file mode 100644
index 6aa3867..0000000
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfError.h>
-
-#include "DwarfEhFrameWithHdr.h"
-#include "DwarfEncoding.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class TestDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
- public:
- TestDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
- ~TestDwarfEhFrameWithHdr() = default;
-
- void TestSetTableEncoding(uint8_t encoding) { this->table_encoding_ = encoding; }
- void TestSetHdrEntriesOffset(uint64_t offset) { this->hdr_entries_offset_ = offset; }
- void TestSetHdrEntriesDataOffset(uint64_t offset) { this->hdr_entries_data_offset_ = offset; }
- void TestSetTableEntrySize(size_t size) { this->table_entry_size_ = size; }
-
- void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
- void TestSetFdeInfo(uint64_t index, const typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo& info) {
- this->fde_info_[index] = info;
- }
-
- uint8_t TestGetVersion() { return this->version_; }
- uint8_t TestGetTableEncoding() { return this->table_encoding_; }
- uint64_t TestGetTableEntrySize() { return this->table_entry_size_; }
- uint64_t TestGetFdeCount() { return this->fde_count_; }
- uint64_t TestGetHdrEntriesOffset() { return this->hdr_entries_offset_; }
- uint64_t TestGetHdrEntriesDataOffset() { return this->hdr_entries_data_offset_; }
-};
-
-template <typename TypeParam>
-class DwarfEhFrameWithHdrTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_.Clear();
- eh_frame_ = new TestDwarfEhFrameWithHdr<TypeParam>(&memory_);
- ResetLogs();
- }
-
- void TearDown() override { delete eh_frame_; }
-
- MemoryFake memory_;
- TestDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
-};
-TYPED_TEST_SUITE_P(DwarfEhFrameWithHdrTest);
-
-// NOTE: All test class variables need to be referenced as this->.
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init) {
- this->memory_.SetMemory(
- 0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
- this->memory_.SetData16(0x1004, 0x500);
- this->memory_.SetData32(0x1006, 126);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
- EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
- EXPECT_EQ(DW_EH_PE_sdata4, this->eh_frame_->TestGetTableEncoding());
- EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
- EXPECT_EQ(126U, this->eh_frame_->TestGetFdeCount());
- EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
- EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
-
- // Verify a zero table entry size fails to init.
- this->memory_.SetData8(0x1003, 0x1);
- ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
- // Reset the value back to the original.
- this->memory_.SetData8(0x1003, DW_EH_PE_sdata4);
-
- // Verify a zero fde count fails to init.
- this->memory_.SetData32(0x1006, 0);
- ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
- ASSERT_EQ(DWARF_ERROR_NO_FDES, this->eh_frame_->LastErrorCode());
-
- // Verify an unexpected version will cause a fail.
- this->memory_.SetData32(0x1006, 126);
- this->memory_.SetData8(0x1000, 0);
- ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
- ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
- this->memory_.SetData8(0x1000, 2);
- ASSERT_FALSE(this->eh_frame_->Init(0x1000, 0x100, 0));
- ASSERT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias) {
- this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
- DW_EH_PE_pcrel | DW_EH_PE_sdata4});
- this->memory_.SetData16(0x1004, 0x500);
- this->memory_.SetData32(0x1006, 1);
- this->memory_.SetData32(0x100a, 0x2500);
- this->memory_.SetData32(0x100e, 0x1400);
-
- // CIE 32 information.
- this->memory_.SetData32(0x1300, 0xfc);
- this->memory_.SetData32(0x1304, 0);
- this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
-
- // FDE 32 information.
- this->memory_.SetData32(0x1400, 0xfc);
- this->memory_.SetData32(0x1404, 0x104);
- this->memory_.SetData32(0x1408, 0x10f8);
- this->memory_.SetData32(0x140c, 0x200);
- this->memory_.SetData16(0x1410, 0);
-
- ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x200, 0x2000));
- ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
- EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
- EXPECT_EQ(0x1b, this->eh_frame_->TestGetTableEncoding());
- EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
- EXPECT_EQ(1U, this->eh_frame_->TestGetFdeCount());
- EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
- EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x4500U, fde->pc_start);
- EXPECT_EQ(0x4700U, fde->pc_end);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias_different_from_eh_frame_bias) {
- this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
- DW_EH_PE_pcrel | DW_EH_PE_sdata4});
- this->memory_.SetData16(0x1004, 0x500);
- this->memory_.SetData32(0x1006, 1);
- this->memory_.SetData32(0x100a, 0x2500);
- this->memory_.SetData32(0x100e, 0x1400);
-
- // CIE 32 information.
- this->memory_.SetData32(0x1300, 0xfc);
- this->memory_.SetData32(0x1304, 0);
- this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
-
- // FDE 32 information.
- this->memory_.SetData32(0x1400, 0xfc);
- this->memory_.SetData32(0x1404, 0x104);
- this->memory_.SetData32(0x1408, 0x20f8);
- this->memory_.SetData32(0x140c, 0x200);
- this->memory_.SetData16(0x1410, 0);
-
- ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x200, 0x1000));
- ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
- EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
- EXPECT_EQ(0x1b, this->eh_frame_->TestGetTableEncoding());
- EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
- EXPECT_EQ(1U, this->eh_frame_->TestGetFdeCount());
- EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
- EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x4500U, fde->pc_start);
- EXPECT_EQ(0x4700U, fde->pc_end);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_wtih_empty_fde) {
- this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
- DW_EH_PE_pcrel | DW_EH_PE_sdata4});
- this->memory_.SetData16(0x1004, 0x500);
- this->memory_.SetData32(0x1006, 1);
- this->memory_.SetData32(0x100a, 0x2500);
- this->memory_.SetData32(0x100e, 0x1400);
-
- // CIE 32 information.
- this->memory_.SetData32(0x1300, 0xfc);
- this->memory_.SetData32(0x1304, 0);
- this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
-
- // FDE 32 information.
- this->memory_.SetData32(0x1400, 0xfc);
- this->memory_.SetData32(0x1404, 0x104);
- this->memory_.SetData32(0x1408, 0x30f8);
- this->memory_.SetData32(0x140c, 0);
- this->memory_.SetData16(0x1410, 0);
-
- // FDE 32 information.
- this->memory_.SetData32(0x1500, 0xfc);
- this->memory_.SetData32(0x1504, 0x204);
- this->memory_.SetData32(0x1508, 0x2ff8);
- this->memory_.SetData32(0x150c, 0x200);
- this->memory_.SetData16(0x1510, 0);
-
- ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x300, 0));
- ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x4500U, fde->pc_start);
- EXPECT_EQ(0x4700U, fde->pc_end);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes_with_empty_fde) {
- this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
- DW_EH_PE_pcrel | DW_EH_PE_sdata4});
- this->memory_.SetData16(0x1004, 0x500);
- this->memory_.SetData32(0x1006, 1);
- this->memory_.SetData32(0x100a, 0x2500);
- this->memory_.SetData32(0x100e, 0x1400);
-
- // CIE 32 information.
- this->memory_.SetData32(0x1300, 0xfc);
- this->memory_.SetData32(0x1304, 0);
- this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
-
- // FDE 32 information.
- this->memory_.SetData32(0x1400, 0xfc);
- this->memory_.SetData32(0x1404, 0x104);
- this->memory_.SetData32(0x1408, 0x30f8);
- this->memory_.SetData32(0x140c, 0);
- this->memory_.SetData16(0x1410, 0);
-
- // FDE 32 information.
- this->memory_.SetData32(0x1500, 0xfc);
- this->memory_.SetData32(0x1504, 0x204);
- this->memory_.SetData32(0x1508, 0x2ff8);
- this->memory_.SetData32(0x150c, 0x200);
- this->memory_.SetData16(0x1510, 0);
-
- ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x300, 0));
- ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
-
- std::vector<const DwarfFde*> fdes;
- this->eh_frame_->GetFdes(&fdes);
- ASSERT_FALSE(fdes.empty());
- ASSERT_EQ(1U, fdes.size());
- EXPECT_EQ(0x4500U, fdes[0]->pc_start);
- EXPECT_EQ(0x4700U, fdes[0]->pc_end);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes) {
- this->memory_.SetMemory(
- 0x1000, std::vector<uint8_t>{1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
- this->memory_.SetData16(0x1004, 0x500);
- this->memory_.SetData32(0x1006, 4);
-
- // Header information.
- this->memory_.SetData32(0x100a, 0x4600);
- this->memory_.SetData32(0x100e, 0x1500);
- this->memory_.SetData32(0x1012, 0x5500);
- this->memory_.SetData32(0x1016, 0x1400);
- this->memory_.SetData32(0x101a, 0x6800);
- this->memory_.SetData32(0x101e, 0x1700);
- this->memory_.SetData32(0x1022, 0x7700);
- this->memory_.SetData32(0x1026, 0x1600);
-
- // CIE 32 information.
- this->memory_.SetData32(0x1300, 0xfc);
- this->memory_.SetData32(0x1304, 0);
- this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, '\0', 0, 0, 0});
-
- // FDE 32 information.
- // pc 0x5500 - 0x5700
- this->memory_.SetData32(0x1400, 0xfc);
- this->memory_.SetData32(0x1404, 0x104);
- this->memory_.SetData32(0x1408, 0x40f8);
- this->memory_.SetData32(0x140c, 0x200);
-
- // pc 0x4600 - 0x4800
- this->memory_.SetData32(0x1500, 0xfc);
- this->memory_.SetData32(0x1504, 0x204);
- this->memory_.SetData32(0x1508, 0x30f8);
- this->memory_.SetData32(0x150c, 0x200);
-
- // pc 0x7700 - 0x7900
- this->memory_.SetData32(0x1600, 0xfc);
- this->memory_.SetData32(0x1604, 0x304);
- this->memory_.SetData32(0x1608, 0x60f8);
- this->memory_.SetData32(0x160c, 0x200);
-
- // pc 0x6800 - 0x6a00
- this->memory_.SetData32(0x1700, 0xfc);
- this->memory_.SetData32(0x1704, 0x404);
- this->memory_.SetData32(0x1708, 0x50f8);
- this->memory_.SetData32(0x170c, 0x200);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
-
- std::vector<const DwarfFde*> fdes;
- this->eh_frame_->GetFdes(&fdes);
- ASSERT_EQ(4U, fdes.size());
-
- EXPECT_EQ(0x4600U, fdes[0]->pc_start);
- EXPECT_EQ(0x4800U, fdes[0]->pc_end);
- EXPECT_EQ(0x5500U, fdes[1]->pc_start);
- EXPECT_EQ(0x5700U, fdes[1]->pc_end);
- EXPECT_EQ(0x6800U, fdes[2]->pc_start);
- EXPECT_EQ(0x6a00U, fdes[2]->pc_end);
- EXPECT_EQ(0x7700U, fdes[3]->pc_start);
- EXPECT_EQ(0x7900U, fdes[3]->pc_end);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
- this->eh_frame_->TestSetTableEntrySize(0x10);
- this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
- this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
-
- ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
- EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
- ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
- EXPECT_EQ(0x1000U, this->eh_frame_->LastErrorAddress());
-}
-
-// We are assuming that pc rel, is really relative to the load_bias.
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
- this->eh_frame_->TestSetTableEncoding(DW_EH_PE_pcrel | DW_EH_PE_udata4);
- this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
- this->eh_frame_->TestSetHdrEntriesDataOffset(0x3000);
- this->eh_frame_->TestSetTableEntrySize(0x10);
-
- this->memory_.SetData32(0x1040, 0x340);
- this->memory_.SetData32(0x1044, 0x500);
-
- auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x340U, info->pc);
- EXPECT_EQ(0x500U, info->offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_datarel) {
- this->eh_frame_->TestSetTableEncoding(DW_EH_PE_datarel | DW_EH_PE_udata4);
- this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
- this->eh_frame_->TestSetHdrEntriesDataOffset(0x3000);
- this->eh_frame_->TestSetTableEntrySize(0x10);
-
- this->memory_.SetData32(0x1040, 0x340);
- this->memory_.SetData32(0x1044, 0x500);
-
- auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x3340U, info->pc);
- EXPECT_EQ(0x3500U, info->offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_cached) {
- this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
- this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
- this->eh_frame_->TestSetTableEntrySize(0x10);
-
- this->memory_.SetData32(0x1040, 0x340);
- this->memory_.SetData32(0x1044, 0x500);
-
- auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x340U, info->pc);
- EXPECT_EQ(0x500U, info->offset);
-
- // Clear the memory so that this will fail if it doesn't read cached data.
- this->memory_.Clear();
-
- info = this->eh_frame_->GetFdeInfoFromIndex(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x340U, info->pc);
- EXPECT_EQ(0x500U, info->offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_verify) {
- this->eh_frame_->TestSetTableEntrySize(0x10);
-
- typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
- for (size_t i = 0; i < 10; i++) {
- info.pc = 0x1000 * (i + 1);
- info.offset = 0x5000 + i * 0x20;
- this->eh_frame_->TestSetFdeInfo(i, info);
- }
-
- uint64_t fde_offset;
- this->eh_frame_->TestSetFdeCount(10);
- EXPECT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- // Not an error, just not found.
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
- // Even number of elements.
- for (size_t i = 0; i < 10; i++) {
- SCOPED_TRACE(testing::Message() << "Failed at index " << i);
- TypeParam pc = 0x1000 * (i + 1);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset));
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset));
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset));
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
- }
-
- // Odd number of elements.
- this->eh_frame_->TestSetFdeCount(9);
- for (size_t i = 0; i < 9; i++) {
- SCOPED_TRACE(testing::Message() << "Failed at index " << i);
- TypeParam pc = 0x1000 * (i + 1);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset));
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset));
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
- EXPECT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset));
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset);
- }
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_index_fail) {
- this->eh_frame_->TestSetTableEntrySize(0x10);
- this->eh_frame_->TestSetFdeCount(10);
-
- uint64_t fde_offset;
- EXPECT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_fail_fde_count) {
- this->eh_frame_->TestSetFdeCount(0);
-
- uint64_t fde_offset;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeOffsetFromPc_search) {
- this->eh_frame_->TestSetTableEntrySize(16);
- this->eh_frame_->TestSetFdeCount(10);
-
- typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
- info.pc = 0x550;
- info.offset = 0x10500;
- this->eh_frame_->TestSetFdeInfo(5, info);
- info.pc = 0x750;
- info.offset = 0x10700;
- this->eh_frame_->TestSetFdeInfo(7, info);
- info.pc = 0x850;
- info.offset = 0x10800;
- this->eh_frame_->TestSetFdeInfo(8, info);
-
- uint64_t fde_offset;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(0x800, &fde_offset));
- EXPECT_EQ(0x10700U, fde_offset);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde32) {
- // CIE 32 information.
- this->memory_.SetData32(0xf000, 0x100);
- this->memory_.SetData32(0xf004, 0);
- this->memory_.SetMemory(0xf008, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
-
- // FDE 32 information.
- this->memory_.SetData32(0x14000, 0x20);
- this->memory_.SetData32(0x14004, 0x5004);
- this->memory_.SetData32(0x14008, 0x9000);
- this->memory_.SetData32(0x1400c, 0x100);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x14000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x1d008U, fde->pc_start);
- EXPECT_EQ(0x1d108U, fde->pc_end);
- EXPECT_EQ(0xf000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0xf00dU, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0xf104U, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde64) {
- // CIE 64 information.
- this->memory_.SetData32(0x6000, 0xffffffff);
- this->memory_.SetData64(0x6004, 0x100);
- this->memory_.SetData64(0x600c, 0);
- this->memory_.SetMemory(0x6014, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
-
- // FDE 64 information.
- this->memory_.SetData32(0x8000, 0xffffffff);
- this->memory_.SetData64(0x8004, 0x200);
- this->memory_.SetData64(0x800c, 0x200c);
- this->memory_.SetData64(0x8014, 0x5000);
- this->memory_.SetData64(0x801c, 0x300);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x8000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
- EXPECT_EQ(0xd018U, fde->pc_start);
- EXPECT_EQ(0xd318U, fde->pc_end);
- EXPECT_EQ(0x6000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata8, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0x6019U, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0x610cU, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_fde_not_found) {
- this->eh_frame_->TestSetTableEntrySize(16);
- this->eh_frame_->TestSetFdeCount(1);
-
- typename DwarfEhFrameWithHdr<TypeParam>::FdeInfo info;
- info.pc = 0x550;
- info.offset = 0x10500;
- this->eh_frame_->TestSetFdeInfo(0, info);
-
- ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
-}
-
-REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias,
- Init_non_zero_load_bias_different_from_eh_frame_bias,
- GetFdeFromPc_wtih_empty_fde, GetFdes_with_empty_fde, GetFdes,
- GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
- GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
- GetFdeOffsetFromPc_verify, GetFdeOffsetFromPc_index_fail,
- GetFdeOffsetFromPc_fail_fde_count, GetFdeOffsetFromPc_search,
- GetCieFde32, GetCieFde64, GetFdeFromPc_fde_not_found);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameWithHdrTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfEhFrameWithHdrTest, DwarfEhFrameWithHdrTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfMemoryTest.cpp b/libunwindstack/tests/DwarfMemoryTest.cpp
deleted file mode 100644
index 650e965..0000000
--- a/libunwindstack/tests/DwarfMemoryTest.cpp
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * Copyright (C) 2017 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 <ios>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfMemory.h>
-
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class DwarfMemoryTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_.Clear();
- dwarf_mem_.reset(new DwarfMemory(&memory_));
- }
-
- template <typename AddressType>
- void GetEncodedSizeTest(uint8_t value, size_t expected);
- template <typename AddressType>
- void ReadEncodedValue_omit();
- template <typename AddressType>
- void ReadEncodedValue_leb128();
- template <typename AddressType>
- void ReadEncodedValue_data1();
- template <typename AddressType>
- void ReadEncodedValue_data2();
- template <typename AddressType>
- void ReadEncodedValue_data4();
- template <typename AddressType>
- void ReadEncodedValue_data8();
- template <typename AddressType>
- void ReadEncodedValue_non_zero_adjust();
- template <typename AddressType>
- void ReadEncodedValue_overflow();
- template <typename AddressType>
- void ReadEncodedValue_high_bit_set();
- template <typename AddressType>
- void ReadEncodedValue_all();
-
- MemoryFake memory_;
- std::unique_ptr<DwarfMemory> dwarf_mem_;
-};
-
-TEST_F(DwarfMemoryTest, ReadBytes) {
- memory_.SetMemory(0, std::vector<uint8_t>{0x10, 0x18, 0xff, 0xfe});
-
- uint8_t byte;
- ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
- ASSERT_EQ(0x10U, byte);
- ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
- ASSERT_EQ(0x18U, byte);
- ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
- ASSERT_EQ(0xffU, byte);
- ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
- ASSERT_EQ(0xfeU, byte);
- ASSERT_EQ(4U, dwarf_mem_->cur_offset());
-
- dwarf_mem_->set_cur_offset(2);
- ASSERT_TRUE(dwarf_mem_->ReadBytes(&byte, 1));
- ASSERT_EQ(0xffU, byte);
- ASSERT_EQ(3U, dwarf_mem_->cur_offset());
-}
-
-TEST_F(DwarfMemoryTest, ReadSigned_check) {
- uint64_t value;
-
- // Signed 8 byte reads.
- memory_.SetData8(0, static_cast<uint8_t>(-10));
- memory_.SetData8(1, 200);
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
- ASSERT_EQ(static_cast<int8_t>(-10), static_cast<int8_t>(value));
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int8_t>(&value));
- ASSERT_EQ(static_cast<int8_t>(200), static_cast<int8_t>(value));
-
- // Signed 16 byte reads.
- memory_.SetData16(0x10, static_cast<uint16_t>(-1000));
- memory_.SetData16(0x12, 50100);
- dwarf_mem_->set_cur_offset(0x10);
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
- ASSERT_EQ(static_cast<int16_t>(-1000), static_cast<int16_t>(value));
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int16_t>(&value));
- ASSERT_EQ(static_cast<int16_t>(50100), static_cast<int16_t>(value));
-
- // Signed 32 byte reads.
- memory_.SetData32(0x100, static_cast<uint32_t>(-1000000000));
- memory_.SetData32(0x104, 3000000000);
- dwarf_mem_->set_cur_offset(0x100);
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
- ASSERT_EQ(static_cast<int32_t>(-1000000000), static_cast<int32_t>(value));
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int32_t>(&value));
- ASSERT_EQ(static_cast<int32_t>(3000000000), static_cast<int32_t>(value));
-
- // Signed 64 byte reads.
- memory_.SetData64(0x200, static_cast<uint64_t>(-2000000000000LL));
- memory_.SetData64(0x208, 5000000000000LL);
- dwarf_mem_->set_cur_offset(0x200);
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
- ASSERT_EQ(static_cast<int64_t>(-2000000000000), static_cast<int64_t>(value));
- ASSERT_TRUE(dwarf_mem_->ReadSigned<int64_t>(&value));
- ASSERT_EQ(static_cast<int64_t>(5000000000000), static_cast<int64_t>(value));
-}
-
-TEST_F(DwarfMemoryTest, ReadULEB128) {
- memory_.SetMemory(0, std::vector<uint8_t>{0x01, 0x80, 0x24, 0xff, 0xc3, 0xff, 0x7f});
-
- uint64_t value;
- ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
- ASSERT_EQ(1U, dwarf_mem_->cur_offset());
- ASSERT_EQ(1U, value);
-
- ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
- ASSERT_EQ(3U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0x1200U, value);
-
- ASSERT_TRUE(dwarf_mem_->ReadULEB128(&value));
- ASSERT_EQ(7U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0xfffe1ffU, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadSLEB128) {
- memory_.SetMemory(0, std::vector<uint8_t>{0x06, 0x40, 0x82, 0x34, 0x89, 0x64, 0xf9, 0xc3, 0x8f,
- 0x2f, 0xbf, 0xc3, 0xf7, 0x5f});
-
- int64_t value;
- ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
- ASSERT_EQ(1U, dwarf_mem_->cur_offset());
- ASSERT_EQ(6U, value);
-
- ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
- ASSERT_EQ(2U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0xffffffffffffffc0ULL, static_cast<uint64_t>(value));
-
- ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
- ASSERT_EQ(4U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0x1a02U, value);
-
- ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
- ASSERT_EQ(6U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0xfffffffffffff209ULL, static_cast<uint64_t>(value));
-
- ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
- ASSERT_EQ(10U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0x5e3e1f9U, value);
-
- ASSERT_TRUE(dwarf_mem_->ReadSLEB128(&value));
- ASSERT_EQ(14U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0xfffffffffbfde1bfULL, static_cast<uint64_t>(value));
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::GetEncodedSizeTest(uint8_t value, size_t expected) {
- for (size_t i = 0; i < 16; i++) {
- uint8_t encoding = (i << 4) | value;
- ASSERT_EQ(expected, dwarf_mem_->GetEncodedSize<AddressType>(encoding))
- << "encoding 0x" << std::hex << static_cast<uint32_t>(encoding) << " test value 0x"
- << static_cast<size_t>(value);
- }
-}
-
-TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint32_t) {
- GetEncodedSizeTest<uint32_t>(0, sizeof(uint32_t));
-}
-
-TEST_F(DwarfMemoryTest, GetEncodedSize_absptr_uint64_t) {
- GetEncodedSizeTest<uint64_t>(0, sizeof(uint64_t));
-}
-
-TEST_F(DwarfMemoryTest, GetEncodedSize_data1) {
- // udata1
- GetEncodedSizeTest<uint32_t>(0x0d, 1);
- GetEncodedSizeTest<uint64_t>(0x0d, 1);
-
- // sdata1
- GetEncodedSizeTest<uint32_t>(0x0e, 1);
- GetEncodedSizeTest<uint64_t>(0x0e, 1);
-}
-
-TEST_F(DwarfMemoryTest, GetEncodedSize_data2) {
- // udata2
- GetEncodedSizeTest<uint32_t>(0x02, 2);
- GetEncodedSizeTest<uint64_t>(0x02, 2);
-
- // sdata2
- GetEncodedSizeTest<uint32_t>(0x0a, 2);
- GetEncodedSizeTest<uint64_t>(0x0a, 2);
-}
-
-TEST_F(DwarfMemoryTest, GetEncodedSize_data4) {
- // udata4
- GetEncodedSizeTest<uint32_t>(0x03, 4);
- GetEncodedSizeTest<uint64_t>(0x03, 4);
-
- // sdata4
- GetEncodedSizeTest<uint32_t>(0x0b, 4);
- GetEncodedSizeTest<uint64_t>(0x0b, 4);
-}
-
-TEST_F(DwarfMemoryTest, GetEncodedSize_data8) {
- // udata8
- GetEncodedSizeTest<uint32_t>(0x04, 8);
- GetEncodedSizeTest<uint64_t>(0x04, 8);
-
- // sdata8
- GetEncodedSizeTest<uint32_t>(0x0c, 8);
- GetEncodedSizeTest<uint64_t>(0x0c, 8);
-}
-
-TEST_F(DwarfMemoryTest, GetEncodedSize_unknown) {
- GetEncodedSizeTest<uint32_t>(0x01, 0);
- GetEncodedSizeTest<uint64_t>(0x01, 0);
-
- GetEncodedSizeTest<uint32_t>(0x09, 0);
- GetEncodedSizeTest<uint64_t>(0x09, 0);
-
- GetEncodedSizeTest<uint32_t>(0x0f, 0);
- GetEncodedSizeTest<uint64_t>(0x0f, 0);
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_omit() {
- uint64_t value = 123;
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0xff, &value));
- ASSERT_EQ(0U, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint32_t) {
- ReadEncodedValue_omit<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_omit_uint64_t) {
- ReadEncodedValue_omit<uint64_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint32_t) {
- uint64_t value = 100;
- ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
-
- memory_.SetData32(0, 0x12345678);
-
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x00, &value));
- ASSERT_EQ(4U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0x12345678U, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_absptr_uint64_t) {
- uint64_t value = 100;
- ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
-
- memory_.SetData64(0, 0x12345678f1f2f3f4ULL);
-
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x00, &value));
- ASSERT_EQ(8U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint32_t) {
- uint64_t value = 100;
- dwarf_mem_->set_cur_offset(1);
- ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
-
- memory_.SetData32(4, 0x12345678);
-
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint32_t>(0x50, &value));
- ASSERT_EQ(8U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0x12345678U, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_aligned_uint64_t) {
- uint64_t value = 100;
- dwarf_mem_->set_cur_offset(1);
- ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
-
- memory_.SetData64(8, 0x12345678f1f2f3f4ULL);
-
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<uint64_t>(0x50, &value));
- ASSERT_EQ(16U, dwarf_mem_->cur_offset());
- ASSERT_EQ(0x12345678f1f2f3f4ULL, value);
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_leb128() {
- memory_.SetMemory(0, std::vector<uint8_t>{0x80, 0x42});
-
- uint64_t value = 100;
- // uleb128
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x01, &value));
- ASSERT_EQ(0x2100U, value);
-
- dwarf_mem_->set_cur_offset(0);
- // sleb128
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x09, &value));
- ASSERT_EQ(0xffffffffffffe100ULL, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint32_t) {
- ReadEncodedValue_leb128<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_leb128_uint64_t) {
- ReadEncodedValue_leb128<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_data1() {
- memory_.SetData8(0, 0xe0);
-
- uint64_t value = 0;
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0d, &value));
- ASSERT_EQ(0xe0U, value);
-
- dwarf_mem_->set_cur_offset(0);
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0e, &value));
- ASSERT_EQ(0xffffffffffffffe0ULL, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint32_t) {
- ReadEncodedValue_data1<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data1_uint64_t) {
- ReadEncodedValue_data1<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_data2() {
- memory_.SetData16(0, 0xe000);
-
- uint64_t value = 0;
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x02, &value));
- ASSERT_EQ(0xe000U, value);
-
- dwarf_mem_->set_cur_offset(0);
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0a, &value));
- ASSERT_EQ(0xffffffffffffe000ULL, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint32_t) {
- ReadEncodedValue_data2<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data2_uint64_t) {
- ReadEncodedValue_data2<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_data4() {
- memory_.SetData32(0, 0xe0000000);
-
- uint64_t value = 0;
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x03, &value));
- ASSERT_EQ(0xe0000000U, value);
-
- dwarf_mem_->set_cur_offset(0);
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0b, &value));
- ASSERT_EQ(0xffffffffe0000000ULL, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint32_t) {
- ReadEncodedValue_data4<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data4_uint64_t) {
- ReadEncodedValue_data4<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_data8() {
- memory_.SetData64(0, 0xe000000000000000ULL);
-
- uint64_t value = 0;
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x04, &value));
- ASSERT_EQ(0xe000000000000000ULL, value);
-
- dwarf_mem_->set_cur_offset(0);
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x0c, &value));
- ASSERT_EQ(0xe000000000000000ULL, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint32_t) {
- ReadEncodedValue_data8<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_data8_uint64_t) {
- ReadEncodedValue_data8<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_non_zero_adjust() {
- memory_.SetData64(0, 0xe000000000000000ULL);
-
- uint64_t value = 0;
- dwarf_mem_->set_pc_offset(0x2000);
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0x14, &value));
- ASSERT_EQ(0xe000000000002000ULL, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint32_t) {
- ReadEncodedValue_non_zero_adjust<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_non_zero_adjust_uint64_t) {
- ReadEncodedValue_non_zero_adjust<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_overflow() {
- memory_.SetData64(0, 0);
-
- uint64_t value = 0;
- dwarf_mem_->set_cur_offset(UINT64_MAX);
- ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<AddressType>(0x50, &value));
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint32_t) {
- ReadEncodedValue_overflow<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_overflow_uint64_t) {
- ReadEncodedValue_overflow<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_high_bit_set() {
- uint64_t value;
- memory_.SetData32(0, 0x15234);
- ASSERT_FALSE(dwarf_mem_->ReadEncodedValue<AddressType>(0xc3, &value));
-
- dwarf_mem_->set_func_offset(0x60000);
- dwarf_mem_->set_cur_offset(0);
- ASSERT_TRUE(dwarf_mem_->ReadEncodedValue<AddressType>(0xc3, &value));
- ASSERT_EQ(0x75234U, value);
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_high_bit_set_uint32_t) {
- ReadEncodedValue_high_bit_set<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_high_bit_set_uint64_t) {
- ReadEncodedValue_high_bit_set<uint64_t>();
-}
-
-template <typename AddressType>
-void DwarfMemoryTest::ReadEncodedValue_all() {
- MemoryFakeAlwaysReadZero memory;
- DwarfMemory dwarf_mem(&memory);
-
- for (size_t i = 0; i <= 0xff; i++) {
- uint64_t value;
- if (dwarf_mem.ReadEncodedValue<AddressType>(static_cast<uint8_t>(i), &value)) {
- ASSERT_EQ(0U, value);
- }
- }
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_all_uint32_t) {
- ReadEncodedValue_all<uint32_t>();
-}
-
-TEST_F(DwarfMemoryTest, ReadEncodedValue_all_uint64_t) {
- ReadEncodedValue_all<uint64_t>();
-}
-
-TEST_F(DwarfMemoryTest, AdjustEncodedValue_absptr) {
- uint64_t value = 0x1234;
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x00, &value));
- ASSERT_EQ(0x1234U, value);
-}
-
-TEST_F(DwarfMemoryTest, AdjustEncodedValue_pcrel) {
- uint64_t value = 0x1234;
- ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
-
- dwarf_mem_->set_pc_offset(0x2000);
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
- ASSERT_EQ(0x3234U, value);
-
- dwarf_mem_->set_pc_offset(static_cast<uint64_t>(-4));
- value = 0x1234;
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x10, &value));
- ASSERT_EQ(0x1230U, value);
-}
-
-TEST_F(DwarfMemoryTest, AdjustEncodedValue_textrel) {
- uint64_t value = 0x8234;
- ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
-
- dwarf_mem_->set_text_offset(0x1000);
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
- ASSERT_EQ(0x9234U, value);
-
- dwarf_mem_->set_text_offset(static_cast<uint64_t>(-16));
- value = 0x8234;
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x20, &value));
- ASSERT_EQ(0x8224U, value);
-}
-
-TEST_F(DwarfMemoryTest, AdjustEncodedValue_datarel) {
- uint64_t value = 0xb234;
- ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
-
- dwarf_mem_->set_data_offset(0x1200);
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
- ASSERT_EQ(0xc434U, value);
-
- dwarf_mem_->set_data_offset(static_cast<uint64_t>(-256));
- value = 0xb234;
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x30, &value));
- ASSERT_EQ(0xb134U, value);
-}
-
-TEST_F(DwarfMemoryTest, AdjustEncodedValue_funcrel) {
- uint64_t value = 0x15234;
- ASSERT_FALSE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
-
- dwarf_mem_->set_func_offset(0x60000);
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
- ASSERT_EQ(0x75234U, value);
-
- dwarf_mem_->set_func_offset(static_cast<uint64_t>(-4096));
- value = 0x15234;
- ASSERT_TRUE(dwarf_mem_->AdjustEncodedValue(0x40, &value));
- ASSERT_EQ(0x14234U, value);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpLogTest.cpp b/libunwindstack/tests/DwarfOpLogTest.cpp
deleted file mode 100644
index 8dbf6e8..0000000
--- a/libunwindstack/tests/DwarfOpLogTest.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <ios>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/Regs.h>
-
-#include "DwarfOp.h"
-
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class DwarfOpLogTest : public ::testing::Test {
- protected:
- void SetUp() override {
- op_memory_.Clear();
- regular_memory_.Clear();
- mem_.reset(new DwarfMemory(&op_memory_));
- op_.reset(new DwarfOp<TypeParam>(mem_.get(), ®ular_memory_));
- }
-
- MemoryFake op_memory_;
- MemoryFake regular_memory_;
-
- std::unique_ptr<DwarfMemory> mem_;
- std::unique_ptr<DwarfOp<TypeParam>> op_;
-};
-TYPED_TEST_SUITE_P(DwarfOpLogTest);
-
-TYPED_TEST_P(DwarfOpLogTest, multiple_ops) {
- // Multi operation opcodes.
- std::vector<uint8_t> opcode_buffer = {
- 0x0a, 0x20, 0x10, 0x08, 0x03, 0x12, 0x27,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- std::vector<std::string> lines;
- this->op_->GetLogInfo(0, opcode_buffer.size(), &lines);
- std::vector<std::string> expected{
- "DW_OP_const2u 4128", "Raw Data: 0x0a 0x20 0x10", "DW_OP_const1u 3", "Raw Data: 0x08 0x03",
- "DW_OP_dup", "Raw Data: 0x12", "DW_OP_xor", "Raw Data: 0x27"};
- ASSERT_EQ(expected, lines);
-}
-
-REGISTER_TYPED_TEST_SUITE_P(DwarfOpLogTest, multiple_ops);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfOpLogTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfOpLogTest, DwarfOpLogTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
deleted file mode 100644
index 0e2d91a..0000000
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ /dev/null
@@ -1,1586 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <ios>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/Log.h>
-
-#include "DwarfOp.h"
-
-#include "MemoryFake.h"
-#include "RegsFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class DwarfOpTest : public ::testing::Test {
- protected:
- void SetUp() override {
- op_memory_.Clear();
- regular_memory_.Clear();
- mem_.reset(new DwarfMemory(&op_memory_));
- op_.reset(new DwarfOp<TypeParam>(mem_.get(), ®ular_memory_));
- }
-
- MemoryFake op_memory_;
- MemoryFake regular_memory_;
-
- std::unique_ptr<DwarfMemory> mem_;
- std::unique_ptr<DwarfOp<TypeParam>> op_;
-};
-TYPED_TEST_SUITE_P(DwarfOpTest);
-
-TYPED_TEST_P(DwarfOpTest, decode) {
- // Memory error.
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
- EXPECT_EQ(0U, this->op_->LastErrorAddress());
-
- // No error.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x96});
- this->mem_->set_cur_offset(0);
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
- ASSERT_EQ(0x96U, this->op_->cur_op());
- ASSERT_EQ(1U, this->mem_->cur_offset());
-}
-
-TYPED_TEST_P(DwarfOpTest, eval) {
- // Memory error.
- ASSERT_FALSE(this->op_->Eval(0, 2));
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
- EXPECT_EQ(0U, this->op_->LastErrorAddress());
-
- // Register set.
- // Do this first, to verify that subsequent calls reset the value.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x50});
- ASSERT_TRUE(this->op_->Eval(0, 1));
- ASSERT_TRUE(this->op_->is_register());
- ASSERT_EQ(1U, this->mem_->cur_offset());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- // Multi operation opcodes.
- std::vector<uint8_t> opcode_buffer = {
- 0x08, 0x04, 0x08, 0x03, 0x08, 0x02, 0x08, 0x01,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Eval(0, 8));
- ASSERT_EQ(DWARF_ERROR_NONE, this->op_->LastErrorCode());
- ASSERT_FALSE(this->op_->is_register());
- ASSERT_EQ(8U, this->mem_->cur_offset());
- ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_EQ(1U, this->op_->StackAt(0));
- ASSERT_EQ(2U, this->op_->StackAt(1));
- ASSERT_EQ(3U, this->op_->StackAt(2));
- ASSERT_EQ(4U, this->op_->StackAt(3));
-
- // Infinite loop.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x2f, 0xfd, 0xff});
- ASSERT_FALSE(this->op_->Eval(0, 4));
- ASSERT_EQ(DWARF_ERROR_TOO_MANY_ITERATIONS, this->op_->LastErrorCode());
- ASSERT_FALSE(this->op_->is_register());
- ASSERT_EQ(0U, this->op_->StackSize());
-}
-
-TYPED_TEST_P(DwarfOpTest, illegal_opcode) {
- // Fill the buffer with all of the illegal opcodes.
- std::vector<uint8_t> opcode_buffer = {0x00, 0x01, 0x02, 0x04, 0x05, 0x07};
- for (size_t opcode = 0xa0; opcode < 256; opcode++) {
- opcode_buffer.push_back(opcode);
- }
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- for (size_t i = 0; i < opcode_buffer.size(); i++) {
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
- ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, not_implemented) {
- std::vector<uint8_t> opcode_buffer = {
- // Push values so that any not implemented ops will return the right error.
- 0x08, 0x03, 0x08, 0x02, 0x08, 0x01,
- // xderef
- 0x18,
- // fbreg
- 0x91, 0x01,
- // piece
- 0x93, 0x01,
- // xderef_size
- 0x95, 0x01,
- // push_object_address
- 0x97,
- // call2
- 0x98, 0x01, 0x02,
- // call4
- 0x99, 0x01, 0x02, 0x03, 0x04,
- // call_ref
- 0x9a,
- // form_tls_address
- 0x9b,
- // call_frame_cfa
- 0x9c,
- // bit_piece
- 0x9d, 0x01, 0x01,
- // implicit_value
- 0x9e, 0x01,
- // stack_value
- 0x9f,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- // Push the stack values.
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_TRUE(this->op_->Decode());
-
- while (this->mem_->cur_offset() < opcode_buffer.size()) {
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->LastErrorCode());
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_addr) {
- std::vector<uint8_t> opcode_buffer = {0x03, 0x12, 0x23, 0x34, 0x45};
- if (sizeof(TypeParam) == 8) {
- opcode_buffer.push_back(0x56);
- opcode_buffer.push_back(0x67);
- opcode_buffer.push_back(0x78);
- opcode_buffer.push_back(0x89);
- }
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x03, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x45342312U, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0x8978675645342312UL, this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_deref) {
- std::vector<uint8_t> opcode_buffer = {
- // Try a dereference with nothing on the stack.
- 0x06,
- // Add an address, then dereference.
- 0x0a, 0x10, 0x20, 0x06,
- // Now do another dereference that should fail in memory.
- 0x06,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
- TypeParam value = 0x12345678;
- this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x06, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(value, this->op_->StackAt(0));
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
- ASSERT_EQ(0x12345678U, this->op_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_deref_size) {
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x94});
- TypeParam value = 0x12345678;
- this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- // Read all byte sizes up to the sizeof the type.
- for (size_t i = 1; i < sizeof(TypeParam); i++) {
- this->op_memory_.SetMemory(
- 0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, static_cast<uint8_t>(i)});
- ASSERT_TRUE(this->op_->Eval(0, 5)) << "Failed at size " << i;
- ASSERT_EQ(1U, this->op_->StackSize()) << "Failed at size " << i;
- ASSERT_EQ(0x94, this->op_->cur_op()) << "Failed at size " << i;
- TypeParam expected_value = 0;
- memcpy(&expected_value, &value, i);
- ASSERT_EQ(expected_value, this->op_->StackAt(0)) << "Failed at size " << i;
- }
-
- // Zero byte read.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, 0x00});
- ASSERT_FALSE(this->op_->Eval(0, 5));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
-
- // Read too many bytes.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, sizeof(TypeParam) + 1});
- ASSERT_FALSE(this->op_->Eval(0, 5));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
-
- // Force bad memory read.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x40, 0x94, 0x01});
- ASSERT_FALSE(this->op_->Eval(0, 5));
- ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
- EXPECT_EQ(0x4010U, this->op_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfOpTest, const_unsigned) {
- std::vector<uint8_t> opcode_buffer = {
- // const1u
- 0x08, 0x12, 0x08, 0xff,
- // const2u
- 0x0a, 0x45, 0x12, 0x0a, 0x00, 0xff,
- // const4u
- 0x0c, 0x12, 0x23, 0x34, 0x45, 0x0c, 0x03, 0x02, 0x01, 0xff,
- // const8u
- 0x0e, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x0e, 0x87, 0x98, 0xa9, 0xba, 0xcb,
- 0xdc, 0xed, 0xfe,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- // const1u
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x08, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x12U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x08, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0xffU, this->op_->StackAt(0));
-
- // const2u
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0a, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(0x1245U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0a, this->op_->cur_op());
- ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_EQ(0xff00U, this->op_->StackAt(0));
-
- // const4u
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0c, this->op_->cur_op());
- ASSERT_EQ(5U, this->op_->StackSize());
- ASSERT_EQ(0x45342312U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0c, this->op_->cur_op());
- ASSERT_EQ(6U, this->op_->StackSize());
- ASSERT_EQ(0xff010203U, this->op_->StackAt(0));
-
- // const8u
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0e, this->op_->cur_op());
- ASSERT_EQ(7U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x05060708U, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0x0102030405060708ULL, this->op_->StackAt(0));
- }
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0e, this->op_->cur_op());
- ASSERT_EQ(8U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0xbaa99887UL, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0xfeeddccbbaa99887ULL, this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, const_signed) {
- std::vector<uint8_t> opcode_buffer = {
- // const1s
- 0x09, 0x12, 0x09, 0xff,
- // const2s
- 0x0b, 0x21, 0x32, 0x0b, 0x08, 0xff,
- // const4s
- 0x0d, 0x45, 0x34, 0x23, 0x12, 0x0d, 0x01, 0x02, 0x03, 0xff,
- // const8s
- 0x0f, 0x89, 0x78, 0x67, 0x56, 0x45, 0x34, 0x23, 0x12, 0x0f, 0x04, 0x03, 0x02, 0x01, 0xef,
- 0xef, 0xef, 0xff,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- // const1s
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x09, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x12U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x09, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-1), this->op_->StackAt(0));
-
- // const2s
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0b, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(0x3221U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0b, this->op_->cur_op());
- ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-248), this->op_->StackAt(0));
-
- // const4s
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0d, this->op_->cur_op());
- ASSERT_EQ(5U, this->op_->StackSize());
- ASSERT_EQ(0x12233445U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0d, this->op_->cur_op());
- ASSERT_EQ(6U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-16580095), this->op_->StackAt(0));
-
- // const8s
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0f, this->op_->cur_op());
- ASSERT_EQ(7U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x56677889ULL, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0x1223344556677889ULL, this->op_->StackAt(0));
- }
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x0f, this->op_->cur_op());
- ASSERT_EQ(8U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x01020304U, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(static_cast<TypeParam>(-4521264810949884LL), this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, const_uleb) {
- std::vector<uint8_t> opcode_buffer = {
- // Single byte ULEB128
- 0x10, 0x22, 0x10, 0x7f,
- // Multi byte ULEB128
- 0x10, 0xa2, 0x22, 0x10, 0xa2, 0x74, 0x10, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
- 0x09, 0x10, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x79,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- // Single byte ULEB128
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x10, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x22U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x10, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0x7fU, this->op_->StackAt(0));
-
- // Multi byte ULEB128
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x10, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(0x1122U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x10, this->op_->cur_op());
- ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_EQ(0x3a22U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x10, this->op_->cur_op());
- ASSERT_EQ(5U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x5080c101U, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0x9101c305080c101ULL, this->op_->StackAt(0));
- }
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x10, this->op_->cur_op());
- ASSERT_EQ(6U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x5080c101U, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0x79101c305080c101ULL, this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, const_sleb) {
- std::vector<uint8_t> opcode_buffer = {
- // Single byte SLEB128
- 0x11, 0x22, 0x11, 0x7f,
- // Multi byte SLEB128
- 0x11, 0xa2, 0x22, 0x11, 0xa2, 0x74, 0x11, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
- 0x09, 0x11,
- };
- if (sizeof(TypeParam) == 4) {
- opcode_buffer.push_back(0xb8);
- opcode_buffer.push_back(0xd3);
- opcode_buffer.push_back(0x63);
- } else {
- opcode_buffer.push_back(0x81);
- opcode_buffer.push_back(0x82);
- opcode_buffer.push_back(0x83);
- opcode_buffer.push_back(0x84);
- opcode_buffer.push_back(0x85);
- opcode_buffer.push_back(0x86);
- opcode_buffer.push_back(0x87);
- opcode_buffer.push_back(0x88);
- opcode_buffer.push_back(0x79);
- }
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- // Single byte SLEB128
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x11, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x22U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x11, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-1), this->op_->StackAt(0));
-
- // Multi byte SLEB128
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x11, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(0x1122U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x11, this->op_->cur_op());
- ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-1502), this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x11, this->op_->cur_op());
- ASSERT_EQ(5U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x5080c101U, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0x9101c305080c101ULL, this->op_->StackAt(0));
- }
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x11, this->op_->cur_op());
- ASSERT_EQ(6U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(static_cast<TypeParam>(-464456), this->op_->StackAt(0));
- } else {
- ASSERT_EQ(static_cast<TypeParam>(-499868564803501823LL), this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_dup) {
- std::vector<uint8_t> opcode_buffer = {
- // Should fail since nothing is on the stack.
- 0x12,
- // Push on a value and dup.
- 0x08, 0x15, 0x12,
- // Do it again.
- 0x08, 0x23, 0x12,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(0x12, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x12, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0x15U, this->op_->StackAt(0));
- ASSERT_EQ(0x15U, this->op_->StackAt(1));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x12, this->op_->cur_op());
- ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_EQ(0x23U, this->op_->StackAt(0));
- ASSERT_EQ(0x23U, this->op_->StackAt(1));
- ASSERT_EQ(0x15U, this->op_->StackAt(2));
- ASSERT_EQ(0x15U, this->op_->StackAt(3));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_drop) {
- std::vector<uint8_t> opcode_buffer = {
- // Push a couple of values.
- 0x08, 0x10, 0x08, 0x20,
- // Drop the values.
- 0x13, 0x13,
- // Attempt to drop empty stack.
- 0x13,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x13, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x10U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x13, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(0x13, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_over) {
- std::vector<uint8_t> opcode_buffer = {
- // Push a couple of values.
- 0x08, 0x1a, 0x08, 0xed,
- // Copy a value.
- 0x14,
- // Remove all but one element.
- 0x13, 0x13,
- // Provoke a failure with this opcode.
- 0x14,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x14, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(0x1aU, this->op_->StackAt(0));
- ASSERT_EQ(0xedU, this->op_->StackAt(1));
- ASSERT_EQ(0x1aU, this->op_->StackAt(2));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(0x14, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_pick) {
- std::vector<uint8_t> opcode_buffer = {
- // Push a few values.
- 0x08, 0x1a, 0x08, 0xed, 0x08, 0x34,
- // Copy the value at offset 2.
- 0x15, 0x01,
- // Copy the last value in the stack.
- 0x15, 0x03,
- // Choose an invalid index.
- 0x15, 0x10,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(3U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x15, this->op_->cur_op());
- ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_EQ(0xedU, this->op_->StackAt(0));
- ASSERT_EQ(0x34U, this->op_->StackAt(1));
- ASSERT_EQ(0xedU, this->op_->StackAt(2));
- ASSERT_EQ(0x1aU, this->op_->StackAt(3));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x15, this->op_->cur_op());
- ASSERT_EQ(5U, this->op_->StackSize());
- ASSERT_EQ(0x1aU, this->op_->StackAt(0));
- ASSERT_EQ(0xedU, this->op_->StackAt(1));
- ASSERT_EQ(0x34U, this->op_->StackAt(2));
- ASSERT_EQ(0xedU, this->op_->StackAt(3));
- ASSERT_EQ(0x1aU, this->op_->StackAt(4));
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(0x15, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_swap) {
- std::vector<uint8_t> opcode_buffer = {
- // Push a couple of values.
- 0x08, 0x26, 0x08, 0xab,
- // Swap values.
- 0x16,
- // Pop a value to cause a failure.
- 0x13, 0x16,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0xabU, this->op_->StackAt(0));
- ASSERT_EQ(0x26U, this->op_->StackAt(1));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x16, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0x26U, this->op_->StackAt(0));
- ASSERT_EQ(0xabU, this->op_->StackAt(1));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(0x16, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_rot) {
- std::vector<uint8_t> opcode_buffer = {
- // Rotate that should cause a failure.
- 0x17, 0x08, 0x10,
- // Only 1 value on stack, should fail.
- 0x17, 0x08, 0x20,
- // Only 2 values on stack, should fail.
- 0x17, 0x08, 0x30,
- // Should rotate properly.
- 0x17,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(0x30U, this->op_->StackAt(0));
- ASSERT_EQ(0x20U, this->op_->StackAt(1));
- ASSERT_EQ(0x10U, this->op_->StackAt(2));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x17, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(0x20U, this->op_->StackAt(0));
- ASSERT_EQ(0x10U, this->op_->StackAt(1));
- ASSERT_EQ(0x30U, this->op_->StackAt(2));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_abs) {
- std::vector<uint8_t> opcode_buffer = {
- // Abs that should fail.
- 0x19,
- // A value that is already positive.
- 0x08, 0x10, 0x19,
- // A value that is negative.
- 0x11, 0x7f, 0x19,
- // A value that is large and negative.
- 0x11, 0x81, 0x80, 0x80, 0x80,
- };
- if (sizeof(TypeParam) == 4) {
- opcode_buffer.push_back(0x08);
- } else {
- opcode_buffer.push_back(0x80);
- opcode_buffer.push_back(0x80);
- opcode_buffer.push_back(0x01);
- }
- opcode_buffer.push_back(0x19);
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x10U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x19, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x10U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x19, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0x1U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(3U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x19, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(2147483647U, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(4398046511105UL, this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_and) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x1b,
- // Push a single value.
- 0x08, 0x20,
- // One element stack, and op will fail.
- 0x1b,
- // Push another value.
- 0x08, 0x02, 0x1b,
- // Push on two negative values.
- 0x11, 0x7c, 0x11, 0x7f, 0x1b,
- // Push one negative, one positive.
- 0x11, 0x10, 0x11, 0x7c, 0x1b,
- // Divide by zero.
- 0x11, 0x10, 0x11, 0x00, 0x1b,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- // Two positive values.
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1b, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x10U, this->op_->StackAt(0));
-
- // Two negative values.
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(3U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1b, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0x04U, this->op_->StackAt(0));
-
- // One negative value, one positive value.
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(3U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(4U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1b, this->op_->cur_op());
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-4), this->op_->StackAt(0));
-
- // Divide by zero.
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(4U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(5U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_div) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x1a,
- // Push a single value.
- 0x08, 0x48,
- // One element stack, and op will fail.
- 0x1a,
- // Push another value.
- 0x08, 0xf0, 0x1a,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1a, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x40U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_minus) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x1c,
- // Push a single value.
- 0x08, 0x48,
- // One element stack, and op will fail.
- 0x1c,
- // Push another value.
- 0x08, 0x04, 0x1c,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1c, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x44U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_mod) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x1d,
- // Push a single value.
- 0x08, 0x47,
- // One element stack, and op will fail.
- 0x1d,
- // Push another value.
- 0x08, 0x04, 0x1d,
- // Try a mod of zero.
- 0x08, 0x01, 0x08, 0x00, 0x1d,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1d, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x03U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(3U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_mul) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x1e,
- // Push a single value.
- 0x08, 0x48,
- // One element stack, and op will fail.
- 0x1e,
- // Push another value.
- 0x08, 0x04, 0x1e,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1e, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x120U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_neg) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x1f,
- // Push a single value.
- 0x08, 0x48, 0x1f,
- // Push a negative value.
- 0x11, 0x7f, 0x1f,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1f, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-72), this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x1f, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0x01U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_not) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x20,
- // Push a single value.
- 0x08, 0x4, 0x20,
- // Push a negative value.
- 0x11, 0x7c, 0x20,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x20, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-5), this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x20, this->op_->cur_op());
- ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_EQ(0x03U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_or) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x21,
- // Push a single value.
- 0x08, 0x48,
- // One element stack, and op will fail.
- 0x21,
- // Push another value.
- 0x08, 0xf4, 0x21,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x21, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0xfcU, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_plus) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x22,
- // Push a single value.
- 0x08, 0xff,
- // One element stack, and op will fail.
- 0x22,
- // Push another value.
- 0x08, 0xf2, 0x22,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x22, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x1f1U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_plus_uconst) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x23,
- // Push a single value.
- 0x08, 0x50, 0x23, 0x80, 0x51,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x23, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x28d0U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_shl) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x24,
- // Push a single value.
- 0x08, 0x67,
- // One element stack, and op will fail.
- 0x24,
- // Push another value.
- 0x08, 0x03, 0x24,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x24, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x338U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_shr) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x25,
- // Push a single value.
- 0x11, 0x70,
- // One element stack, and op will fail.
- 0x25,
- // Push another value.
- 0x08, 0x03, 0x25,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x25, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- if (sizeof(TypeParam) == 4) {
- ASSERT_EQ(0x1ffffffeU, this->op_->StackAt(0));
- } else {
- ASSERT_EQ(0x1ffffffffffffffeULL, this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_shra) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x26,
- // Push a single value.
- 0x11, 0x70,
- // One element stack, and op will fail.
- 0x26,
- // Push another value.
- 0x08, 0x03, 0x26,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x26, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(static_cast<TypeParam>(-2), this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_xor) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x27,
- // Push a single value.
- 0x08, 0x11,
- // One element stack, and op will fail.
- 0x27,
- // Push another value.
- 0x08, 0x41, 0x27,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(2U, this->op_->StackSize());
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x27, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x50U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_bra) {
- std::vector<uint8_t> opcode_buffer = {
- // No stack, and op will fail.
- 0x28,
- // Push on a non-zero value with a positive branch.
- 0x08, 0x11, 0x28, 0x02, 0x01,
- // Push on a zero value with a positive branch.
- 0x08, 0x00, 0x28, 0x05, 0x00,
- // Push on a non-zero value with a negative branch.
- 0x08, 0x11, 0x28, 0xfc, 0xff,
- // Push on a zero value with a negative branch.
- 0x08, 0x00, 0x28, 0xf0, 0xff,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Decode());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- // Push on a non-zero value with a positive branch.
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- uint64_t offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x28, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
- ASSERT_EQ(offset + 0x102, this->mem_->cur_offset());
-
- // Push on a zero value with a positive branch.
- this->mem_->set_cur_offset(offset);
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x28, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
- ASSERT_EQ(offset - 5, this->mem_->cur_offset());
-
- // Push on a non-zero value with a negative branch.
- this->mem_->set_cur_offset(offset);
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x28, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
- ASSERT_EQ(offset - 4, this->mem_->cur_offset());
-
- // Push on a zero value with a negative branch.
- this->mem_->set_cur_offset(offset);
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(1U, this->op_->StackSize());
-
- offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x28, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
- ASSERT_EQ(offset + 16, this->mem_->cur_offset());
-}
-
-TYPED_TEST_P(DwarfOpTest, compare_opcode_stack_error) {
- // All of the ops require two stack elements. Loop through all of these
- // ops with potential errors.
- std::vector<uint8_t> opcode_buffer = {
- 0xff, // Place holder for compare op.
- 0x08, 0x11,
- 0xff, // Place holder for compare op.
- };
-
- for (uint8_t opcode = 0x29; opcode <= 0x2e; opcode++) {
- opcode_buffer[0] = opcode;
- opcode_buffer[3] = opcode;
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_FALSE(this->op_->Eval(0, 1));
- ASSERT_EQ(opcode, this->op_->cur_op());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
-
- ASSERT_FALSE(this->op_->Eval(1, 4));
- ASSERT_EQ(opcode, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, compare_opcodes) {
- // Have three different checks for each compare op:
- // - Both values the same.
- // - The first value larger than the second.
- // - The second value larger than the first.
- std::vector<uint8_t> opcode_buffer = {
- // Values the same.
- 0x08, 0x11, 0x08, 0x11,
- 0xff, // Placeholder.
- // First value larger.
- 0x08, 0x12, 0x08, 0x10,
- 0xff, // Placeholder.
- // Second value larger.
- 0x08, 0x10, 0x08, 0x12,
- 0xff, // Placeholder.
- };
-
- // Opcode followed by the expected values on the stack.
- std::vector<uint8_t> expected = {
- 0x29, 1, 0, 0, // eq
- 0x2a, 1, 1, 0, // ge
- 0x2b, 0, 1, 0, // gt
- 0x2c, 1, 0, 1, // le
- 0x2d, 0, 0, 1, // lt
- 0x2e, 0, 1, 1, // ne
- };
- for (size_t i = 0; i < expected.size(); i += 4) {
- opcode_buffer[4] = expected[i];
- opcode_buffer[9] = expected[i];
- opcode_buffer[14] = expected[i];
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Eval(0, 15))
- << "Op: 0x" << std::hex << static_cast<uint32_t>(expected[i]) << " failed";
-
- ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_EQ(expected[i + 1], this->op_->StackAt(2));
- ASSERT_EQ(expected[i + 2], this->op_->StackAt(1));
- ASSERT_EQ(expected[i + 3], this->op_->StackAt(0));
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_skip) {
- std::vector<uint8_t> opcode_buffer = {
- // Positive value.
- 0x2f, 0x10, 0x20,
- // Negative value.
- 0x2f, 0xfd, 0xff,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- uint64_t offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x2f, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
- ASSERT_EQ(offset + 0x2010, this->mem_->cur_offset());
-
- this->mem_->set_cur_offset(offset);
- offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x2f, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
- ASSERT_EQ(offset - 3, this->mem_->cur_offset());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_lit) {
- std::vector<uint8_t> opcode_buffer;
-
- // Verify every lit opcode.
- for (uint8_t op = 0x30; op <= 0x4f; op++) {
- opcode_buffer.push_back(op);
- }
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- for (size_t i = 0; i < opcode_buffer.size(); i++) {
- uint32_t op = opcode_buffer[i];
- ASSERT_TRUE(this->op_->Eval(i, i + 1)) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize()) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op - 0x30U, this->op_->StackAt(0)) << "Failed op: 0x" << std::hex << op;
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_reg) {
- std::vector<uint8_t> opcode_buffer;
-
- // Verify every reg opcode.
- for (uint8_t op = 0x50; op <= 0x6f; op++) {
- opcode_buffer.push_back(op);
- }
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- for (size_t i = 0; i < opcode_buffer.size(); i++) {
- uint32_t op = opcode_buffer[i];
- ASSERT_TRUE(this->op_->Eval(i, i + 1)) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op, this->op_->cur_op());
- ASSERT_TRUE(this->op_->is_register()) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(1U, this->op_->StackSize()) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op - 0x50U, this->op_->StackAt(0)) << "Failed op: 0x" << std::hex << op;
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_regx) {
- std::vector<uint8_t> opcode_buffer = {
- 0x90, 0x02, 0x90, 0x80, 0x15,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- ASSERT_TRUE(this->op_->Eval(0, 2));
- ASSERT_EQ(0x90, this->op_->cur_op());
- ASSERT_TRUE(this->op_->is_register());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x02U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Eval(2, 5));
- ASSERT_EQ(0x90, this->op_->cur_op());
- ASSERT_TRUE(this->op_->is_register());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0xa80U, this->op_->StackAt(0));
-}
-
-TYPED_TEST_P(DwarfOpTest, op_breg) {
- std::vector<uint8_t> opcode_buffer;
-
- // Verify every reg opcode.
- for (uint8_t op = 0x70; op <= 0x8f; op++) {
- // Positive value added to register.
- opcode_buffer.push_back(op);
- opcode_buffer.push_back(0x12);
- // Negative value added to register.
- opcode_buffer.push_back(op);
- opcode_buffer.push_back(0x7e);
- }
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- RegsImplFake<TypeParam> regs(32);
- for (size_t i = 0; i < 32; i++) {
- regs[i] = i + 10;
- }
- RegsInfo<TypeParam> regs_info(®s);
- this->op_->set_regs_info(®s_info);
-
- uint64_t offset = 0;
- for (uint32_t op = 0x70; op <= 0x8f; op++) {
- // Positive value added to register.
- ASSERT_TRUE(this->op_->Eval(offset, offset + 2)) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize()) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op - 0x70 + 10 + 0x12, this->op_->StackAt(0)) << "Failed op: 0x" << std::hex << op;
- offset += 2;
-
- // Negative value added to register.
- ASSERT_TRUE(this->op_->Eval(offset, offset + 2)) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize()) << "Failed op: 0x" << std::hex << op;
- ASSERT_EQ(op - 0x70 + 10 - 2, this->op_->StackAt(0)) << "Failed op: 0x" << std::hex << op;
- offset += 2;
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, op_breg_invalid_register) {
- std::vector<uint8_t> opcode_buffer = {
- 0x7f, 0x12, 0x80, 0x12,
- };
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- RegsImplFake<TypeParam> regs(16);
- for (size_t i = 0; i < 16; i++) {
- regs[i] = i + 10;
- }
- RegsInfo<TypeParam> regs_info(®s);
- this->op_->set_regs_info(®s_info);
-
- // Should pass since this references the last regsister.
- ASSERT_TRUE(this->op_->Eval(0, 2));
- ASSERT_EQ(0x7fU, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x2bU, this->op_->StackAt(0));
-
- // Should fail since this references a non-existent register.
- ASSERT_FALSE(this->op_->Eval(2, 4));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_bregx) {
- std::vector<uint8_t> opcode_buffer = {// Positive value added to register.
- 0x92, 0x05, 0x20,
- // Negative value added to register.
- 0x92, 0x06, 0x80, 0x7e,
- // Illegal register.
- 0x92, 0x80, 0x15, 0x80, 0x02};
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- RegsImplFake<TypeParam> regs(10);
- regs[5] = 0x45;
- regs[6] = 0x190;
- RegsInfo<TypeParam> regs_info(®s);
- this->op_->set_regs_info(®s_info);
-
- ASSERT_TRUE(this->op_->Eval(0, 3));
- ASSERT_EQ(0x92, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x65U, this->op_->StackAt(0));
-
- ASSERT_TRUE(this->op_->Eval(3, 7));
- ASSERT_EQ(0x92, this->op_->cur_op());
- ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_EQ(0x90U, this->op_->StackAt(0));
-
- ASSERT_FALSE(this->op_->Eval(7, 12));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfOpTest, op_nop) {
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x96});
-
- ASSERT_TRUE(this->op_->Decode());
- ASSERT_EQ(0x96, this->op_->cur_op());
- ASSERT_EQ(0U, this->op_->StackSize());
-}
-
-TYPED_TEST_P(DwarfOpTest, is_dex_pc) {
- // Special sequence that indicates this is a dex pc.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0c, 'D', 'E', 'X', '1', 0x13});
-
- ASSERT_TRUE(this->op_->Eval(0, 6));
- EXPECT_TRUE(this->op_->dex_pc_set());
-
- // Try without the last op.
- ASSERT_TRUE(this->op_->Eval(0, 5));
- EXPECT_FALSE(this->op_->dex_pc_set());
-
- // Change the constant.
- this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0c, 'D', 'E', 'X', '2', 0x13});
- ASSERT_TRUE(this->op_->Eval(0, 6));
- EXPECT_FALSE(this->op_->dex_pc_set());
-}
-
-REGISTER_TYPED_TEST_SUITE_P(DwarfOpTest, decode, eval, illegal_opcode, not_implemented, op_addr,
- op_deref, op_deref_size, const_unsigned, const_signed, const_uleb,
- const_sleb, op_dup, op_drop, op_over, op_pick, op_swap, op_rot, op_abs,
- op_and, op_div, op_minus, op_mod, op_mul, op_neg, op_not, op_or,
- op_plus, op_plus_uconst, op_shl, op_shr, op_shra, op_xor, op_bra,
- compare_opcode_stack_error, compare_opcodes, op_skip, op_lit, op_reg,
- op_regx, op_breg, op_breg_invalid_register, op_bregx, op_nop,
- is_dex_pc);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfOpTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfOpTest, DwarfOpTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
deleted file mode 100644
index a08a8d0..0000000
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfError.h>
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/Elf.h>
-
-#include "DwarfEncoding.h"
-
-#include "LogFake.h"
-#include "MemoryFake.h"
-#include "RegsFake.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class TestDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
- public:
- TestDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
- virtual ~TestDwarfSectionImpl() = default;
-
- bool Init(uint64_t, uint64_t, int64_t) override { return false; }
-
- void GetFdes(std::vector<const DwarfFde*>*) override {}
-
- const DwarfFde* GetFdeFromPc(uint64_t) override { return nullptr; }
-
- uint64_t GetCieOffsetFromFde32(uint32_t) { return 0; }
-
- uint64_t GetCieOffsetFromFde64(uint64_t) { return 0; }
-
- uint64_t AdjustPcFromFde(uint64_t) override { return 0; }
-
- void TestSetCachedCieLocRegs(uint64_t offset, const dwarf_loc_regs_t& loc_regs) {
- this->cie_loc_regs_[offset] = loc_regs;
- }
- void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
- void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
-};
-
-template <typename TypeParam>
-class DwarfSectionImplTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_.Clear();
- section_ = new TestDwarfSectionImpl<TypeParam>(&memory_);
- ResetLogs();
- }
-
- void TearDown() override { delete section_; }
-
- MemoryFake memory_;
- TestDwarfSectionImpl<TypeParam>* section_ = nullptr;
-};
-TYPED_TEST_SUITE_P(DwarfSectionImplTest);
-
-// NOTE: All test class variables need to be referenced as this->.
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache) {
- ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
- ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) {
- DwarfCie cie{.version = 3, .return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[9] = 0x3000;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x2, 0x5002}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x5000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_no_stack) {
- DwarfCie cie{.version = 3, .return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[9] = 0x3000;
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x96, 0x96, 0x96});
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x2, 0x5002}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_STATE, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr) {
- DwarfCie cie{.version = 3, .return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[9] = 0x3000;
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
- TypeParam cfa_value = 0x12345;
- this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value));
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_val_expr) {
- DwarfCie cie{.version = 3, .return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[9] = 0x3000;
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5004}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- ASSERT_FALSE(finished);
- EXPECT_EQ(0x80000000U, regs.sp());
- EXPECT_EQ(0x20U, regs.pc());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_is_register) {
- DwarfCie cie{.version = 3, .return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[9] = 0x3000;
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x50, 0x96, 0x96});
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x2, 0x5002}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_bad_regs) {
- DwarfCie cie{.return_address_register = 60};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_no_cfa) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_CFA_NOT_DEFINED, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_bad) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {20, 0}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-
- this->section_->TestClearError();
- loc_regs.erase(CFA_REG);
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_INVALID, {0, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-
- this->section_->TestClearError();
- loc_regs.erase(CFA_REG);
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_OFFSET, {0, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-
- this->section_->TestClearError();
- loc_regs.erase(CFA_REG);
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_prev) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[9] = 0x3000;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {9, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_FALSE(finished);
- EXPECT_EQ(0x20U, regs.pc());
- EXPECT_EQ(0x3000U, regs.sp());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_register_from_value) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[6] = 0x4000;
- regs[9] = 0x3000;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {6, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_FALSE(finished);
- EXPECT_EQ(0x20U, regs.pc());
- EXPECT_EQ(0x4000U, regs.sp());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_double_indirection) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[1] = 0x100;
- regs[3] = 0x300;
- regs[8] = 0x10;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 1}};
- loc_regs[9] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(0x301U, regs[1]);
- EXPECT_EQ(0x300U, regs[3]);
- EXPECT_EQ(0x10U, regs[8]);
- EXPECT_EQ(0x102U, regs[9]);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_register_reference_chain) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[0] = 0x10;
- regs[1] = 0x20;
- regs[2] = 0x30;
- regs[3] = 0x40;
- regs[4] = 0x50;
- regs[5] = 0x60;
- regs[8] = 0x20;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
- loc_regs[2] = DwarfLocation{DWARF_LOCATION_REGISTER, {1, 2}};
- loc_regs[3] = DwarfLocation{DWARF_LOCATION_REGISTER, {2, 3}};
- loc_regs[4] = DwarfLocation{DWARF_LOCATION_REGISTER, {3, 4}};
- loc_regs[5] = DwarfLocation{DWARF_LOCATION_REGISTER, {4, 5}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(0x10U, regs[0]);
- EXPECT_EQ(0x11U, regs[1]);
- EXPECT_EQ(0x22U, regs[2]);
- EXPECT_EQ(0x33U, regs[3]);
- EXPECT_EQ(0x44U, regs[4]);
- EXPECT_EQ(0x55U, regs[5]);
- EXPECT_EQ(0x20U, regs[8]);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_dex_pc) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[0] = 0x10;
- regs[8] = 0x20;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x8, 0x5008}};
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 'D', 'E', 'X', '1', 0x13, 0x08, 0x11});
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(0x10U, regs[0]);
- EXPECT_EQ(0x20U, regs[8]);
- EXPECT_EQ(0x11U, regs.dex_pc());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_invalid_register) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[8] = 0x10;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_REGISTER, {10, 0}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_different_reg_locations) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- if (sizeof(TypeParam) == sizeof(uint64_t)) {
- this->memory_.SetData64(0x2150, 0x12345678abcdef00ULL);
- } else {
- this->memory_.SetData32(0x2150, 0x12345678);
- }
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[3] = 0x234;
- regs[5] = 0x10;
- regs[8] = 0x2100;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_VAL_OFFSET, {0x100, 0}};
- loc_regs[2] = DwarfLocation{DWARF_LOCATION_OFFSET, {0x50, 0}};
- loc_regs[3] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_FALSE(finished);
- EXPECT_EQ(0x10U, regs.pc());
- EXPECT_EQ(0x2100U, regs.sp());
- EXPECT_EQ(0x2200U, regs[1]);
- EXPECT_EQ(0x234U, regs[3]);
- if (sizeof(TypeParam) == sizeof(uint64_t)) {
- EXPECT_EQ(0x12345678abcdef00ULL, regs[2]);
- } else {
- EXPECT_EQ(0x12345678U, regs[2]);
- }
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address_undefined) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[8] = 0x10;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[5] = DwarfLocation{DWARF_LOCATION_UNDEFINED, {0, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_TRUE(finished);
- EXPECT_EQ(0U, regs.pc());
- EXPECT_EQ(0x10U, regs.sp());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_pc_zero) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0;
- regs[8] = 0x10;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_TRUE(finished);
- EXPECT_EQ(0U, regs.pc());
- EXPECT_EQ(0x10U, regs.sp());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_return_address) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[8] = 0x10;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_FALSE(finished);
- EXPECT_EQ(0x20U, regs.pc());
- EXPECT_EQ(0x10U, regs.sp());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_ignore_large_reg_loc) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[5] = 0x20;
- regs[8] = 0x10;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- // This should not result in any errors.
- loc_regs[20] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_FALSE(finished);
- EXPECT_EQ(0x20U, regs.pc());
- EXPECT_EQ(0x10U, regs.sp());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_expr) {
- DwarfCie cie{.version = 3, .return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[8] = 0x3000;
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
- TypeParam cfa_value = 0x12345;
- this->memory_.SetMemory(0x80000000, &cfa_value, sizeof(cfa_value));
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[5] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_FALSE(finished);
- EXPECT_EQ(0x3000U, regs.sp());
- EXPECT_EQ(0x12345U, regs.pc());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_reg_val_expr) {
- DwarfCie cie{.version = 3, .return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- dwarf_loc_regs_t loc_regs;
-
- regs.set_pc(0x100);
- regs.set_sp(0x2000);
- regs[8] = 0x3000;
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x0c, 0x00, 0x00, 0x00, 0x80});
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[5] = DwarfLocation{DWARF_LOCATION_VAL_EXPRESSION, {0x4, 0x5004}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_FALSE(finished);
- EXPECT_EQ(0x3000U, regs.sp());
- EXPECT_EQ(0x80000000U, regs.pc());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register_invalid) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- regs.set_pseudo_reg(11);
- dwarf_loc_regs_t loc_regs;
-
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[1] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
- bool finished;
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-
- loc_regs.clear();
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[12] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
- ASSERT_FALSE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- EXPECT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Eval_pseudo_register) {
- DwarfCie cie{.return_address_register = 5};
- RegsImplFake<TypeParam> regs(10);
- regs.set_pseudo_reg(11);
- dwarf_loc_regs_t loc_regs;
-
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[11] = DwarfLocation{DWARF_LOCATION_PSEUDO_REGISTER, {20, 0}};
- bool finished;
- ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
- uint64_t pseudo_value = 0;
- ASSERT_TRUE(regs.GetPseudoRegister(11, &pseudo_value));
- EXPECT_EQ(20U, pseudo_value);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) {
- DwarfCie cie{};
- cie.cfa_instructions_offset = 0x3000;
- cie.cfa_instructions_end = 0x3002;
- DwarfFde fde{};
- fde.cie = &cie;
- fde.cie_offset = 0x8000;
- fde.cfa_instructions_offset = 0x6000;
- fde.cfa_instructions_end = 0x6002;
-
- this->memory_.SetMemory(0x3000, std::vector<uint8_t>{0x09, 0x02, 0x01});
- this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0x09, 0x04, 0x03});
-
- dwarf_loc_regs_t loc_regs;
- ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs, ARCH_UNKNOWN));
- ASSERT_EQ(2U, loc_regs.size());
-
- auto entry = loc_regs.find(2);
- ASSERT_NE(entry, loc_regs.end());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, entry->second.type);
- ASSERT_EQ(1U, entry->second.values[0]);
-
- entry = loc_regs.find(4);
- ASSERT_NE(entry, loc_regs.end());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, entry->second.type);
- ASSERT_EQ(3U, entry->second.values[0]);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_cached) {
- DwarfCie cie{};
- cie.cfa_instructions_offset = 0x3000;
- cie.cfa_instructions_end = 0x3002;
- DwarfFde fde{};
- fde.cie = &cie;
- fde.cie_offset = 0x8000;
- fde.cfa_instructions_offset = 0x6000;
- fde.cfa_instructions_end = 0x6002;
-
- dwarf_loc_regs_t cie_loc_regs;
- cie_loc_regs[6] = DwarfLocation{DWARF_LOCATION_REGISTER, {4, 0}};
- this->section_->TestSetCachedCieLocRegs(0x8000, cie_loc_regs);
- this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0x09, 0x04, 0x03});
-
- dwarf_loc_regs_t loc_regs;
- ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs, ARCH_UNKNOWN));
- ASSERT_EQ(2U, loc_regs.size());
-
- auto entry = loc_regs.find(6);
- ASSERT_NE(entry, loc_regs.end());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, entry->second.type);
- ASSERT_EQ(4U, entry->second.values[0]);
-
- entry = loc_regs.find(4);
- ASSERT_NE(entry, loc_regs.end());
- ASSERT_EQ(DWARF_LOCATION_REGISTER, entry->second.type);
- ASSERT_EQ(3U, entry->second.values[0]);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, Log) {
- DwarfCie cie{};
- cie.cfa_instructions_offset = 0x5000;
- cie.cfa_instructions_end = 0x5001;
- DwarfFde fde{};
- fde.cie = &cie;
- fde.cfa_instructions_offset = 0x6000;
- fde.cfa_instructions_end = 0x6001;
-
- this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x00});
- this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0xc2});
- ASSERT_TRUE(this->section_->Log(2, 0x1000, &fde, ARCH_UNKNOWN));
-
- ASSERT_EQ(
- "4 unwind DW_CFA_nop\n"
- "4 unwind Raw Data: 0x00\n"
- "4 unwind DW_CFA_restore register(2)\n"
- "4 unwind Raw Data: 0xc2\n",
- GetFakeLogPrint());
- ASSERT_EQ("", GetFakeLogBuf());
-}
-
-REGISTER_TYPED_TEST_SUITE_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache,
- GetFdeFromOffset_fail_should_not_cache, Eval_cfa_expr_eval_fail,
- Eval_cfa_expr_no_stack, Eval_cfa_expr_is_register, Eval_cfa_expr,
- Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa, Eval_cfa_bad,
- Eval_cfa_register_prev, Eval_cfa_register_from_value,
- Eval_double_indirection, Eval_register_reference_chain, Eval_dex_pc,
- Eval_invalid_register, Eval_different_reg_locations,
- Eval_return_address_undefined, Eval_pc_zero, Eval_return_address,
- Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
- Eval_pseudo_register_invalid, Eval_pseudo_register,
- GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
-
-typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfSectionImplTest, DwarfSectionImplTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
deleted file mode 100644
index febd6d3..0000000
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/Elf.h>
-
-#include "MemoryFake.h"
-#include "RegsFake.h"
-
-namespace unwindstack {
-
-class MockDwarfSection : public DwarfSection {
- public:
- MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
- virtual ~MockDwarfSection() = default;
-
- MOCK_METHOD(bool, Init, (uint64_t, uint64_t, int64_t), (override));
-
- MOCK_METHOD(bool, Eval, (const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*),
- (override));
-
- MOCK_METHOD(bool, Log, (uint8_t, uint64_t, const DwarfFde*, ArchEnum arch), (override));
-
- MOCK_METHOD(void, GetFdes, (std::vector<const DwarfFde*>*), (override));
-
- MOCK_METHOD(const DwarfFde*, GetFdeFromPc, (uint64_t), (override));
-
- MOCK_METHOD(bool, GetCfaLocationInfo,
- (uint64_t, const DwarfFde*, dwarf_loc_regs_t*, ArchEnum arch), (override));
-
- MOCK_METHOD(uint64_t, GetCieOffsetFromFde32, (uint32_t), (override));
-
- MOCK_METHOD(uint64_t, GetCieOffsetFromFde64, (uint64_t), (override));
-
- MOCK_METHOD(uint64_t, AdjustPcFromFde, (uint64_t), (override));
-};
-
-class DwarfSectionTest : public ::testing::Test {
- protected:
- void SetUp() override { section_.reset(new MockDwarfSection(&memory_)); }
-
- MemoryFake memory_;
- std::unique_ptr<MockDwarfSection> section_;
- static RegsFake regs_;
-};
-
-RegsFake DwarfSectionTest::regs_(10);
-
-TEST_F(DwarfSectionTest, Step_fail_fde) {
- EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr));
-
- bool finished;
- ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
-}
-
-TEST_F(DwarfSectionTest, Step_fail_cie_null) {
- DwarfFde fde{};
- fde.pc_end = 0x2000;
- fde.cie = nullptr;
-
- EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
-
- bool finished;
- ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished));
-}
-
-TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
- DwarfCie cie{};
- DwarfFde fde{};
- fde.pc_end = 0x2000;
- fde.cie = &cie;
-
- EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
- EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
- .WillOnce(::testing::Return(false));
-
- bool finished;
- ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished));
-}
-
-TEST_F(DwarfSectionTest, Step_pass) {
- DwarfCie cie{};
- DwarfFde fde{};
- fde.pc_end = 0x2000;
- fde.cie = &cie;
-
- EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
- EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
- .WillOnce(::testing::Return(true));
-
- MemoryFake process;
- EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, ®s_, ::testing::_))
- .WillOnce(::testing::Return(true));
-
- bool finished;
- ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
-}
-
-static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde,
- dwarf_loc_regs_t* loc_regs, ArchEnum) {
- loc_regs->pc_start = fde->pc_start;
- loc_regs->pc_end = fde->pc_end;
- return true;
-}
-
-TEST_F(DwarfSectionTest, Step_cache) {
- DwarfCie cie{};
- DwarfFde fde{};
- fde.pc_start = 0x500;
- fde.pc_end = 0x2000;
- fde.cie = &cie;
-
- EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
- EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
- .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
-
- MemoryFake process;
- EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, ®s_, ::testing::_))
- .WillRepeatedly(::testing::Return(true));
-
- bool finished;
- ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
- ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
- ASSERT_TRUE(section_->Step(0x1500, ®s_, &process, &finished));
-}
-
-TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
- DwarfCie cie{};
- DwarfFde fde0{};
- fde0.pc_start = 0x1000;
- fde0.pc_end = 0x2000;
- fde0.cie = &cie;
- EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde0));
- EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_, ::testing::_))
- .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
-
- MemoryFake process;
- EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, ®s_, ::testing::_))
- .WillRepeatedly(::testing::Return(true));
-
- bool finished;
- ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished));
-
- DwarfFde fde1{};
- fde1.pc_start = 0x500;
- fde1.pc_end = 0x800;
- fde1.cie = &cie;
- EXPECT_CALL(*section_, GetFdeFromPc(0x600)).WillOnce(::testing::Return(&fde1));
- EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_, ::testing::_))
- .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
-
- ASSERT_TRUE(section_->Step(0x600, ®s_, &process, &finished));
- ASSERT_TRUE(section_->Step(0x700, ®s_, &process, &finished));
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfCacheTest.cpp b/libunwindstack/tests/ElfCacheTest.cpp
deleted file mode 100644
index 5f13546..0000000
--- a/libunwindstack/tests/ElfCacheTest.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * 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 <elf.h>
-#include <unistd.h>
-
-#include <android-base/file.h>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-
-#include "ElfTestUtils.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class ElfCacheTest : public ::testing::Test {
- protected:
- static void SetUpTestSuite() { memory_.reset(new MemoryFake); }
-
- void SetUp() override { Elf::SetCachingEnabled(true); }
-
- void TearDown() override { Elf::SetCachingEnabled(false); }
-
- void WriteElfFile(uint64_t offset, TemporaryFile* tf, uint32_t type) {
- ASSERT_TRUE(type == EM_ARM || type == EM_386 || type == EM_X86_64);
- size_t ehdr_size;
- Elf32_Ehdr ehdr32;
- Elf64_Ehdr ehdr64;
- void* ptr;
- if (type == EM_ARM || type == EM_386) {
- ehdr_size = sizeof(ehdr32);
- ptr = &ehdr32;
- TestInitEhdr(&ehdr32, ELFCLASS32, type);
- } else {
- ehdr_size = sizeof(ehdr64);
- ptr = &ehdr64;
- TestInitEhdr(&ehdr64, ELFCLASS64, type);
- }
-
- ASSERT_EQ(offset, static_cast<uint64_t>(lseek(tf->fd, offset, SEEK_SET)));
- ASSERT_TRUE(android::base::WriteFully(tf->fd, ptr, ehdr_size));
- }
-
- void VerifyWithinSameMap(bool cache_enabled);
- void VerifySameMap(bool cache_enabled);
- void VerifyWithinSameMapNeverReadAtZero(bool cache_enabled);
-
- static std::shared_ptr<Memory> memory_;
-};
-
-std::shared_ptr<Memory> ElfCacheTest::memory_;
-
-void ElfCacheTest::VerifySameMap(bool cache_enabled) {
- if (!cache_enabled) {
- Elf::SetCachingEnabled(false);
- }
-
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
- WriteElfFile(0, &tf, EM_ARM);
- close(tf.fd);
-
- uint64_t start = 0x1000;
- uint64_t end = 0x20000;
- MapInfo info1(nullptr, nullptr, start, end, 0, 0x5, tf.path);
- MapInfo info2(nullptr, nullptr, start, end, 0, 0x5, tf.path);
-
- Elf* elf1 = info1.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf1->valid());
- Elf* elf2 = info2.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf2->valid());
-
- if (cache_enabled) {
- EXPECT_EQ(elf1, elf2);
- } else {
- EXPECT_NE(elf1, elf2);
- }
-}
-
-TEST_F(ElfCacheTest, no_caching) {
- VerifySameMap(false);
-}
-
-TEST_F(ElfCacheTest, caching_invalid_elf) {
- VerifySameMap(true);
-}
-
-void ElfCacheTest::VerifyWithinSameMap(bool cache_enabled) {
- if (!cache_enabled) {
- Elf::SetCachingEnabled(false);
- }
-
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
- WriteElfFile(0, &tf, EM_ARM);
- WriteElfFile(0x100, &tf, EM_386);
- WriteElfFile(0x200, &tf, EM_X86_64);
- lseek(tf.fd, 0x500, SEEK_SET);
- uint8_t value = 0;
- write(tf.fd, &value, 1);
- close(tf.fd);
-
- uint64_t start = 0x1000;
- uint64_t end = 0x20000;
- // Will have an elf at offset 0 in file.
- MapInfo info0_1(nullptr, nullptr, start, end, 0, 0x5, tf.path);
- MapInfo info0_2(nullptr, nullptr, start, end, 0, 0x5, tf.path);
- // Will have an elf at offset 0x100 in file.
- MapInfo info100_1(nullptr, nullptr, start, end, 0x100, 0x5, tf.path);
- MapInfo info100_2(nullptr, nullptr, start, end, 0x100, 0x5, tf.path);
- // Will have an elf at offset 0x200 in file.
- MapInfo info200_1(nullptr, nullptr, start, end, 0x200, 0x5, tf.path);
- MapInfo info200_2(nullptr, nullptr, start, end, 0x200, 0x5, tf.path);
- // Will have an elf at offset 0 in file.
- MapInfo info300_1(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
- MapInfo info300_2(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
-
- Elf* elf0_1 = info0_1.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf0_1->valid());
- EXPECT_EQ(ARCH_ARM, elf0_1->arch());
- Elf* elf0_2 = info0_2.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf0_2->valid());
- EXPECT_EQ(ARCH_ARM, elf0_2->arch());
- EXPECT_EQ(0U, info0_1.elf_offset);
- EXPECT_EQ(0U, info0_2.elf_offset);
- if (cache_enabled) {
- EXPECT_EQ(elf0_1, elf0_2);
- } else {
- EXPECT_NE(elf0_1, elf0_2);
- }
-
- Elf* elf100_1 = info100_1.GetElf(memory_, ARCH_X86);
- ASSERT_TRUE(elf100_1->valid());
- EXPECT_EQ(ARCH_X86, elf100_1->arch());
- Elf* elf100_2 = info100_2.GetElf(memory_, ARCH_X86);
- ASSERT_TRUE(elf100_2->valid());
- EXPECT_EQ(ARCH_X86, elf100_2->arch());
- EXPECT_EQ(0U, info100_1.elf_offset);
- EXPECT_EQ(0U, info100_2.elf_offset);
- if (cache_enabled) {
- EXPECT_EQ(elf100_1, elf100_2);
- } else {
- EXPECT_NE(elf100_1, elf100_2);
- }
-
- Elf* elf200_1 = info200_1.GetElf(memory_, ARCH_X86_64);
- ASSERT_TRUE(elf200_1->valid());
- EXPECT_EQ(ARCH_X86_64, elf200_1->arch());
- Elf* elf200_2 = info200_2.GetElf(memory_, ARCH_X86_64);
- ASSERT_TRUE(elf200_2->valid());
- EXPECT_EQ(ARCH_X86_64, elf200_2->arch());
- EXPECT_EQ(0U, info200_1.elf_offset);
- EXPECT_EQ(0U, info200_2.elf_offset);
- if (cache_enabled) {
- EXPECT_EQ(elf200_1, elf200_2);
- } else {
- EXPECT_NE(elf200_1, elf200_2);
- }
-
- Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf300_1->valid());
- EXPECT_EQ(ARCH_ARM, elf300_1->arch());
- Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf300_2->valid());
- EXPECT_EQ(ARCH_ARM, elf300_2->arch());
- EXPECT_EQ(0x300U, info300_1.elf_offset);
- EXPECT_EQ(0x300U, info300_2.elf_offset);
- if (cache_enabled) {
- EXPECT_EQ(elf300_1, elf300_2);
- EXPECT_EQ(elf0_1, elf300_1);
- } else {
- EXPECT_NE(elf300_1, elf300_2);
- EXPECT_NE(elf0_1, elf300_1);
- }
-}
-
-TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero) {
- VerifyWithinSameMap(false);
-}
-
-TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero) {
- VerifyWithinSameMap(true);
-}
-
-// Verify that when reading from multiple non-zero offsets in the same map
-// that when cached, all of the elf objects are the same.
-void ElfCacheTest::VerifyWithinSameMapNeverReadAtZero(bool cache_enabled) {
- if (!cache_enabled) {
- Elf::SetCachingEnabled(false);
- }
-
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
- WriteElfFile(0, &tf, EM_ARM);
- lseek(tf.fd, 0x500, SEEK_SET);
- uint8_t value = 0;
- write(tf.fd, &value, 1);
- close(tf.fd);
-
- uint64_t start = 0x1000;
- uint64_t end = 0x20000;
- // Multiple info sections at different offsets will have non-zero elf offsets.
- MapInfo info300_1(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
- MapInfo info300_2(nullptr, nullptr, start, end, 0x300, 0x5, tf.path);
- MapInfo info400_1(nullptr, nullptr, start, end, 0x400, 0x5, tf.path);
- MapInfo info400_2(nullptr, nullptr, start, end, 0x400, 0x5, tf.path);
-
- Elf* elf300_1 = info300_1.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf300_1->valid());
- EXPECT_EQ(ARCH_ARM, elf300_1->arch());
- Elf* elf300_2 = info300_2.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf300_2->valid());
- EXPECT_EQ(ARCH_ARM, elf300_2->arch());
- EXPECT_EQ(0x300U, info300_1.elf_offset);
- EXPECT_EQ(0x300U, info300_2.elf_offset);
- if (cache_enabled) {
- EXPECT_EQ(elf300_1, elf300_2);
- } else {
- EXPECT_NE(elf300_1, elf300_2);
- }
-
- Elf* elf400_1 = info400_1.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf400_1->valid());
- EXPECT_EQ(ARCH_ARM, elf400_1->arch());
- Elf* elf400_2 = info400_2.GetElf(memory_, ARCH_ARM);
- ASSERT_TRUE(elf400_2->valid());
- EXPECT_EQ(ARCH_ARM, elf400_2->arch());
- EXPECT_EQ(0x400U, info400_1.elf_offset);
- EXPECT_EQ(0x400U, info400_2.elf_offset);
- if (cache_enabled) {
- EXPECT_EQ(elf400_1, elf400_2);
- EXPECT_EQ(elf300_1, elf400_1);
- } else {
- EXPECT_NE(elf400_1, elf400_2);
- EXPECT_NE(elf300_1, elf400_1);
- }
-}
-
-TEST_F(ElfCacheTest, no_caching_valid_elf_offset_non_zero_never_read_at_zero) {
- VerifyWithinSameMapNeverReadAtZero(false);
-}
-
-TEST_F(ElfCacheTest, caching_valid_elf_offset_non_zero_never_read_at_zero) {
- VerifyWithinSameMapNeverReadAtZero(true);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfFake.cpp b/libunwindstack/tests/ElfFake.cpp
deleted file mode 100644
index 3d5ddd6..0000000
--- a/libunwindstack/tests/ElfFake.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2017 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 <deque>
-#include <string>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-#include "ElfFake.h"
-#include "RegsFake.h"
-
-namespace unwindstack {
-
-std::deque<FunctionData> ElfInterfaceFake::functions_;
-std::deque<StepData> ElfInterfaceFake::steps_;
-
-bool ElfInterfaceFake::GetFunctionName(uint64_t, std::string* name, uint64_t* offset) {
- if (functions_.empty()) {
- return false;
- }
- auto entry = functions_.front();
- functions_.pop_front();
- *name = entry.name;
- *offset = entry.offset;
- return true;
-}
-
-bool ElfInterfaceFake::GetGlobalVariable(const std::string& global, uint64_t* offset) {
- auto entry = globals_.find(global);
- if (entry == globals_.end()) {
- return false;
- }
- *offset = entry->second;
- return true;
-}
-
-bool ElfInterfaceFake::Step(uint64_t, Regs* regs, Memory*, bool* finished) {
- if (steps_.empty()) {
- return false;
- }
- auto entry = steps_.front();
- steps_.pop_front();
-
- if (entry.pc == 0 && entry.sp == 0 && !entry.finished) {
- // Pretend as though there is no frame.
- return false;
- }
-
- RegsFake* fake_regs = reinterpret_cast<RegsFake*>(regs);
- fake_regs->set_pc(entry.pc);
- fake_regs->set_sp(entry.sp);
- *finished = entry.finished;
- return true;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfFake.h b/libunwindstack/tests/ElfFake.h
deleted file mode 100644
index 3b6cb80..0000000
--- a/libunwindstack/tests/ElfFake.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2017 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_TESTS_ELF_FAKE_H
-#define _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
-
-#include <stdint.h>
-
-#include <deque>
-#include <string>
-#include <unordered_map>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-#include "ElfInterfaceArm.h"
-
-namespace unwindstack {
-
-struct StepData {
- StepData(uint64_t pc, uint64_t sp, bool finished) : pc(pc), sp(sp), finished(finished) {}
- uint64_t pc;
- uint64_t sp;
- bool finished;
-};
-
-struct FunctionData {
- FunctionData(std::string name, uint64_t offset) : name(name), offset(offset) {}
-
- std::string name;
- uint64_t offset;
-};
-
-class ElfFake : public Elf {
- public:
- ElfFake(Memory* memory) : Elf(memory) { valid_ = true; }
- virtual ~ElfFake() = default;
-
- void FakeSetValid(bool valid) { valid_ = valid; }
-
- void FakeSetLoadBias(uint64_t load_bias) { load_bias_ = load_bias; }
-
- void FakeSetArch(ArchEnum arch) { arch_ = arch; }
-
- void FakeSetInterface(ElfInterface* interface) { interface_.reset(interface); }
- void FakeSetGnuDebugdataInterface(ElfInterface* interface) {
- gnu_debugdata_interface_.reset(interface);
- }
-};
-
-class ElfInterfaceFake : public ElfInterface {
- public:
- ElfInterfaceFake(Memory* memory) : ElfInterface(memory) {}
- virtual ~ElfInterfaceFake() = default;
-
- bool Init(int64_t*) override { return false; }
- void InitHeaders() override {}
- std::string GetSoname() override { return fake_soname_; }
-
- bool GetFunctionName(uint64_t, std::string*, uint64_t*) override;
- bool GetGlobalVariable(const std::string&, uint64_t*) override;
- std::string GetBuildID() override { return fake_build_id_; }
-
- bool Step(uint64_t, Regs*, Memory*, bool*) override;
-
- void FakeSetGlobalVariable(const std::string& global, uint64_t offset) {
- globals_[global] = offset;
- }
-
- void FakeSetBuildID(std::string& build_id) { fake_build_id_ = build_id; }
- void FakeSetBuildID(const char* build_id) { fake_build_id_ = build_id; }
-
- void FakeSetSoname(const char* soname) { fake_soname_ = soname; }
-
- static void FakePushFunctionData(const FunctionData data) { functions_.push_back(data); }
- static void FakePushStepData(const StepData data) { steps_.push_back(data); }
-
- static void FakeClear() {
- functions_.clear();
- steps_.clear();
- }
-
- void FakeSetErrorCode(ErrorCode code) { last_error_.code = code; }
-
- void FakeSetErrorAddress(uint64_t address) { last_error_.address = address; }
-
- void FakeSetDataOffset(uint64_t offset) { data_offset_ = offset; }
- void FakeSetDataVaddrStart(uint64_t vaddr) { data_vaddr_start_ = vaddr; }
- void FakeSetDataVaddrEnd(uint64_t vaddr) { data_vaddr_end_ = vaddr; }
-
- void FakeSetDynamicOffset(uint64_t offset) { dynamic_offset_ = offset; }
- void FakeSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; }
- void FakeSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; }
-
- void FakeSetGnuDebugdataOffset(uint64_t offset) { gnu_debugdata_offset_ = offset; }
- void FakeSetGnuDebugdataSize(uint64_t size) { gnu_debugdata_size_ = size; }
-
- private:
- std::unordered_map<std::string, uint64_t> globals_;
- std::string fake_build_id_;
- std::string fake_soname_;
-
- static std::deque<FunctionData> functions_;
- static std::deque<StepData> steps_;
-};
-
-class ElfInterface32Fake : public ElfInterface32 {
- public:
- ElfInterface32Fake(Memory* memory) : ElfInterface32(memory) {}
- virtual ~ElfInterface32Fake() = default;
-
- void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
- void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
- void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
- void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
-class ElfInterface64Fake : public ElfInterface64 {
- public:
- ElfInterface64Fake(Memory* memory) : ElfInterface64(memory) {}
- virtual ~ElfInterface64Fake() = default;
-
- void FakeSetEhFrameOffset(uint64_t offset) { eh_frame_offset_ = offset; }
- void FakeSetEhFrameSize(uint64_t size) { eh_frame_size_ = size; }
- void FakeSetDebugFrameOffset(uint64_t offset) { debug_frame_offset_ = offset; }
- void FakeSetDebugFrameSize(uint64_t size) { debug_frame_size_ = size; }
-};
-
-class ElfInterfaceArmFake : public ElfInterfaceArm {
- public:
- ElfInterfaceArmFake(Memory* memory) : ElfInterfaceArm(memory) {}
- virtual ~ElfInterfaceArmFake() = default;
-
- void FakeSetStartOffset(uint64_t offset) { start_offset_ = offset; }
- void FakeSetTotalEntries(size_t entries) { total_entries_ = entries; }
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_ELF_FAKE_H
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
deleted file mode 100644
index 43c6a97..0000000
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-
-#include <gtest/gtest.h>
-
-#include <vector>
-
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/RegsArm.h>
-
-#include "ElfInterfaceArm.h"
-
-#include "ElfFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class ElfInterfaceArmTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_.Clear();
- process_memory_.Clear();
- }
-
- MemoryFake memory_;
- MemoryFake process_memory_;
-};
-
-TEST_F(ElfInterfaceArmTest, GetPrel32Addr) {
- ElfInterfaceArmFake interface(&memory_);
- memory_.SetData32(0x1000, 0x230000);
-
- uint32_t value;
- ASSERT_TRUE(interface.GetPrel31Addr(0x1000, &value));
- ASSERT_EQ(0x231000U, value);
-
- memory_.SetData32(0x1000, 0x80001000);
- ASSERT_TRUE(interface.GetPrel31Addr(0x1000, &value));
- ASSERT_EQ(0x2000U, value);
-
- memory_.SetData32(0x1000, 0x70001000);
- ASSERT_TRUE(interface.GetPrel31Addr(0x1000, &value));
- ASSERT_EQ(0xf0002000U, value);
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_start_zero) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0);
- interface.FakeSetTotalEntries(10);
-
- uint64_t entry_offset;
- ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_no_entries) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x100);
- interface.FakeSetTotalEntries(0);
-
- uint64_t entry_offset;
- ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_no_valid_memory) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x100);
- interface.FakeSetTotalEntries(2);
-
- uint64_t entry_offset;
- ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_ip_before_first) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(1);
- memory_.SetData32(0x1000, 0x6000);
-
- uint64_t entry_offset;
- ASSERT_FALSE(interface.FindEntry(0x1000, &entry_offset));
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_single_entry_negative_value) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x8000);
- interface.FakeSetTotalEntries(1);
- memory_.SetData32(0x8000, 0x7fffff00);
-
- uint64_t entry_offset;
- ASSERT_TRUE(interface.FindEntry(0x7ff0, &entry_offset));
- ASSERT_EQ(0x8000U, entry_offset);
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_two_entries) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(2);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1008, 0x7000);
-
- uint64_t entry_offset;
- ASSERT_TRUE(interface.FindEntry(0x7000, &entry_offset));
- ASSERT_EQ(0x1000U, entry_offset);
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_last_check_single_entry) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(1);
- memory_.SetData32(0x1000, 0x6000);
-
- uint64_t entry_offset;
- ASSERT_TRUE(interface.FindEntry(0x7000, &entry_offset));
- ASSERT_EQ(0x1000U, entry_offset);
-
- // To guarantee that we are using the cache on the second run,
- // set the memory to a different value.
- memory_.SetData32(0x1000, 0x8000);
- ASSERT_TRUE(interface.FindEntry(0x7004, &entry_offset));
- ASSERT_EQ(0x1000U, entry_offset);
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_last_check_multiple_entries) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(2);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1008, 0x8000);
-
- uint64_t entry_offset;
- ASSERT_TRUE(interface.FindEntry(0x9008, &entry_offset));
- ASSERT_EQ(0x1008U, entry_offset);
-
- // To guarantee that we are using the cache on the second run,
- // set the memory to a different value.
- memory_.SetData32(0x1000, 0x16000);
- memory_.SetData32(0x1008, 0x18000);
- ASSERT_TRUE(interface.FindEntry(0x9100, &entry_offset));
- ASSERT_EQ(0x1008U, entry_offset);
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_even) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(4);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1008, 0x7000);
- memory_.SetData32(0x1010, 0x8000);
- memory_.SetData32(0x1018, 0x9000);
-
- uint64_t entry_offset;
- ASSERT_TRUE(interface.FindEntry(0x9100, &entry_offset));
- ASSERT_EQ(0x1010U, entry_offset);
-
- // To guarantee that we are using the cache on the second run,
- // set the memory to a different value.
- memory_.SetData32(0x1000, 0x16000);
- memory_.SetData32(0x1008, 0x17000);
- memory_.SetData32(0x1010, 0x18000);
- memory_.SetData32(0x1018, 0x19000);
- ASSERT_TRUE(interface.FindEntry(0x9100, &entry_offset));
- ASSERT_EQ(0x1010U, entry_offset);
-}
-
-TEST_F(ElfInterfaceArmTest, FindEntry_multiple_entries_odd) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(5);
- memory_.SetData32(0x1000, 0x5000);
- memory_.SetData32(0x1008, 0x6000);
- memory_.SetData32(0x1010, 0x7000);
- memory_.SetData32(0x1018, 0x8000);
- memory_.SetData32(0x1020, 0x9000);
-
- uint64_t entry_offset;
- ASSERT_TRUE(interface.FindEntry(0x8100, &entry_offset));
- ASSERT_EQ(0x1010U, entry_offset);
-
- // To guarantee that we are using the cache on the second run,
- // set the memory to a different value.
- memory_.SetData32(0x1000, 0x15000);
- memory_.SetData32(0x1008, 0x16000);
- memory_.SetData32(0x1010, 0x17000);
- memory_.SetData32(0x1018, 0x18000);
- memory_.SetData32(0x1020, 0x19000);
- ASSERT_TRUE(interface.FindEntry(0x8100, &entry_offset));
- ASSERT_EQ(0x1010U, entry_offset);
-}
-
-TEST_F(ElfInterfaceArmTest, iterate) {
- ElfInterfaceArmFake interface(&memory_);
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(5);
- memory_.SetData32(0x1000, 0x5000);
- memory_.SetData32(0x1008, 0x6000);
- memory_.SetData32(0x1010, 0x7000);
- memory_.SetData32(0x1018, 0x8000);
- memory_.SetData32(0x1020, 0x9000);
-
- std::vector<uint32_t> entries;
- for (auto addr : interface) {
- entries.push_back(addr);
- }
- ASSERT_EQ(5U, entries.size());
- ASSERT_EQ(0x6000U, entries[0]);
- ASSERT_EQ(0x7008U, entries[1]);
- ASSERT_EQ(0x8010U, entries[2]);
- ASSERT_EQ(0x9018U, entries[3]);
- ASSERT_EQ(0xa020U, entries[4]);
-
- // Make sure the iterate cached the entries.
- memory_.SetData32(0x1000, 0x11000);
- memory_.SetData32(0x1008, 0x12000);
- memory_.SetData32(0x1010, 0x13000);
- memory_.SetData32(0x1018, 0x14000);
- memory_.SetData32(0x1020, 0x15000);
-
- entries.clear();
- for (auto addr : interface) {
- entries.push_back(addr);
- }
- ASSERT_EQ(5U, entries.size());
- ASSERT_EQ(0x6000U, entries[0]);
- ASSERT_EQ(0x7008U, entries[1]);
- ASSERT_EQ(0x8010U, entries[2]);
- ASSERT_EQ(0x9018U, entries[3]);
- ASSERT_EQ(0xa020U, entries[4]);
-}
-
-TEST_F(ElfInterfaceArmTest, HandleUnknownType_arm_exidx) {
- ElfInterfaceArmFake interface(&memory_);
-
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(100);
-
- // Verify that if the type is not the one we want, we don't set the values.
- interface.HandleUnknownType(0x70000000, 0x2000, 320);
- ASSERT_EQ(0x1000U, interface.start_offset());
- ASSERT_EQ(100U, interface.total_entries());
-
- // Everything is correct and present.
- interface.HandleUnknownType(0x70000001, 0x2000, 320);
- ASSERT_EQ(0x2000U, interface.start_offset());
- ASSERT_EQ(40U, interface.total_entries());
-}
-
-TEST_F(ElfInterfaceArmTest, StepExidx) {
- ElfInterfaceArmFake interface(&memory_);
-
- // FindEntry fails.
- bool finished;
- ASSERT_FALSE(interface.StepExidx(0x7000, nullptr, nullptr, &finished));
- EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
-
- // ExtractEntry should fail.
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(2);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1008, 0x8000);
-
- RegsArm regs;
- regs[ARM_REG_SP] = 0x1000;
- regs[ARM_REG_LR] = 0x20000;
- regs.set_sp(regs[ARM_REG_SP]);
- regs.set_pc(0x1234);
- ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_MEMORY_INVALID, interface.LastErrorCode());
- EXPECT_EQ(0x1004U, interface.LastErrorAddress());
-
- // Eval should fail.
- memory_.SetData32(0x1004, 0x81000000);
- ASSERT_FALSE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
-
- // Everything should pass.
- memory_.SetData32(0x1004, 0x80b0b0b0);
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
- ASSERT_FALSE(finished);
- ASSERT_EQ(0x1000U, regs.sp());
- ASSERT_EQ(0x1000U, regs[ARM_REG_SP]);
- ASSERT_EQ(0x20000U, regs.pc());
- ASSERT_EQ(0x20000U, regs[ARM_REG_PC]);
-
- // Load bias is non-zero.
- interface.set_load_bias(0x1000);
- ASSERT_TRUE(interface.StepExidx(0x8000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
-
- // Pc too small.
- interface.set_load_bias(0x9000);
- ASSERT_FALSE(interface.StepExidx(0x8000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_UNWIND_INFO, interface.LastErrorCode());
-}
-
-TEST_F(ElfInterfaceArmTest, StepExidx_pc_set) {
- ElfInterfaceArmFake interface(&memory_);
-
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(2);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1004, 0x808800b0);
- memory_.SetData32(0x1008, 0x8000);
- process_memory_.SetData32(0x10000, 0x10);
-
- RegsArm regs;
- regs[ARM_REG_SP] = 0x10000;
- regs[ARM_REG_LR] = 0x20000;
- regs.set_sp(regs[ARM_REG_SP]);
- regs.set_pc(0x1234);
-
- // Everything should pass.
- bool finished;
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
- ASSERT_FALSE(finished);
- ASSERT_EQ(0x10004U, regs.sp());
- ASSERT_EQ(0x10004U, regs[ARM_REG_SP]);
- ASSERT_EQ(0x10U, regs.pc());
- ASSERT_EQ(0x10U, regs[ARM_REG_PC]);
-}
-
-TEST_F(ElfInterfaceArmTest, StepExidx_cant_unwind) {
- ElfInterfaceArmFake interface(&memory_);
-
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(1);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1004, 1);
-
- RegsArm regs;
- regs[ARM_REG_SP] = 0x10000;
- regs[ARM_REG_LR] = 0x20000;
- regs.set_sp(regs[ARM_REG_SP]);
- regs.set_pc(0x1234);
-
- bool finished;
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
- ASSERT_TRUE(finished);
- ASSERT_EQ(0x10000U, regs.sp());
- ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
- ASSERT_EQ(0x1234U, regs.pc());
-}
-
-TEST_F(ElfInterfaceArmTest, StepExidx_refuse_unwind) {
- ElfInterfaceArmFake interface(&memory_);
-
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(1);
- memory_.SetData32(0x1000, 0x6000);
- memory_.SetData32(0x1004, 0x808000b0);
-
- RegsArm regs;
- regs[ARM_REG_SP] = 0x10000;
- regs[ARM_REG_LR] = 0x20000;
- regs.set_sp(regs[ARM_REG_SP]);
- regs.set_pc(0x1234);
-
- bool finished;
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
- ASSERT_TRUE(finished);
- ASSERT_EQ(0x10000U, regs.sp());
- ASSERT_EQ(0x10000U, regs[ARM_REG_SP]);
- ASSERT_EQ(0x1234U, regs.pc());
-}
-
-TEST_F(ElfInterfaceArmTest, StepExidx_pc_zero) {
- ElfInterfaceArmFake interface(&memory_);
-
- interface.FakeSetStartOffset(0x1000);
- interface.FakeSetTotalEntries(1);
- memory_.SetData32(0x1000, 0x6000);
- // Set the pc using a pop r15 command.
- memory_.SetData32(0x1004, 0x808800b0);
-
- // pc value of zero.
- process_memory_.SetData32(0x10000, 0);
-
- RegsArm regs;
- regs[ARM_REG_SP] = 0x10000;
- regs[ARM_REG_LR] = 0x20000;
- regs.set_sp(regs[ARM_REG_SP]);
- regs.set_pc(0x1234);
-
- bool finished;
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
- ASSERT_TRUE(finished);
- ASSERT_EQ(0U, regs.pc());
-
- // Now set the pc from the lr register (pop r14).
- memory_.SetData32(0x1004, 0x808400b0);
-
- regs[ARM_REG_SP] = 0x10000;
- regs[ARM_REG_LR] = 0x20000;
- regs.set_sp(regs[ARM_REG_SP]);
- regs.set_pc(0x1234);
-
- ASSERT_TRUE(interface.StepExidx(0x7000, ®s, &process_memory_, &finished));
- EXPECT_EQ(ERROR_NONE, interface.LastErrorCode());
- ASSERT_TRUE(finished);
- ASSERT_EQ(0U, regs.pc());
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
deleted file mode 100644
index 3cf90fe..0000000
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ /dev/null
@@ -1,1966 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-
-#include <memory>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/ElfInterface.h>
-
-#include "DwarfEncoding.h"
-#include "ElfInterfaceArm.h"
-
-#include "ElfFake.h"
-#include "MemoryFake.h"
-
-#if !defined(PT_ARM_EXIDX)
-#define PT_ARM_EXIDX 0x70000001
-#endif
-
-#if !defined(EM_AARCH64)
-#define EM_AARCH64 183
-#endif
-
-namespace unwindstack {
-
-class ElfInterfaceTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_.Clear();
- }
-
- void SetStringMemory(uint64_t offset, const char* string) {
- memory_.SetMemory(offset, string, strlen(string) + 1);
- }
-
- template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
- void SinglePtLoad();
-
- template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
- void MultipleExecutablePtLoads();
-
- template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
- void MultipleExecutablePtLoadsIncrementsNotSizeOfPhdr();
-
- template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
- void NonExecutablePtLoads();
-
- template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
- void ManyPhdrs();
-
- enum SonameTestEnum : uint8_t {
- SONAME_NORMAL,
- SONAME_DTNULL_AFTER,
- SONAME_DTSIZE_SMALL,
- SONAME_MISSING_MAP,
- };
-
- template <typename Ehdr, typename Phdr, typename Shdr, typename Dyn>
- void SonameInit(SonameTestEnum test_type = SONAME_NORMAL);
-
- template <typename ElfInterfaceType>
- void Soname();
-
- template <typename ElfInterfaceType>
- void SonameAfterDtNull();
-
- template <typename ElfInterfaceType>
- void SonameSize();
-
- template <typename ElfInterfaceType>
- void SonameMissingMap();
-
- template <typename ElfType>
- void InitHeadersEhFrameTest();
-
- template <typename ElfType>
- void InitHeadersDebugFrame();
-
- template <typename ElfType>
- void InitHeadersEhFrameFail();
-
- template <typename ElfType>
- void InitHeadersDebugFrameFail();
-
- template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
- void InitProgramHeadersMalformed();
-
- template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
- void InitSectionHeadersMalformed();
-
- template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
- void InitSectionHeadersMalformedSymData();
-
- template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
- void InitSectionHeaders(uint64_t entry_size);
-
- template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
- void InitSectionHeadersOffsets();
-
- template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
- void InitSectionHeadersOffsetsEhFrameSectionBias(uint64_t addr, uint64_t offset,
- int64_t expected_bias);
-
- template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
- void InitSectionHeadersOffsetsEhFrameHdrSectionBias(uint64_t addr, uint64_t offset,
- int64_t expected_bias);
-
- template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
- void InitSectionHeadersOffsetsDebugFrameSectionBias(uint64_t addr, uint64_t offset,
- int64_t expected_bias);
-
- template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
- void CheckGnuEhFrame(uint64_t addr, uint64_t offset, int64_t expected_bias);
-
- template <typename Sym>
- void InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset,
- uint64_t sym_offset, const char* name);
-
- template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
- void BuildID();
-
- template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
- void BuildIDTwoNotes();
-
- template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
- void BuildIDSectionTooSmallForName();
-
- template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
- void BuildIDSectionTooSmallForDesc();
-
- template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
- void BuildIDSectionTooSmallForHeader();
-
- template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
- void CheckLoadBiasInFirstPhdr(int64_t load_bias);
-
- template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
- void CheckLoadBiasInFirstExecPhdr(uint64_t offset, uint64_t vaddr, int64_t load_bias);
-
- MemoryFake memory_;
-};
-
-template <typename Sym>
-void ElfInterfaceTest::InitSym(uint64_t offset, uint32_t value, uint32_t size, uint32_t name_offset,
- uint64_t sym_offset, const char* name) {
- Sym sym = {};
- sym.st_info = STT_FUNC;
- sym.st_value = value;
- sym.st_size = size;
- sym.st_name = name_offset;
- sym.st_shndx = SHN_COMMON;
-
- memory_.SetMemory(offset, &sym, sizeof(sym));
- memory_.SetMemory(sym_offset + name_offset, name, strlen(name) + 1);
-}
-
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
-void ElfInterfaceTest::SinglePtLoad() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 1;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_vaddr = 0x2000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000, load_bias);
-
- const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
- ASSERT_EQ(1U, pt_loads.size());
- LoadInfo load_data = pt_loads.at(0);
- ASSERT_EQ(0U, load_data.offset);
- ASSERT_EQ(0x2000U, load_data.table_offset);
- ASSERT_EQ(0x10000U, load_data.table_size);
-}
-
-TEST_F(ElfInterfaceTest, single_pt_load_32) {
- SinglePtLoad<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, single_pt_load_64) {
- SinglePtLoad<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
-void ElfInterfaceTest::MultipleExecutablePtLoads() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 3;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_vaddr = 0x2000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x1000;
- phdr.p_vaddr = 0x2001;
- phdr.p_memsz = 0x10001;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1001;
- memory_.SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x2000;
- phdr.p_vaddr = 0x2002;
- phdr.p_memsz = 0x10002;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1002;
- memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000, load_bias);
-
- const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
- ASSERT_EQ(3U, pt_loads.size());
-
- LoadInfo load_data = pt_loads.at(0);
- ASSERT_EQ(0U, load_data.offset);
- ASSERT_EQ(0x2000U, load_data.table_offset);
- ASSERT_EQ(0x10000U, load_data.table_size);
-
- load_data = pt_loads.at(0x1000);
- ASSERT_EQ(0x1000U, load_data.offset);
- ASSERT_EQ(0x2001U, load_data.table_offset);
- ASSERT_EQ(0x10001U, load_data.table_size);
-
- load_data = pt_loads.at(0x2000);
- ASSERT_EQ(0x2000U, load_data.offset);
- ASSERT_EQ(0x2002U, load_data.table_offset);
- ASSERT_EQ(0x10002U, load_data.table_size);
-}
-
-TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_32) {
- MultipleExecutablePtLoads<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_64) {
- MultipleExecutablePtLoads<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
-void ElfInterfaceTest::MultipleExecutablePtLoadsIncrementsNotSizeOfPhdr() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 3;
- ehdr.e_phentsize = sizeof(Phdr) + 100;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_vaddr = 0x2000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x1000;
- phdr.p_vaddr = 0x2001;
- phdr.p_memsz = 0x10001;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1001;
- memory_.SetMemory(0x100 + sizeof(phdr) + 100, &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x2000;
- phdr.p_vaddr = 0x2002;
- phdr.p_memsz = 0x10002;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1002;
- memory_.SetMemory(0x100 + 2 * (sizeof(phdr) + 100), &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000, load_bias);
-
- const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
- ASSERT_EQ(3U, pt_loads.size());
-
- LoadInfo load_data = pt_loads.at(0);
- ASSERT_EQ(0U, load_data.offset);
- ASSERT_EQ(0x2000U, load_data.table_offset);
- ASSERT_EQ(0x10000U, load_data.table_size);
-
- load_data = pt_loads.at(0x1000);
- ASSERT_EQ(0x1000U, load_data.offset);
- ASSERT_EQ(0x2001U, load_data.table_offset);
- ASSERT_EQ(0x10001U, load_data.table_size);
-
- load_data = pt_loads.at(0x2000);
- ASSERT_EQ(0x2000U, load_data.offset);
- ASSERT_EQ(0x2002U, load_data.table_offset);
- ASSERT_EQ(0x10002U, load_data.table_size);
-}
-
-TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_increments_not_size_of_phdr_32) {
- MultipleExecutablePtLoadsIncrementsNotSizeOfPhdr<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn,
- ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, multiple_executable_pt_loads_increments_not_size_of_phdr_64) {
- MultipleExecutablePtLoadsIncrementsNotSizeOfPhdr<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn,
- ElfInterface64>();
-}
-
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
-void ElfInterfaceTest::NonExecutablePtLoads() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 3;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_vaddr = 0x2000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x1000;
- phdr.p_vaddr = 0x2001;
- phdr.p_memsz = 0x10001;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1001;
- memory_.SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x2000;
- phdr.p_vaddr = 0x2002;
- phdr.p_memsz = 0x10002;
- phdr.p_flags = PF_R;
- phdr.p_align = 0x1002;
- memory_.SetMemory(0x100 + 2 * sizeof(phdr), &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x1001, load_bias);
-
- const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
- ASSERT_EQ(1U, pt_loads.size());
-
- LoadInfo load_data = pt_loads.at(0x1000);
- ASSERT_EQ(0x1000U, load_data.offset);
- ASSERT_EQ(0x2001U, load_data.table_offset);
- ASSERT_EQ(0x10001U, load_data.table_size);
-}
-
-TEST_F(ElfInterfaceTest, non_executable_pt_loads_32) {
- NonExecutablePtLoads<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, non_executable_pt_loads_64) {
- NonExecutablePtLoads<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Phdr, typename Dyn, typename ElfInterfaceType>
-void ElfInterfaceTest::ManyPhdrs() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 7;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- uint64_t phdr_offset = 0x100;
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_vaddr = 0x2000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_GNU_EH_FRAME;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_DYNAMIC;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_INTERP;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_NOTE;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_SHLIB;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_GNU_EH_FRAME;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000, load_bias);
-
- const std::unordered_map<uint64_t, LoadInfo>& pt_loads = elf->pt_loads();
- ASSERT_EQ(1U, pt_loads.size());
-
- LoadInfo load_data = pt_loads.at(0);
- ASSERT_EQ(0U, load_data.offset);
- ASSERT_EQ(0x2000U, load_data.table_offset);
- ASSERT_EQ(0x10000U, load_data.table_size);
-}
-
-TEST_F(ElfInterfaceTest, many_phdrs_32) {
- ElfInterfaceTest::ManyPhdrs<Elf32_Ehdr, Elf32_Phdr, Elf32_Dyn, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, many_phdrs_64) {
- ElfInterfaceTest::ManyPhdrs<Elf64_Ehdr, Elf64_Phdr, Elf64_Dyn, ElfInterface64>();
-}
-
-TEST_F(ElfInterfaceTest, arm32) {
- ElfInterfaceArm elf_arm(&memory_);
-
- Elf32_Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 1;
- ehdr.e_phentsize = sizeof(Elf32_Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Elf32_Phdr phdr = {};
- phdr.p_type = PT_ARM_EXIDX;
- phdr.p_offset = 0x2000;
- phdr.p_filesz = 16;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- // Add arm exidx entries.
- memory_.SetData32(0x2000, 0x1000);
- memory_.SetData32(0x2008, 0x1000);
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf_arm.Init(&load_bias));
- EXPECT_EQ(0, load_bias);
-
- std::vector<uint32_t> entries;
- for (auto addr : elf_arm) {
- entries.push_back(addr);
- }
- ASSERT_EQ(2U, entries.size());
- ASSERT_EQ(0x3000U, entries[0]);
- ASSERT_EQ(0x3008U, entries[1]);
-
- ASSERT_EQ(0x2000U, elf_arm.start_offset());
- ASSERT_EQ(2U, elf_arm.total_entries());
-}
-
-template <typename Ehdr, typename Phdr, typename Shdr, typename Dyn>
-void ElfInterfaceTest::SonameInit(SonameTestEnum test_type) {
- Ehdr ehdr = {};
- ehdr.e_shoff = 0x200;
- ehdr.e_shnum = 2;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 1;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Shdr shdr = {};
- shdr.sh_type = SHT_STRTAB;
- if (test_type == SONAME_MISSING_MAP) {
- shdr.sh_addr = 0x20100;
- } else {
- shdr.sh_addr = 0x10100;
- }
- shdr.sh_offset = 0x10000;
- memory_.SetMemory(0x200 + sizeof(shdr), &shdr, sizeof(shdr));
-
- Phdr phdr = {};
- phdr.p_type = PT_DYNAMIC;
- phdr.p_offset = 0x2000;
- phdr.p_memsz = sizeof(Dyn) * 3;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- uint64_t offset = 0x2000;
- Dyn dyn;
-
- dyn.d_tag = DT_STRTAB;
- dyn.d_un.d_ptr = 0x10100;
- memory_.SetMemory(offset, &dyn, sizeof(dyn));
- offset += sizeof(dyn);
-
- dyn.d_tag = DT_STRSZ;
- if (test_type == SONAME_DTSIZE_SMALL) {
- dyn.d_un.d_val = 0x10;
- } else {
- dyn.d_un.d_val = 0x1000;
- }
- memory_.SetMemory(offset, &dyn, sizeof(dyn));
- offset += sizeof(dyn);
-
- if (test_type == SONAME_DTNULL_AFTER) {
- dyn.d_tag = DT_NULL;
- memory_.SetMemory(offset, &dyn, sizeof(dyn));
- offset += sizeof(dyn);
- }
-
- dyn.d_tag = DT_SONAME;
- dyn.d_un.d_val = 0x10;
- memory_.SetMemory(offset, &dyn, sizeof(dyn));
- offset += sizeof(dyn);
-
- dyn.d_tag = DT_NULL;
- memory_.SetMemory(offset, &dyn, sizeof(dyn));
-
- SetStringMemory(0x10010, "fake_soname.so");
-}
-
-template <typename ElfInterfaceType>
-void ElfInterfaceTest::Soname() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
-
- ASSERT_EQ("fake_soname.so", elf->GetSoname());
-}
-
-TEST_F(ElfInterfaceTest, soname_32) {
- SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>();
- Soname<ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, soname_64) {
- SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>();
- Soname<ElfInterface64>();
-}
-
-template <typename ElfInterfaceType>
-void ElfInterfaceTest::SonameAfterDtNull() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
-
- ASSERT_EQ("", elf->GetSoname());
-}
-
-TEST_F(ElfInterfaceTest, soname_after_dt_null_32) {
- SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTNULL_AFTER);
- SonameAfterDtNull<ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, soname_after_dt_null_64) {
- SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTNULL_AFTER);
- SonameAfterDtNull<ElfInterface64>();
-}
-
-template <typename ElfInterfaceType>
-void ElfInterfaceTest::SonameSize() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
-
- ASSERT_EQ("", elf->GetSoname());
-}
-
-TEST_F(ElfInterfaceTest, soname_size_32) {
- SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_DTSIZE_SMALL);
- SonameSize<ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, soname_size_64) {
- SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_DTSIZE_SMALL);
- SonameSize<ElfInterface64>();
-}
-
-// Verify that there is no map from STRTAB in the dynamic section to a
-// STRTAB entry in the section headers.
-template <typename ElfInterfaceType>
-void ElfInterfaceTest::SonameMissingMap() {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
-
- ASSERT_EQ("", elf->GetSoname());
-}
-
-TEST_F(ElfInterfaceTest, soname_missing_map_32) {
- SonameInit<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Dyn>(SONAME_MISSING_MAP);
- SonameMissingMap<ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, soname_missing_map_64) {
- SonameInit<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Dyn>(SONAME_MISSING_MAP);
- SonameMissingMap<ElfInterface64>();
-}
-
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersEhFrameTest() {
- ElfType elf(&memory_);
-
- elf.FakeSetEhFrameOffset(0x10000);
- elf.FakeSetEhFrameSize(0);
- elf.FakeSetDebugFrameOffset(0);
- elf.FakeSetDebugFrameSize(0);
-
- memory_.SetMemory(0x10000,
- std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata2, DW_EH_PE_udata2});
- memory_.SetData32(0x10004, 0x500);
- memory_.SetData32(0x10008, 250);
-
- elf.InitHeaders();
-
- EXPECT_FALSE(elf.eh_frame() == nullptr);
- EXPECT_TRUE(elf.debug_frame() == nullptr);
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame_32) {
- InitHeadersEhFrameTest<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame_64) {
- InitHeadersEhFrameTest<ElfInterface64Fake>();
-}
-
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersDebugFrame() {
- ElfType elf(&memory_);
-
- elf.FakeSetEhFrameOffset(0);
- elf.FakeSetEhFrameSize(0);
- elf.FakeSetDebugFrameOffset(0x5000);
- elf.FakeSetDebugFrameSize(0x200);
-
- memory_.SetData32(0x5000, 0xfc);
- memory_.SetData32(0x5004, 0xffffffff);
- memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 4, 8, 2});
-
- memory_.SetData32(0x5100, 0xfc);
- memory_.SetData32(0x5104, 0);
- memory_.SetData32(0x5108, 0x1500);
- memory_.SetData32(0x510c, 0x200);
-
- elf.InitHeaders();
-
- EXPECT_TRUE(elf.eh_frame() == nullptr);
- EXPECT_FALSE(elf.debug_frame() == nullptr);
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame_32) {
- InitHeadersDebugFrame<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame_64) {
- InitHeadersDebugFrame<ElfInterface64Fake>();
-}
-
-template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
-void ElfInterfaceTest::InitProgramHeadersMalformed() {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 3;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
-}
-
-TEST_F(ElfInterfaceTest, init_program_headers_malformed_32) {
- InitProgramHeadersMalformed<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, init_program_headers_malformed_64) {
- InitProgramHeadersMalformed<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
-void ElfInterfaceTest::InitSectionHeadersMalformed() {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_shoff = 0x1000;
- ehdr.e_shnum = 10;
- ehdr.e_shentsize = sizeof(Shdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_malformed_32) {
- InitSectionHeadersMalformed<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_malformed_64) {
- InitSectionHeadersMalformed<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
-void ElfInterfaceTest::InitSectionHeadersMalformedSymData() {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x1000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 5;
- ehdr.e_shentsize = sizeof(Shdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- Shdr shdr = {};
- shdr.sh_type = SHT_SYMTAB;
- shdr.sh_link = 4;
- shdr.sh_addr = 0x5000;
- shdr.sh_offset = 0x5000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = shdr.sh_entsize * 10;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_DYNSYM;
- shdr.sh_link = 10;
- shdr.sh_addr = 0x6000;
- shdr.sh_offset = 0x6000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = shdr.sh_entsize * 10;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_DYNSYM;
- shdr.sh_link = 2;
- shdr.sh_addr = 0x6000;
- shdr.sh_offset = 0x6000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = shdr.sh_entsize * 10;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for the entries.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_EQ(0U, elf->debug_frame_offset());
- EXPECT_EQ(0U, elf->debug_frame_size());
- EXPECT_EQ(0U, elf->gnu_debugdata_offset());
- EXPECT_EQ(0U, elf->gnu_debugdata_size());
-
- std::string name;
- uint64_t name_offset;
- ASSERT_FALSE(elf->GetFunctionName(0x90010, &name, &name_offset));
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata_32) {
- InitSectionHeadersMalformedSymData<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_malformed_symdata_64) {
- InitSectionHeadersMalformedSymData<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename Sym, typename ElfInterfaceType>
-void ElfInterfaceTest::InitSectionHeaders(uint64_t entry_size) {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x1000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 5;
- ehdr.e_shentsize = entry_size;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- Shdr shdr = {};
- shdr.sh_type = SHT_SYMTAB;
- shdr.sh_link = 4;
- shdr.sh_addr = 0x5000;
- shdr.sh_offset = 0x5000;
- shdr.sh_entsize = sizeof(Sym);
- shdr.sh_size = shdr.sh_entsize * 10;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_DYNSYM;
- shdr.sh_link = 4;
- shdr.sh_addr = 0x6000;
- shdr.sh_offset = 0x6000;
- shdr.sh_entsize = sizeof(Sym);
- shdr.sh_size = shdr.sh_entsize * 10;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 0xa000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for the entries.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- InitSym<Sym>(0x5000, 0x90000, 0x1000, 0x100, 0xf000, "function_one");
- InitSym<Sym>(0x6000, 0xd0000, 0x1000, 0x300, 0xf000, "function_two");
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_EQ(0U, elf->debug_frame_offset());
- EXPECT_EQ(0U, elf->debug_frame_size());
- EXPECT_EQ(0U, elf->gnu_debugdata_offset());
- EXPECT_EQ(0U, elf->gnu_debugdata_size());
-
- // Look in the first symbol table.
- std::string name;
- uint64_t name_offset;
- ASSERT_TRUE(elf->GetFunctionName(0x90010, &name, &name_offset));
- EXPECT_EQ("function_one", name);
- EXPECT_EQ(16U, name_offset);
- ASSERT_TRUE(elf->GetFunctionName(0xd0020, &name, &name_offset));
- EXPECT_EQ("function_two", name);
- EXPECT_EQ(32U, name_offset);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_32) {
- InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(sizeof(Elf32_Shdr));
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_64) {
- InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(sizeof(Elf64_Shdr));
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size_32) {
- InitSectionHeaders<Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, ElfInterface32>(0x100);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_non_std_entry_size_64) {
- InitSectionHeaders<Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, ElfInterface64>(0x100);
-}
-
-template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
-void ElfInterfaceTest::InitSectionHeadersOffsets() {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 7;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- Shdr shdr = {};
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x200;
- shdr.sh_addr = 0x5000;
- shdr.sh_offset = 0x5000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x800;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x100;
- shdr.sh_addr = 0x6000;
- shdr.sh_offset = 0x6000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x500;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x300;
- shdr.sh_addr = 0x7000;
- shdr.sh_offset = 0x7000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x800;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x400;
- shdr.sh_addr = 0xa000;
- shdr.sh_offset = 0xa000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0xf00;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_NOTE;
- shdr.sh_name = 0x500;
- shdr.sh_addr = 0xb000;
- shdr.sh_offset = 0xb000;
- shdr.sh_size = 0xf00;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
- memory_.SetMemory(0xf200, ".gnu_debugdata", sizeof(".gnu_debugdata"));
- memory_.SetMemory(0xf300, ".eh_frame", sizeof(".eh_frame"));
- memory_.SetMemory(0xf400, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
- memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_EQ(0x6000U, elf->debug_frame_offset());
- EXPECT_EQ(0, elf->debug_frame_section_bias());
- EXPECT_EQ(0x500U, elf->debug_frame_size());
-
- EXPECT_EQ(0x5000U, elf->gnu_debugdata_offset());
- EXPECT_EQ(0x800U, elf->gnu_debugdata_size());
-
- EXPECT_EQ(0x7000U, elf->eh_frame_offset());
- EXPECT_EQ(0, elf->eh_frame_section_bias());
- EXPECT_EQ(0x800U, elf->eh_frame_size());
-
- EXPECT_EQ(0xa000U, elf->eh_frame_hdr_offset());
- EXPECT_EQ(0, elf->eh_frame_hdr_section_bias());
- EXPECT_EQ(0xf00U, elf->eh_frame_hdr_size());
-
- EXPECT_EQ(0xb000U, elf->gnu_build_id_offset());
- EXPECT_EQ(0xf00U, elf->gnu_build_id_size());
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_32) {
- InitSectionHeadersOffsets<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_64) {
- InitSectionHeadersOffsets<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
-void ElfInterfaceTest::InitSectionHeadersOffsetsEhFrameSectionBias(uint64_t addr, uint64_t offset,
- int64_t expected_bias) {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t elf_offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = elf_offset;
- ehdr.e_shnum = 4;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- elf_offset += ehdr.e_shentsize;
-
- Shdr shdr = {};
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x200;
- shdr.sh_addr = 0x8000;
- shdr.sh_offset = 0x8000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x800;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
- elf_offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
- elf_offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x100;
- shdr.sh_addr = addr;
- shdr.sh_offset = offset;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x500;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf100, ".eh_frame", sizeof(".eh_frame"));
- memory_.SetMemory(0xf200, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_EQ(offset, elf->eh_frame_offset());
- EXPECT_EQ(expected_bias, elf->eh_frame_section_bias());
- EXPECT_EQ(0x500U, elf->eh_frame_size());
-
- EXPECT_EQ(0x8000U, elf->eh_frame_hdr_offset());
- EXPECT_EQ(0, elf->eh_frame_hdr_section_bias());
- EXPECT_EQ(0x800U, elf->eh_frame_hdr_size());
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_zero_32) {
- InitSectionHeadersOffsetsEhFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(0x4000,
- 0x4000, 0);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_zero_64) {
- InitSectionHeadersOffsetsEhFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(0x6000,
- 0x6000, 0);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_positive_32) {
- InitSectionHeadersOffsetsEhFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
- 0x5000, 0x4000, 0x1000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_positive_64) {
- InitSectionHeadersOffsetsEhFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
- 0x6000, 0x4000, 0x2000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_negative_32) {
- InitSectionHeadersOffsetsEhFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
- 0x3000, 0x4000, -0x1000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_section_bias_negative_64) {
- InitSectionHeadersOffsetsEhFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
- 0x6000, 0x9000, -0x3000);
-}
-
-template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
-void ElfInterfaceTest::InitSectionHeadersOffsetsEhFrameHdrSectionBias(uint64_t addr,
- uint64_t offset,
- int64_t expected_bias) {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t elf_offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = elf_offset;
- ehdr.e_shnum = 4;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- elf_offset += ehdr.e_shentsize;
-
- Shdr shdr = {};
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x200;
- shdr.sh_addr = addr;
- shdr.sh_offset = offset;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x800;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
- elf_offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
- elf_offset += ehdr.e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x100;
- shdr.sh_addr = 0x5000;
- shdr.sh_offset = 0x5000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x500;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf100, ".eh_frame", sizeof(".eh_frame"));
- memory_.SetMemory(0xf200, ".eh_frame_hdr", sizeof(".eh_frame_hdr"));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_EQ(0x5000U, elf->eh_frame_offset());
- EXPECT_EQ(0, elf->eh_frame_section_bias());
- EXPECT_EQ(0x500U, elf->eh_frame_size());
- EXPECT_EQ(offset, elf->eh_frame_hdr_offset());
- EXPECT_EQ(expected_bias, elf->eh_frame_hdr_section_bias());
- EXPECT_EQ(0x800U, elf->eh_frame_hdr_size());
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_zero_32) {
- InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(0x9000,
- 0x9000, 0);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_zero_64) {
- InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(0xa000,
- 0xa000, 0);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_positive_32) {
- InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
- 0x9000, 0x4000, 0x5000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_positive_64) {
- InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
- 0x6000, 0x1000, 0x5000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_negative_32) {
- InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
- 0x3000, 0x5000, -0x2000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_eh_frame_hdr_section_bias_negative_64) {
- InitSectionHeadersOffsetsEhFrameHdrSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
- 0x5000, 0x9000, -0x4000);
-}
-
-template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
-void ElfInterfaceTest::InitSectionHeadersOffsetsDebugFrameSectionBias(uint64_t addr,
- uint64_t offset,
- int64_t expected_bias) {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t elf_offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = elf_offset;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- elf_offset += ehdr.e_shentsize;
-
- Shdr shdr = {};
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_link = 2;
- shdr.sh_name = 0x100;
- shdr.sh_addr = addr;
- shdr.sh_offset = offset;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x800;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
- elf_offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(elf_offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf100, ".debug_frame", sizeof(".debug_frame"));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_EQ(offset, elf->debug_frame_offset());
- EXPECT_EQ(expected_bias, elf->debug_frame_section_bias());
- EXPECT_EQ(0x800U, elf->debug_frame_size());
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_zero_32) {
- InitSectionHeadersOffsetsDebugFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(0x5000,
- 0x5000, 0);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_zero_64) {
- InitSectionHeadersOffsetsDebugFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(0xa000,
- 0xa000, 0);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_positive_32) {
- InitSectionHeadersOffsetsDebugFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
- 0x5000, 0x2000, 0x3000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_positive_64) {
- InitSectionHeadersOffsetsDebugFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
- 0x7000, 0x1000, 0x6000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_negative_32) {
- InitSectionHeadersOffsetsDebugFrameSectionBias<Elf32_Ehdr, Elf32_Shdr, ElfInterface32>(
- 0x6000, 0x7000, -0x1000);
-}
-
-TEST_F(ElfInterfaceTest, init_section_headers_offsets_debug_frame_section_bias_negative_64) {
- InitSectionHeadersOffsetsDebugFrameSectionBias<Elf64_Ehdr, Elf64_Shdr, ElfInterface64>(
- 0x3000, 0x5000, -0x2000);
-}
-
-template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
-void ElfInterfaceTest::CheckGnuEhFrame(uint64_t addr, uint64_t offset, int64_t expected_bias) {
- std::unique_ptr<ElfInterface> elf(new ElfInterfaceType(&memory_));
-
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 2;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- uint64_t phdr_offset = 0x100;
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
- phdr_offset += sizeof(phdr);
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_GNU_EH_FRAME;
- phdr.p_vaddr = addr;
- phdr.p_offset = offset;
- memory_.SetMemory(phdr_offset, &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_EQ(expected_bias, elf->eh_frame_hdr_section_bias());
-}
-
-TEST_F(ElfInterfaceTest, eh_frame_zero_section_bias_32) {
- ElfInterfaceTest::CheckGnuEhFrame<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x4000, 0x4000, 0);
-}
-
-TEST_F(ElfInterfaceTest, eh_frame_zero_section_bias_64) {
- ElfInterfaceTest::CheckGnuEhFrame<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x4000, 0x4000, 0);
-}
-
-TEST_F(ElfInterfaceTest, eh_frame_positive_section_bias_32) {
- ElfInterfaceTest::CheckGnuEhFrame<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x4000, 0x1000, 0x3000);
-}
-
-TEST_F(ElfInterfaceTest, eh_frame_positive_section_bias_64) {
- ElfInterfaceTest::CheckGnuEhFrame<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x4000, 0x1000, 0x3000);
-}
-
-TEST_F(ElfInterfaceTest, eh_frame_negative_section_bias_32) {
- ElfInterfaceTest::CheckGnuEhFrame<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x4000, 0x5000,
- -0x1000);
-}
-
-TEST_F(ElfInterfaceTest, eh_frame_negative_section_bias_64) {
- ElfInterfaceTest::CheckGnuEhFrame<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x4000, 0x5000,
- -0x1000);
-}
-
-TEST_F(ElfInterfaceTest, is_valid_pc_from_pt_load) {
- std::unique_ptr<ElfInterface> elf(new ElfInterface32(&memory_));
-
- Elf32_Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 1;
- ehdr.e_phentsize = sizeof(Elf32_Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Elf32_Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_vaddr = 0;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0, load_bias);
- EXPECT_TRUE(elf->IsValidPc(0));
- EXPECT_TRUE(elf->IsValidPc(0x5000));
- EXPECT_TRUE(elf->IsValidPc(0xffff));
- EXPECT_FALSE(elf->IsValidPc(0x10000));
-}
-
-TEST_F(ElfInterfaceTest, is_valid_pc_from_pt_load_non_zero_load_bias) {
- std::unique_ptr<ElfInterface> elf(new ElfInterface32(&memory_));
-
- Elf32_Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 1;
- ehdr.e_phentsize = sizeof(Elf32_Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Elf32_Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_vaddr = 0x2000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- EXPECT_EQ(0x2000, load_bias);
- EXPECT_FALSE(elf->IsValidPc(0));
- EXPECT_FALSE(elf->IsValidPc(0x1000));
- EXPECT_FALSE(elf->IsValidPc(0x1fff));
- EXPECT_TRUE(elf->IsValidPc(0x2000));
- EXPECT_TRUE(elf->IsValidPc(0x5000));
- EXPECT_TRUE(elf->IsValidPc(0x11fff));
- EXPECT_FALSE(elf->IsValidPc(0x12000));
-}
-
-TEST_F(ElfInterfaceTest, is_valid_pc_from_debug_frame) {
- std::unique_ptr<ElfInterface> elf(new ElfInterface32(&memory_));
-
- uint64_t sh_offset = 0x100;
-
- Elf32_Ehdr ehdr = {};
- ehdr.e_shstrndx = 1;
- ehdr.e_shoff = sh_offset;
- ehdr.e_shentsize = sizeof(Elf32_Shdr);
- ehdr.e_shnum = 3;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Elf32_Shdr shdr = {};
- shdr.sh_type = SHT_NULL;
- memory_.SetMemory(sh_offset, &shdr, sizeof(shdr));
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 1;
- shdr.sh_offset = 0x500;
- shdr.sh_size = 0x100;
- memory_.SetMemory(sh_offset, &shdr, sizeof(shdr));
- memory_.SetMemory(0x500, ".debug_frame");
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 0;
- shdr.sh_addr = 0x600;
- shdr.sh_offset = 0x600;
- shdr.sh_size = 0x200;
- memory_.SetMemory(sh_offset, &shdr, sizeof(shdr));
-
- // CIE 32.
- memory_.SetData32(0x600, 0xfc);
- memory_.SetData32(0x604, 0xffffffff);
- memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
-
- // FDE 32.
- memory_.SetData32(0x700, 0xfc);
- memory_.SetData32(0x704, 0);
- memory_.SetData32(0x708, 0x2100);
- memory_.SetData32(0x70c, 0x200);
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- elf->InitHeaders();
- EXPECT_EQ(0, load_bias);
- EXPECT_FALSE(elf->IsValidPc(0));
- EXPECT_FALSE(elf->IsValidPc(0x20ff));
- EXPECT_TRUE(elf->IsValidPc(0x2100));
- EXPECT_TRUE(elf->IsValidPc(0x2200));
- EXPECT_TRUE(elf->IsValidPc(0x22ff));
- EXPECT_FALSE(elf->IsValidPc(0x2300));
-}
-
-TEST_F(ElfInterfaceTest, is_valid_pc_from_eh_frame) {
- std::unique_ptr<ElfInterface> elf(new ElfInterface32(&memory_));
-
- uint64_t sh_offset = 0x100;
-
- Elf32_Ehdr ehdr = {};
- ehdr.e_shstrndx = 1;
- ehdr.e_shoff = sh_offset;
- ehdr.e_shentsize = sizeof(Elf32_Shdr);
- ehdr.e_shnum = 3;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Elf32_Shdr shdr = {};
- shdr.sh_type = SHT_NULL;
- memory_.SetMemory(sh_offset, &shdr, sizeof(shdr));
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 1;
- shdr.sh_offset = 0x500;
- shdr.sh_size = 0x100;
- memory_.SetMemory(sh_offset, &shdr, sizeof(shdr));
- memory_.SetMemory(0x500, ".eh_frame");
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 0;
- shdr.sh_addr = 0x600;
- shdr.sh_offset = 0x600;
- shdr.sh_size = 0x200;
- memory_.SetMemory(sh_offset, &shdr, sizeof(shdr));
-
- // CIE 32.
- memory_.SetData32(0x600, 0xfc);
- memory_.SetData32(0x604, 0);
- memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
-
- // FDE 32.
- memory_.SetData32(0x700, 0xfc);
- memory_.SetData32(0x704, 0x104);
- memory_.SetData32(0x708, 0x20f8);
- memory_.SetData32(0x70c, 0x200);
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- elf->InitHeaders();
- EXPECT_EQ(0, load_bias);
- EXPECT_FALSE(elf->IsValidPc(0));
- EXPECT_FALSE(elf->IsValidPc(0x27ff));
- EXPECT_TRUE(elf->IsValidPc(0x2800));
- EXPECT_TRUE(elf->IsValidPc(0x2900));
- EXPECT_TRUE(elf->IsValidPc(0x29ff));
- EXPECT_FALSE(elf->IsValidPc(0x2a00));
-}
-
-template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
-void ElfInterfaceTest::BuildID() {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- char note_section[128];
- Nhdr note_header = {};
- note_header.n_namesz = 4; // "GNU"
- 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");
- // This part of the note does not contain any trailing '\0'.
- memcpy(¬e_section[note_offset], "BUILDID", 7);
-
- Shdr shdr = {};
- shdr.sh_type = SHT_NOTE;
- shdr.sh_name = 0x500;
- shdr.sh_offset = 0xb000;
- shdr.sh_size = sizeof(note_section);
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
- memory_.SetMemory(0xb000, note_section, sizeof(note_section));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- ASSERT_EQ("BUILDID", elf->GetBuildID());
-}
-
-TEST_F(ElfInterfaceTest, build_id_32) {
- BuildID<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_64) {
- BuildID<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
-void ElfInterfaceTest::BuildIDTwoNotes() {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- char note_section[128];
- Nhdr note_header = {};
- note_header.n_namesz = 8; // "WRONG" aligned to 4
- 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;
- // 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 = 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");
- // This part of the note does not contain any trailing '\0'.
- memcpy(¬e_section[note_offset], "BUILDID", 7);
-
- Shdr shdr = {};
- shdr.sh_type = SHT_NOTE;
- shdr.sh_name = 0x500;
- shdr.sh_offset = 0xb000;
- shdr.sh_size = sizeof(note_section);
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
- memory_.SetMemory(0xb000, note_section, sizeof(note_section));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- ASSERT_EQ("BUILDID", elf->GetBuildID());
-}
-
-TEST_F(ElfInterfaceTest, build_id_two_notes_32) {
- BuildIDTwoNotes<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_two_notes_64) {
- BuildIDTwoNotes<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
-void ElfInterfaceTest::BuildIDSectionTooSmallForName () {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- char note_section[128];
- Nhdr note_header = {};
- note_header.n_namesz = 4; // "GNU"
- 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");
- // This part of the note does not contain any trailing '\0'.
- memcpy(¬e_section[note_offset], "BUILDID", 7);
-
- Shdr shdr = {};
- shdr.sh_type = SHT_NOTE;
- shdr.sh_name = 0x500;
- shdr.sh_offset = 0xb000;
- shdr.sh_size = sizeof(note_header) + 1;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
- memory_.SetMemory(0xb000, note_section, sizeof(note_section));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- ASSERT_EQ("", elf->GetBuildID());
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name_32) {
- BuildIDSectionTooSmallForName<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_name_64) {
- BuildIDSectionTooSmallForName<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
-void ElfInterfaceTest::BuildIDSectionTooSmallForDesc () {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- char note_section[128];
- Nhdr note_header = {};
- note_header.n_namesz = 4; // "GNU"
- 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");
- // This part of the note does not contain any trailing '\0'.
- memcpy(¬e_section[note_offset], "BUILDID", 7);
-
- Shdr shdr = {};
- shdr.sh_type = SHT_NOTE;
- shdr.sh_name = 0x500;
- shdr.sh_offset = 0xb000;
- shdr.sh_size = sizeof(note_header) + sizeof("GNU") + 1;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
- memory_.SetMemory(0xb000, note_section, sizeof(note_section));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- ASSERT_EQ("", elf->GetBuildID());
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc_32) {
- BuildIDSectionTooSmallForDesc<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_desc_64) {
- BuildIDSectionTooSmallForDesc<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Shdr, typename Nhdr, typename ElfInterfaceType>
-void ElfInterfaceTest::BuildIDSectionTooSmallForHeader () {
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
-
- uint64_t offset = 0x2000;
-
- Ehdr ehdr = {};
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- offset += ehdr.e_shentsize;
-
- char note_section[128];
- Nhdr note_header = {};
- note_header.n_namesz = 4; // "GNU"
- 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");
- // This part of the note does not contain any trailing '\0'.
- memcpy(¬e_section[note_offset], "BUILDID", 7);
-
- Shdr shdr = {};
- shdr.sh_type = SHT_NOTE;
- shdr.sh_name = 0x500;
- shdr.sh_offset = 0xb000;
- shdr.sh_size = sizeof(note_header) - 1;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- memory_.SetMemory(offset, &shdr, sizeof(shdr));
-
- memory_.SetMemory(0xf500, ".note.gnu.build-id", sizeof(".note.gnu.build-id"));
- memory_.SetMemory(0xb000, note_section, sizeof(note_section));
-
- int64_t load_bias = 0;
- ASSERT_TRUE(elf->Init(&load_bias));
- ASSERT_EQ("", elf->GetBuildID());
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header_32) {
- BuildIDSectionTooSmallForHeader<Elf32_Ehdr, Elf32_Shdr, Elf32_Nhdr, ElfInterface32>();
-}
-
-TEST_F(ElfInterfaceTest, build_id_section_too_small_for_header_64) {
- BuildIDSectionTooSmallForHeader<Elf64_Ehdr, Elf64_Shdr, Elf64_Nhdr, ElfInterface64>();
-}
-
-template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
-void ElfInterfaceTest::CheckLoadBiasInFirstPhdr(int64_t load_bias) {
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 2;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0;
- phdr.p_vaddr = load_bias;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x1000;
- phdr.p_memsz = 0x2000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
-
- int64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
- ASSERT_EQ(load_bias, static_load_bias);
-
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
- int64_t init_load_bias = 0;
- ASSERT_TRUE(elf->Init(&init_load_bias));
- ASSERT_EQ(init_load_bias, static_load_bias);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_zero_32) {
- CheckLoadBiasInFirstPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_zero_64) {
- CheckLoadBiasInFirstPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_non_zero_32) {
- CheckLoadBiasInFirstPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x1000);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_non_zero_64) {
- CheckLoadBiasInFirstPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000);
-}
-
-template <typename Ehdr, typename Phdr, typename ElfInterfaceType>
-void ElfInterfaceTest::CheckLoadBiasInFirstExecPhdr(uint64_t offset, uint64_t vaddr,
- int64_t load_bias) {
- Ehdr ehdr = {};
- ehdr.e_phoff = 0x100;
- ehdr.e_phnum = 3;
- ehdr.e_phentsize = sizeof(Phdr);
- memory_.SetMemory(0, &ehdr, sizeof(ehdr));
-
- Phdr phdr = {};
- phdr.p_type = PT_LOAD;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100, &phdr, sizeof(phdr));
-
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = offset;
- phdr.p_vaddr = vaddr;
- phdr.p_memsz = 0x2000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
-
- // Second executable load should be ignored for load bias computation.
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_offset = 0x1234;
- phdr.p_vaddr = 0x2000;
- phdr.p_memsz = 0x2000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_.SetMemory(0x200 + sizeof(phdr), &phdr, sizeof(phdr));
-
- int64_t static_load_bias = ElfInterface::GetLoadBias<Ehdr, Phdr>(&memory_);
- ASSERT_EQ(load_bias, static_load_bias);
-
- std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
- int64_t init_load_bias = 0;
- ASSERT_TRUE(elf->Init(&init_load_bias));
- ASSERT_EQ(init_load_bias, static_load_bias);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_32) {
- CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x1000, 0x1000, 0);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_exec_zero_64) {
- CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000, 0x1000, 0);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_exec_positive_32) {
- CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x1000, 0x4000, 0x3000);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_exec_positive_64) {
- CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x1000, 0x4000, 0x3000);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_exec_negative_32) {
- CheckLoadBiasInFirstExecPhdr<Elf32_Ehdr, Elf32_Phdr, ElfInterface32>(0x5000, 0x1000, -0x4000);
-}
-
-TEST_F(ElfInterfaceTest, get_load_bias_exec_negative_64) {
- CheckLoadBiasInFirstExecPhdr<Elf64_Ehdr, Elf64_Phdr, ElfInterface64>(0x5000, 0x1000, -0x4000);
-}
-
-TEST_F(ElfInterfaceTest, huge_gnu_debugdata_size) {
- ElfInterfaceFake interface(nullptr);
-
- interface.FakeSetGnuDebugdataOffset(0x1000);
- interface.FakeSetGnuDebugdataSize(0xffffffffffffffffUL);
- ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
-
- interface.FakeSetGnuDebugdataSize(0x4000000000000UL);
- ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
-
- // This should exceed the size_t value of the first allocation.
-#if defined(__LP64__)
- interface.FakeSetGnuDebugdataSize(0x3333333333333334ULL);
-#else
- interface.FakeSetGnuDebugdataSize(0x33333334);
-#endif
- ASSERT_TRUE(interface.CreateGnuDebugdataMemory() == nullptr);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp
deleted file mode 100644
index f0852a4..0000000
--- a/libunwindstack/tests/ElfTest.cpp
+++ /dev/null
@@ -1,544 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/RegsArm.h>
-
-#include "ElfFake.h"
-#include "ElfTestUtils.h"
-#include "LogFake.h"
-#include "MemoryFake.h"
-
-#if !defined(PT_ARM_EXIDX)
-#define PT_ARM_EXIDX 0x70000001
-#endif
-
-namespace unwindstack {
-
-class ElfTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_ = new MemoryFake;
- }
-
- void InitElf32(uint32_t machine_type) {
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, machine_type);
-
- ehdr.e_phoff = 0x100;
- ehdr.e_ehsize = sizeof(ehdr);
- ehdr.e_phentsize = sizeof(Elf32_Phdr);
- ehdr.e_phnum = 1;
- ehdr.e_shentsize = sizeof(Elf32_Shdr);
- if (machine_type == EM_ARM) {
- ehdr.e_flags = 0x5000200;
- ehdr.e_phnum = 2;
- }
- memory_->SetMemory(0, &ehdr, sizeof(ehdr));
-
- Elf32_Phdr phdr;
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_filesz = 0x10000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_->SetMemory(0x100, &phdr, sizeof(phdr));
-
- if (machine_type == EM_ARM) {
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_ARM_EXIDX;
- phdr.p_offset = 0x30000;
- phdr.p_vaddr = 0x30000;
- phdr.p_paddr = 0x30000;
- phdr.p_filesz = 16;
- phdr.p_memsz = 16;
- phdr.p_flags = PF_R;
- phdr.p_align = 0x4;
- memory_->SetMemory(0x100 + sizeof(phdr), &phdr, sizeof(phdr));
- }
- }
-
- void InitElf64(uint32_t machine_type) {
- Elf64_Ehdr ehdr;
- TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, machine_type);
-
- ehdr.e_phoff = 0x100;
- ehdr.e_flags = 0x5000200;
- ehdr.e_ehsize = sizeof(ehdr);
- ehdr.e_phentsize = sizeof(Elf64_Phdr);
- ehdr.e_phnum = 1;
- ehdr.e_shentsize = sizeof(Elf64_Shdr);
- memory_->SetMemory(0, &ehdr, sizeof(ehdr));
-
- Elf64_Phdr phdr;
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_filesz = 0x10000;
- phdr.p_memsz = 0x10000;
- phdr.p_flags = PF_R | PF_X;
- phdr.p_align = 0x1000;
- memory_->SetMemory(0x100, &phdr, sizeof(phdr));
- }
-
- void VerifyStepIfSignalHandler(uint64_t load_bias);
-
- MemoryFake* memory_;
-};
-
-TEST_F(ElfTest, invalid_memory) {
- Elf elf(memory_);
-
- ASSERT_FALSE(elf.Init());
- ASSERT_FALSE(elf.valid());
-}
-
-TEST_F(ElfTest, elf_invalid) {
- Elf elf(memory_);
-
- InitElf32(EM_386);
-
- // Corrupt the ELF signature.
- memory_->SetData32(0, 0x7f000000);
-
- ASSERT_FALSE(elf.Init());
- ASSERT_FALSE(elf.valid());
- ASSERT_TRUE(elf.interface() == nullptr);
-
- ASSERT_EQ("", elf.GetSoname());
-
- std::string name;
- uint64_t func_offset;
- ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
-
- ASSERT_FALSE(elf.StepIfSignalHandler(0, nullptr, nullptr));
- EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
-
- bool finished;
- ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished));
- EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode());
-}
-
-TEST_F(ElfTest, elf32_invalid_machine) {
- Elf elf(memory_);
-
- InitElf32(EM_PPC);
-
- ResetLogs();
- ASSERT_FALSE(elf.Init());
-
- ASSERT_EQ("", GetFakeLogBuf());
- ASSERT_EQ("4 unwind 32 bit elf that is neither arm nor x86 nor mips: e_machine = 20\n\n",
- GetFakeLogPrint());
-}
-
-TEST_F(ElfTest, elf64_invalid_machine) {
- Elf elf(memory_);
-
- InitElf64(EM_PPC64);
-
- ResetLogs();
- ASSERT_FALSE(elf.Init());
-
- ASSERT_EQ("", GetFakeLogBuf());
- ASSERT_EQ("4 unwind 64 bit elf that is neither aarch64 nor x86_64 nor mips64: e_machine = 21\n\n",
- GetFakeLogPrint());
-}
-
-TEST_F(ElfTest, elf_arm) {
- Elf elf(memory_);
-
- InitElf32(EM_ARM);
-
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.valid());
- ASSERT_EQ(static_cast<uint32_t>(EM_ARM), elf.machine_type());
- ASSERT_EQ(ELFCLASS32, elf.class_type());
- ASSERT_TRUE(elf.interface() != nullptr);
-}
-
-TEST_F(ElfTest, elf_mips) {
- Elf elf(memory_);
-
- InitElf32(EM_MIPS);
-
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.valid());
- ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
- ASSERT_EQ(ELFCLASS32, elf.class_type());
- ASSERT_TRUE(elf.interface() != nullptr);
-}
-
-TEST_F(ElfTest, elf_x86) {
- Elf elf(memory_);
-
- InitElf32(EM_386);
-
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.valid());
- ASSERT_EQ(static_cast<uint32_t>(EM_386), elf.machine_type());
- ASSERT_EQ(ELFCLASS32, elf.class_type());
- ASSERT_TRUE(elf.interface() != nullptr);
-}
-
-TEST_F(ElfTest, elf_arm64) {
- Elf elf(memory_);
-
- InitElf64(EM_AARCH64);
-
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.valid());
- ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), elf.machine_type());
- ASSERT_EQ(ELFCLASS64, elf.class_type());
- ASSERT_TRUE(elf.interface() != nullptr);
-}
-
-TEST_F(ElfTest, elf_x86_64) {
- Elf elf(memory_);
-
- InitElf64(EM_X86_64);
-
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.valid());
- ASSERT_EQ(static_cast<uint32_t>(EM_X86_64), elf.machine_type());
- ASSERT_EQ(ELFCLASS64, elf.class_type());
- ASSERT_TRUE(elf.interface() != nullptr);
-}
-
-TEST_F(ElfTest, elf_mips64) {
- Elf elf(memory_);
-
- InitElf64(EM_MIPS);
-
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.valid());
- ASSERT_EQ(static_cast<uint32_t>(EM_MIPS), elf.machine_type());
- ASSERT_EQ(ELFCLASS64, elf.class_type());
- ASSERT_TRUE(elf.interface() != nullptr);
-}
-
-TEST_F(ElfTest, gnu_debugdata_init32) {
- TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(offset, ptr, size);
- });
-
- Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
- EXPECT_EQ(0x1acU, elf.interface()->gnu_debugdata_offset());
- EXPECT_EQ(0x8cU, elf.interface()->gnu_debugdata_size());
-}
-
-TEST_F(ElfTest, gnu_debugdata_init64) {
- TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(offset, ptr, size);
- });
-
- Elf elf(memory_);
- ASSERT_TRUE(elf.Init());
- ASSERT_TRUE(elf.interface() != nullptr);
- ASSERT_TRUE(elf.gnu_debugdata_interface() != nullptr);
- EXPECT_EQ(0x200U, elf.interface()->gnu_debugdata_offset());
- EXPECT_EQ(0x90U, elf.interface()->gnu_debugdata_size());
-}
-
-TEST_F(ElfTest, rel_pc) {
- ElfFake elf(memory_);
-
- ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
- elf.FakeSetInterface(interface);
-
- elf.FakeSetValid(true);
- MapInfo map_info(nullptr, nullptr, 0x1000, 0x2000, 0, 0, "");
-
- ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
-
- elf.FakeSetValid(false);
- ASSERT_EQ(0x101U, elf.GetRelPc(0x1101, &map_info));
-}
-
-void ElfTest::VerifyStepIfSignalHandler(uint64_t load_bias) {
- ElfFake elf(memory_);
-
- RegsArm regs;
- regs[13] = 0x50000;
- regs[15] = 0x8000;
-
- ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
- elf.FakeSetInterface(interface);
- elf.FakeSetLoadBias(load_bias);
-
- memory_->SetData32(0x3000, 0xdf0027ad);
- MemoryFake process_memory;
- process_memory.SetData32(0x50000, 0);
- for (size_t i = 0; i < 16; i++) {
- process_memory.SetData32(0x500a0 + i * sizeof(uint32_t), i);
- }
-
- elf.FakeSetValid(true);
- ASSERT_TRUE(elf.StepIfSignalHandler(0x3000 + load_bias, ®s, &process_memory));
- EXPECT_EQ(ERROR_NONE, elf.GetLastErrorCode());
- EXPECT_EQ(15U, regs.pc());
- EXPECT_EQ(13U, regs.sp());
-}
-
-TEST_F(ElfTest, step_in_signal_map) {
- VerifyStepIfSignalHandler(0);
-}
-
-TEST_F(ElfTest, step_in_signal_map_non_zero_load_bias) {
- VerifyStepIfSignalHandler(0x1000);
-}
-
-class ElfInterfaceMock : public ElfInterface {
- public:
- ElfInterfaceMock(Memory* memory) : ElfInterface(memory) {}
- virtual ~ElfInterfaceMock() = default;
-
- bool Init(int64_t*) override { return false; }
- void InitHeaders() override {}
- std::string GetSoname() override { return ""; }
- bool GetFunctionName(uint64_t, std::string*, uint64_t*) override { return false; }
- std::string GetBuildID() override { return ""; }
-
- MOCK_METHOD(bool, Step, (uint64_t, Regs*, Memory*, bool*), (override));
- MOCK_METHOD(bool, GetGlobalVariable, (const std::string&, uint64_t*), (override));
- MOCK_METHOD(bool, IsValidPc, (uint64_t), (override));
-
- void MockSetDataOffset(uint64_t offset) { data_offset_ = offset; }
- void MockSetDataVaddrStart(uint64_t vaddr) { data_vaddr_start_ = vaddr; }
- void MockSetDataVaddrEnd(uint64_t vaddr) { data_vaddr_end_ = vaddr; }
-
- void MockSetDynamicOffset(uint64_t offset) { dynamic_offset_ = offset; }
- void MockSetDynamicVaddrStart(uint64_t vaddr) { dynamic_vaddr_start_ = vaddr; }
- void MockSetDynamicVaddrEnd(uint64_t vaddr) { dynamic_vaddr_end_ = vaddr; }
-};
-
-TEST_F(ElfTest, step_in_interface) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
-
- RegsArm regs;
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
- MemoryFake process_memory;
-
- bool finished;
- EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished))
- .WillOnce(::testing::Return(true));
-
- ASSERT_TRUE(elf.Step(0x1000, ®s, &process_memory, &finished));
-}
-
-TEST_F(ElfTest, get_global_invalid_elf) {
- ElfFake elf(memory_);
- elf.FakeSetValid(false);
-
- std::string global("something");
- uint64_t offset;
- ASSERT_FALSE(elf.GetGlobalVariableOffset(global, &offset));
-}
-
-TEST_F(ElfTest, get_global_valid_not_in_interface) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
-
- std::string global("something");
- EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
- .WillOnce(::testing::Return(false));
-
- uint64_t offset;
- ASSERT_FALSE(elf.GetGlobalVariableOffset(global, &offset));
-}
-
-TEST_F(ElfTest, get_global_vaddr_in_no_sections) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
-
- std::string global("something");
- EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
- .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x300), ::testing::Return(true)));
-
- uint64_t offset;
- ASSERT_FALSE(elf.GetGlobalVariableOffset(global, &offset));
-}
-
-TEST_F(ElfTest, get_global_vaddr_in_data_section) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
- interface->MockSetDataVaddrStart(0x500);
- interface->MockSetDataVaddrEnd(0x600);
- interface->MockSetDataOffset(0xa000);
-
- std::string global("something");
- EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
- .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x580), ::testing::Return(true)));
-
- uint64_t offset;
- ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset));
- EXPECT_EQ(0xa080U, offset);
-}
-
-TEST_F(ElfTest, get_global_vaddr_in_dynamic_section) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
- interface->MockSetDataVaddrStart(0x500);
- interface->MockSetDataVaddrEnd(0x600);
- interface->MockSetDataOffset(0xa000);
-
- interface->MockSetDynamicVaddrStart(0x800);
- interface->MockSetDynamicVaddrEnd(0x900);
- interface->MockSetDynamicOffset(0xc000);
-
- std::string global("something");
- EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
- .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x880), ::testing::Return(true)));
-
- uint64_t offset;
- ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset));
- EXPECT_EQ(0xc080U, offset);
-}
-
-TEST_F(ElfTest, get_global_vaddr_with_tagged_pointer) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
- elf.FakeSetArch(ARCH_ARM64);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
- interface->MockSetDataVaddrStart(0x500);
- interface->MockSetDataVaddrEnd(0x600);
- interface->MockSetDataOffset(0xa000);
-
- std::string global("something");
- EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
- .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x8800000000000580),
- ::testing::Return(true)));
-
- uint64_t offset;
- ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset));
- EXPECT_EQ(0xa080U, offset);
-}
-
-TEST_F(ElfTest, get_global_vaddr_without_tagged_pointer) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
- elf.FakeSetArch(ARCH_X86_64);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
- interface->MockSetDataVaddrStart(0x8800000000000500);
- interface->MockSetDataVaddrEnd(0x8800000000000600);
- interface->MockSetDataOffset(0x880000000000a000);
-
- std::string global("something");
- EXPECT_CALL(*interface, GetGlobalVariable(global, ::testing::_))
- .WillOnce(::testing::DoAll(::testing::SetArgPointee<1>(0x8800000000000580),
- ::testing::Return(true)));
-
- uint64_t offset;
- ASSERT_TRUE(elf.GetGlobalVariableOffset(global, &offset));
- EXPECT_EQ(0x880000000000a080U, offset);
-}
-
-TEST_F(ElfTest, is_valid_pc_elf_invalid) {
- ElfFake elf(memory_);
- elf.FakeSetValid(false);
-
- EXPECT_FALSE(elf.IsValidPc(0x100));
- EXPECT_FALSE(elf.IsValidPc(0x200));
-}
-
-TEST_F(ElfTest, is_valid_pc_interface) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
-
- EXPECT_CALL(*interface, IsValidPc(0x1500)).WillOnce(::testing::Return(true));
-
- EXPECT_TRUE(elf.IsValidPc(0x1500));
-}
-
-TEST_F(ElfTest, is_valid_pc_from_gnu_debugdata) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
-
- ElfInterfaceMock* interface = new ElfInterfaceMock(memory_);
- elf.FakeSetInterface(interface);
- ElfInterfaceMock* gnu_interface = new ElfInterfaceMock(memory_);
- elf.FakeSetGnuDebugdataInterface(gnu_interface);
-
- EXPECT_CALL(*interface, IsValidPc(0x1500)).WillOnce(::testing::Return(false));
- EXPECT_CALL(*gnu_interface, IsValidPc(0x1500)).WillOnce(::testing::Return(true));
-
- EXPECT_TRUE(elf.IsValidPc(0x1500));
-}
-
-TEST_F(ElfTest, error_code_not_valid) {
- ElfFake elf(memory_);
- elf.FakeSetValid(false);
-
- ErrorData error{ERROR_MEMORY_INVALID, 0x100};
- elf.GetLastError(&error);
- EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
- EXPECT_EQ(0x100U, error.address);
-}
-
-TEST_F(ElfTest, error_code_valid) {
- ElfFake elf(memory_);
- elf.FakeSetValid(true);
- ElfInterfaceFake* interface = new ElfInterfaceFake(memory_);
- elf.FakeSetInterface(interface);
- interface->FakeSetErrorCode(ERROR_MEMORY_INVALID);
- interface->FakeSetErrorAddress(0x1000);
-
- ErrorData error{ERROR_NONE, 0};
- elf.GetLastError(&error);
- EXPECT_EQ(ERROR_MEMORY_INVALID, error.code);
- EXPECT_EQ(0x1000U, error.address);
- EXPECT_EQ(ERROR_MEMORY_INVALID, elf.GetLastErrorCode());
- EXPECT_EQ(0x1000U, elf.GetLastErrorAddress());
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.cpp b/libunwindstack/tests/ElfTestUtils.cpp
deleted file mode 100644
index 69163ac..0000000
--- a/libunwindstack/tests/ElfTestUtils.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "ElfTestUtils.h"
-
-namespace unwindstack {
-
-template <typename Ehdr>
-void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) {
- memset(ehdr, 0, sizeof(Ehdr));
- memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
- ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
- ehdr->e_ident[EI_VERSION] = EV_CURRENT;
- ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
- ehdr->e_ident[EI_CLASS] = elf_class;
- ehdr->e_type = ET_DYN;
- ehdr->e_machine = machine_type;
- ehdr->e_version = EV_CURRENT;
- ehdr->e_ehsize = sizeof(Ehdr);
-}
-
-std::string TestGetFileDirectory() {
- std::string exec(testing::internal::GetArgvs()[0]);
- auto const value = exec.find_last_of('/');
- if (value == std::string::npos) {
- return "tests/files/";
- }
- return exec.substr(0, value + 1) + "tests/files/";
-}
-
-template <typename Ehdr, typename Shdr>
-void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine, bool init_gnu_debugdata,
- TestCopyFuncType copy_func) {
- Ehdr ehdr;
-
- TestInitEhdr(&ehdr, elf_class, machine);
-
- uint64_t offset = sizeof(Ehdr);
- ehdr.e_shoff = offset;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Shdr);
- ehdr.e_shstrndx = 2;
- copy_func(0, &ehdr, sizeof(ehdr));
-
- Shdr shdr;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_NULL;
- copy_func(offset, &shdr, sizeof(shdr));
- offset += ehdr.e_shentsize;
-
- // Skip this header, it will contain the gnu_debugdata information.
- uint64_t gnu_offset = offset;
- offset += ehdr.e_shentsize;
-
- uint64_t symtab_offset = sizeof(ehdr) + ehdr.e_shnum * ehdr.e_shentsize;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_name = 1;
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_offset = symtab_offset;
- shdr.sh_size = 0x100;
- copy_func(offset, &shdr, sizeof(shdr));
-
- char value = '\0';
- uint64_t symname_offset = symtab_offset;
- copy_func(symname_offset, &value, 1);
- symname_offset++;
- std::string name(".shstrtab");
- copy_func(symname_offset, name.c_str(), name.size() + 1);
- symname_offset += name.size() + 1;
- name = ".gnu_debugdata";
- copy_func(symname_offset, name.c_str(), name.size() + 1);
-
- ssize_t bytes = 0x100;
- offset = symtab_offset + 0x100;
- if (init_gnu_debugdata) {
- // Read in the compressed elf data and copy it in.
- name = TestGetFileDirectory();
- if (elf_class == ELFCLASS32) {
- name += "elf32.xz";
- } else {
- name += "elf64.xz";
- }
- int fd = TEMP_FAILURE_RETRY(open(name.c_str(), O_RDONLY));
- ASSERT_NE(-1, fd) << "Cannot open " + name;
- // Assumes the file is less than 1024 bytes.
- std::vector<uint8_t> buf(1024);
- bytes = TEMP_FAILURE_RETRY(read(fd, buf.data(), buf.size()));
- ASSERT_GT(bytes, 0);
- // Make sure the file isn't too big.
- ASSERT_NE(static_cast<size_t>(bytes), buf.size())
- << "File " + name + " is too big, increase buffer size.";
- close(fd);
- buf.resize(bytes);
- copy_func(offset, buf.data(), buf.size());
- }
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = symname_offset - symtab_offset;
- shdr.sh_addr = offset;
- shdr.sh_offset = offset;
- shdr.sh_size = bytes;
- copy_func(gnu_offset, &shdr, sizeof(shdr));
-}
-
-template void TestInitEhdr<Elf32_Ehdr>(Elf32_Ehdr*, uint32_t, uint32_t);
-template void TestInitEhdr<Elf64_Ehdr>(Elf64_Ehdr*, uint32_t, uint32_t);
-
-template void TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(uint32_t, uint32_t, bool,
- TestCopyFuncType);
-template void TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(uint32_t, uint32_t, bool,
- TestCopyFuncType);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfTestUtils.h b/libunwindstack/tests/ElfTestUtils.h
deleted file mode 100644
index 62cd59a..0000000
--- a/libunwindstack/tests/ElfTestUtils.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2017 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_TESTS_ELF_TEST_UTILS_H
-#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
-
-#include <functional>
-#include <string>
-
-namespace unwindstack {
-
-typedef std::function<void(uint64_t, const void*, size_t)> TestCopyFuncType;
-
-template <typename Ehdr>
-void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type);
-
-template <typename Ehdr, typename Shdr>
-void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
- TestCopyFuncType copy_func);
-
-std::string TestGetFileDirectory();
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
diff --git a/libunwindstack/tests/GenGnuDebugdata.cpp b/libunwindstack/tests/GenGnuDebugdata.cpp
deleted file mode 100644
index 2644582..0000000
--- a/libunwindstack/tests/GenGnuDebugdata.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#if !defined(EM_AARCH64)
-#define EM_AARCH64 183
-#endif
-
-template <typename Ehdr>
-void InitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine) {
- memset(ehdr, 0, sizeof(Ehdr));
- memcpy(&ehdr->e_ident[0], ELFMAG, SELFMAG);
- ehdr->e_ident[EI_DATA] = ELFDATA2LSB;
- ehdr->e_ident[EI_VERSION] = EV_CURRENT;
- ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
- ehdr->e_ident[EI_CLASS] = elf_class;
- ehdr->e_type = ET_DYN;
- ehdr->e_machine = machine;
- ehdr->e_version = EV_CURRENT;
- ehdr->e_ehsize = sizeof(Ehdr);
-}
-
-template <typename Ehdr, typename Shdr>
-void GenElf(Ehdr* ehdr, int fd) {
- uint64_t offset = sizeof(Ehdr);
- ehdr->e_shoff = offset;
- ehdr->e_shnum = 3;
- ehdr->e_shentsize = sizeof(Shdr);
- ehdr->e_shstrndx = 2;
- TEMP_FAILURE_RETRY(write(fd, ehdr, sizeof(Ehdr)));
-
- Shdr shdr;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_name = 0;
- shdr.sh_type = SHT_NULL;
- TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
- offset += ehdr->e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 11;
- shdr.sh_addr = 0x5000;
- shdr.sh_offset = 0x5000;
- shdr.sh_entsize = 0x100;
- shdr.sh_size = 0x800;
- TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
- offset += ehdr->e_shentsize;
-
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 1;
- shdr.sh_offset = 0x200;
- shdr.sh_size = 24;
- TEMP_FAILURE_RETRY(write(fd, &shdr, sizeof(Shdr)));
-
- // Write out the name entries information.
- lseek(fd, 0x200, SEEK_SET);
- std::string name;
- TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
- name = ".shstrtab";
- TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
- name = ".debug_frame";
- TEMP_FAILURE_RETRY(write(fd, name.data(), name.size() + 1));
-}
-
-int main() {
- int elf32_fd = TEMP_FAILURE_RETRY(open("elf32", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
- if (elf32_fd == -1) {
- printf("Failed to create elf32: %s\n", strerror(errno));
- return 1;
- }
-
- int elf64_fd = TEMP_FAILURE_RETRY(open("elf64", O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0644));
- if (elf64_fd == -1) {
- printf("Failed to create elf64: %s\n", strerror(errno));
- return 1;
- }
-
- Elf32_Ehdr ehdr32;
- InitEhdr<Elf32_Ehdr>(&ehdr32, ELFCLASS32, EM_ARM);
- GenElf<Elf32_Ehdr, Elf32_Shdr>(&ehdr32, elf32_fd);
- close(elf32_fd);
-
- Elf64_Ehdr ehdr64;
- InitEhdr<Elf64_Ehdr>(&ehdr64, ELFCLASS64, EM_AARCH64);
- GenElf<Elf64_Ehdr, Elf64_Shdr>(&ehdr64, elf64_fd);
- close(elf64_fd);
-}
diff --git a/libunwindstack/tests/IsolatedSettings.cpp b/libunwindstack/tests/IsolatedSettings.cpp
deleted file mode 100644
index dbd8bd6..0000000
--- a/libunwindstack/tests/IsolatedSettings.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdint.h>
-#include <stdio.h>
-
-extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
- static const char* initial_args[2] = {"--slow_threshold_ms=90000",
- "--deadline_threshold_ms=120000"};
- *args = initial_args;
- *num_args = 2;
- return true;
-}
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
deleted file mode 100644
index 9b32a3a..0000000
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * 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 <elf.h>
-#include <string.h>
-
-#include <memory>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-#include "ElfFake.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class JitDebugTest : public ::testing::Test {
- protected:
- void CreateFakeElf(MapInfo* map_info, uint64_t global_offset, uint64_t data_offset,
- uint64_t data_vaddr, uint64_t data_size) {
- MemoryFake* memory = new MemoryFake;
- ElfFake* elf = new ElfFake(memory);
- elf->FakeSetValid(true);
- ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
- elf->FakeSetInterface(interface);
- interface->FakeSetGlobalVariable("__jit_debug_descriptor", global_offset);
- interface->FakeSetDataOffset(data_offset);
- interface->FakeSetDataVaddrStart(data_vaddr);
- interface->FakeSetDataVaddrEnd(data_vaddr + data_size);
- map_info->elf.reset(elf);
- }
-
- void Init(ArchEnum arch) {
- 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"
- "4000-6000 r--s 00000000 00:00 0 /fake/elf1\n"
- "6000-8000 -wxs 00002000 00:00 0 /fake/elf1\n"
- "a000-c000 --xp 00000000 00:00 0 /fake/elf2\n"
- "c000-f000 rw-p 00002000 00:00 0 /fake/elf2\n"
- "f000-11000 r--p 00000000 00:00 0 /fake/elf3\n"
- "11000-12000 rw-p 00002000 00:00 0 /fake/elf3\n"
- "12000-14000 r--p 00000000 00:00 0 /fake/elf4\n"
- "100000-110000 rw-p 00ee000 00:00 0 /fake/elf4\n"
- "200000-210000 rw-p 01ee000 00:00 0 /fake/elf4\n"));
- ASSERT_TRUE(maps_->Parse());
-
- MapInfo* map_info = maps_->Get(3);
- ASSERT_TRUE(map_info != nullptr);
- CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
-
- map_info = maps_->Get(5);
- ASSERT_TRUE(map_info != nullptr);
- CreateFakeElf(map_info, 0x2800, 0x2000, 0x2000, 0x3000);
-
- map_info = maps_->Get(7);
- ASSERT_TRUE(map_info != nullptr);
- CreateFakeElf(map_info, 0xee800, 0xee000, 0xee000, 0x10000);
- }
-
- void SetUp() override {
- memory_ = new MemoryFake;
- process_memory_.reset(memory_);
-
- Init(ARCH_ARM);
- }
-
- template <typename EhdrType, typename ShdrType>
- void CreateElf(uint64_t offset, uint8_t class_type, uint8_t machine_type, uint32_t pc,
- uint32_t size) {
- EhdrType ehdr;
- memset(&ehdr, 0, sizeof(ehdr));
- uint64_t sh_offset = sizeof(ehdr);
- memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
- ehdr.e_ident[EI_CLASS] = class_type;
- ehdr.e_machine = machine_type;
- ehdr.e_shstrndx = 1;
- ehdr.e_shoff = sh_offset;
- ehdr.e_shentsize = sizeof(ShdrType);
- ehdr.e_shnum = 3;
- memory_->SetMemory(offset, &ehdr, sizeof(ehdr));
-
- ShdrType shdr;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_NULL;
- memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 1;
- shdr.sh_offset = 0x500;
- shdr.sh_size = 0x100;
- memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
- memory_->SetMemory(offset + 0x500, ".debug_frame");
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 0;
- shdr.sh_addr = 0x600;
- shdr.sh_offset = 0x600;
- shdr.sh_size = 0x200;
- memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
-
- // Now add a single cie/fde.
- uint64_t dwarf_offset = offset + 0x600;
- if (class_type == ELFCLASS32) {
- // CIE 32 information.
- memory_->SetData32(dwarf_offset, 0xfc);
- memory_->SetData32(dwarf_offset + 0x4, 0xffffffff);
- memory_->SetData8(dwarf_offset + 0x8, 1);
- memory_->SetData8(dwarf_offset + 0x9, '\0');
- memory_->SetData8(dwarf_offset + 0xa, 0x4);
- memory_->SetData8(dwarf_offset + 0xb, 0x4);
- memory_->SetData8(dwarf_offset + 0xc, 0x1);
-
- // FDE 32 information.
- memory_->SetData32(dwarf_offset + 0x100, 0xfc);
- memory_->SetData32(dwarf_offset + 0x104, 0);
- memory_->SetData32(dwarf_offset + 0x108, pc);
- memory_->SetData32(dwarf_offset + 0x10c, size);
- } else {
- // CIE 64 information.
- memory_->SetData32(dwarf_offset, 0xffffffff);
- memory_->SetData64(dwarf_offset + 4, 0xf4);
- memory_->SetData64(dwarf_offset + 0xc, 0xffffffffffffffffULL);
- memory_->SetData8(dwarf_offset + 0x14, 1);
- memory_->SetData8(dwarf_offset + 0x15, '\0');
- memory_->SetData8(dwarf_offset + 0x16, 0x4);
- memory_->SetData8(dwarf_offset + 0x17, 0x4);
- memory_->SetData8(dwarf_offset + 0x18, 0x1);
-
- // FDE 64 information.
- memory_->SetData32(dwarf_offset + 0x100, 0xffffffff);
- memory_->SetData64(dwarf_offset + 0x104, 0xf4);
- memory_->SetData64(dwarf_offset + 0x10c, 0);
- memory_->SetData64(dwarf_offset + 0x114, pc);
- memory_->SetData64(dwarf_offset + 0x11c, size);
- }
- }
-
- void WriteDescriptor32(uint64_t addr, uint32_t entry);
- void WriteDescriptor64(uint64_t addr, uint64_t entry);
- void WriteEntry32Pack(uint64_t addr, uint32_t prev, uint32_t next, uint32_t elf_addr,
- uint64_t elf_size);
- void WriteEntry32Pad(uint64_t addr, uint32_t prev, uint32_t next, uint32_t elf_addr,
- uint64_t elf_size);
- void WriteEntry64(uint64_t addr, uint64_t prev, uint64_t next, uint64_t elf_addr,
- uint64_t elf_size);
-
- std::shared_ptr<Memory> process_memory_;
- MemoryFake* memory_;
- std::unique_ptr<JitDebug> jit_debug_;
- std::unique_ptr<BufferMaps> maps_;
-};
-
-void JitDebugTest::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 JitDebugTest::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 JitDebugTest::WriteEntry32Pack(uint64_t addr, uint32_t prev, uint32_t next, uint32_t elf_addr,
- uint64_t elf_size) {
- // Format of the 32 bit JITCodeEntry structure:
- // uint32_t next
- memory_->SetData32(addr, next);
- // uint32_t prev
- memory_->SetData32(addr + 4, prev);
- // uint32_t symfile_addr
- memory_->SetData32(addr + 8, elf_addr);
- // uint64_t symfile_size
- memory_->SetData64(addr + 12, elf_size);
-}
-
-void JitDebugTest::WriteEntry32Pad(uint64_t addr, uint32_t prev, uint32_t next, uint32_t elf_addr,
- uint64_t elf_size) {
- // Format of the 32 bit JITCodeEntry structure:
- // uint32_t next
- memory_->SetData32(addr, next);
- // uint32_t prev
- memory_->SetData32(addr + 4, prev);
- // uint32_t symfile_addr
- memory_->SetData32(addr + 8, elf_addr);
- // uint32_t pad
- memory_->SetData32(addr + 12, 0);
- // uint64_t symfile_size
- memory_->SetData64(addr + 16, elf_size);
-}
-
-void JitDebugTest::WriteEntry64(uint64_t addr, uint64_t prev, uint64_t next, uint64_t elf_addr,
- uint64_t elf_size) {
- // Format of the 64 bit JITCodeEntry structure:
- // uint64_t next
- memory_->SetData64(addr, next);
- // uint64_t prev
- memory_->SetData64(addr + 8, prev);
- // uint64_t symfile_addr
- memory_->SetData64(addr + 16, elf_addr);
- // uint64_t symfile_size
- memory_->SetData64(addr + 24, elf_size);
-}
-
-TEST_F(JitDebugTest, get_elf_invalid) {
- 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_->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_->GetElf(maps_.get(), 0x1500);
- ASSERT_TRUE(elf == nullptr);
-}
-
-TEST_F(JitDebugTest, get_elf_no_valid_code_entry) {
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
-
- WriteDescriptor32(0x11800, 0x200000);
-
- Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
- ASSERT_TRUE(elf == nullptr);
-}
-
-TEST_F(JitDebugTest, get_elf_invalid_descriptor_first_entry) {
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
-
- WriteDescriptor32(0x11800, 0);
-
- Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
- ASSERT_TRUE(elf == nullptr);
-}
-
-TEST_F(JitDebugTest, get_elf_invalid_descriptor_version) {
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
-
- WriteDescriptor32(0x11800, 0x20000);
- // Set the version to an invalid value.
- memory_->SetData32(0x11800, 2);
-
- Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
- ASSERT_TRUE(elf == nullptr);
-}
-
-TEST_F(JitDebugTest, get_elf_32) {
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
-
- WriteDescriptor32(0x11800, 0x200000);
- WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
-
- 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();
- Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
- ASSERT_TRUE(elf2 != nullptr);
- EXPECT_EQ(elf, elf2);
-}
-
-TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) {
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x5000, ELFCLASS32, EM_ARM, 0x2000, 0x300);
-
- WriteDescriptor32(0x11800, 0x200000);
- WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
- WriteDescriptor32(0x100800, 0x201000);
- WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000);
-
- 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(0x11800, 0);
- jit_debug_.reset(new JitDebug(process_memory_));
- jit_debug_->SetArch(ARCH_ARM);
-
- ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
- ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr);
-}
-
-TEST_F(JitDebugTest, get_elf_x86) {
- Init(ARCH_X86);
-
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
-
- WriteDescriptor32(0x11800, 0x200000);
- WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000);
-
- 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();
- Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
- ASSERT_TRUE(elf2 != nullptr);
- EXPECT_EQ(elf, elf2);
-}
-
-TEST_F(JitDebugTest, get_elf_64) {
- Init(ARCH_ARM64);
-
- CreateElf<Elf64_Ehdr, Elf64_Shdr>(0x4000, ELFCLASS64, EM_AARCH64, 0x1500, 0x200);
-
- WriteDescriptor64(0x11800, 0x200000);
- WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000);
-
- 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();
- Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
- ASSERT_TRUE(elf2 != nullptr);
- EXPECT_EQ(elf, elf2);
-}
-
-TEST_F(JitDebugTest, get_elf_multiple_entries) {
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x5000, ELFCLASS32, EM_ARM, 0x2300, 0x400);
-
- WriteDescriptor32(0x11800, 0x200000);
- WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000);
- WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000);
-
- Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400);
- ASSERT_TRUE(elf_2 != nullptr);
-
- 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();
- 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) {
- CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
-
- WriteDescriptor32(0x11800, 0x200000);
- WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
-
- // Only search a given named list of libs.
- std::vector<std::string> libs{"libart.so"};
- 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_.reset(new JitDebug(process_memory_, libs));
- // Make sure that clearing our copy of the libs doesn't affect the
- // JitDebug object.
- libs.clear();
- jit_debug_->SetArch(ARCH_ARM);
- EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/LocalUnwinderTest.cpp b/libunwindstack/tests/LocalUnwinderTest.cpp
deleted file mode 100644
index 9936f7a..0000000
--- a/libunwindstack/tests/LocalUnwinderTest.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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 <dlfcn.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <android-base/stringprintf.h>
-
-#include <unwindstack/LocalUnwinder.h>
-
-namespace unwindstack {
-
-static std::vector<LocalFrameData>* g_frame_info;
-static LocalUnwinder* g_unwinder;
-
-extern "C" void SignalLocalInnerFunction() {
- g_unwinder->Unwind(g_frame_info, 256);
-}
-
-extern "C" void SignalLocalMiddleFunction() {
- SignalLocalInnerFunction();
-}
-
-extern "C" void SignalLocalOuterFunction() {
- SignalLocalMiddleFunction();
-}
-
-static void SignalLocalCallerHandler(int, siginfo_t*, void*) {
- SignalLocalOuterFunction();
-}
-
-static std::string ErrorMsg(const std::vector<const char*>& function_names,
- const std::vector<LocalFrameData>& frame_info) {
- std::string unwind;
- size_t i = 0;
- for (const auto& frame : frame_info) {
- unwind += android::base::StringPrintf("#%02zu pc 0x%" PRIx64 " rel_pc 0x%" PRIx64, i++,
- frame.pc, frame.rel_pc);
- if (frame.map_info != nullptr) {
- if (!frame.map_info->name.empty()) {
- unwind += " " + frame.map_info->name;
- } else {
- unwind += android::base::StringPrintf(" 0x%" PRIx64 "-0x%" PRIx64, frame.map_info->start,
- frame.map_info->end);
- }
- if (frame.map_info->offset != 0) {
- unwind += android::base::StringPrintf(" offset 0x%" PRIx64, frame.map_info->offset);
- }
- }
- if (!frame.function_name.empty()) {
- unwind += " " + frame.function_name;
- if (frame.function_offset != 0) {
- unwind += android::base::StringPrintf("+%" PRId64, frame.function_offset);
- }
- }
- unwind += '\n';
- }
-
- return std::string(
- "Unwind completed without finding all frames\n"
- " Looking for function: ") +
- function_names.front() + "\n" + "Unwind data:\n" + unwind;
-}
-
-// This test assumes that this code is compiled with optimizations turned
-// off. If this doesn't happen, then all of the calls will be optimized
-// away.
-extern "C" void LocalInnerFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
- std::vector<LocalFrameData> frame_info;
- g_frame_info = &frame_info;
- g_unwinder = unwinder;
- std::vector<const char*> expected_function_names;
-
- if (unwind_through_signal) {
- struct sigaction act, oldact;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = SignalLocalCallerHandler;
- act.sa_flags = SA_RESTART | SA_ONSTACK;
- ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
-
- raise(SIGUSR1);
-
- ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
-
- expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction",
- "LocalInnerFunction", "SignalLocalOuterFunction",
- "SignalLocalMiddleFunction", "SignalLocalInnerFunction"};
- } else {
- ASSERT_TRUE(unwinder->Unwind(&frame_info, 256));
-
- expected_function_names = {"LocalOuterFunction", "LocalMiddleFunction", "LocalInnerFunction"};
- }
-
- for (auto& frame : frame_info) {
- if (frame.function_name == expected_function_names.back()) {
- expected_function_names.pop_back();
- if (expected_function_names.empty()) {
- break;
- }
- }
- }
-
- ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info);
-}
-
-extern "C" void LocalMiddleFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
- LocalInnerFunction(unwinder, unwind_through_signal);
-}
-
-extern "C" void LocalOuterFunction(LocalUnwinder* unwinder, bool unwind_through_signal) {
- LocalMiddleFunction(unwinder, unwind_through_signal);
-}
-
-class LocalUnwinderTest : public ::testing::Test {
- protected:
- void SetUp() override {
- unwinder_.reset(new LocalUnwinder);
- ASSERT_TRUE(unwinder_->Init());
- }
-
- std::unique_ptr<LocalUnwinder> unwinder_;
-};
-
-TEST_F(LocalUnwinderTest, local) {
- LocalOuterFunction(unwinder_.get(), false);
-}
-
-TEST_F(LocalUnwinderTest, local_signal) {
- LocalOuterFunction(unwinder_.get(), true);
-}
-
-TEST_F(LocalUnwinderTest, local_multiple) {
- ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
-
- ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true));
-
- ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
-
- ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), true));
-}
-
-// This test verifies that doing an unwind before and after a dlopen
-// works. It's verifying that the maps read during the first unwind
-// do not cause a problem when doing the unwind using the code in
-// the dlopen'd code.
-TEST_F(LocalUnwinderTest, unwind_after_dlopen) {
- // Prime the maps data.
- ASSERT_NO_FATAL_FAILURE(LocalOuterFunction(unwinder_.get(), false));
-
- std::string testlib(testing::internal::GetArgvs()[0]);
- auto const value = testlib.find_last_of('/');
- if (value != std::string::npos) {
- testlib = testlib.substr(0, value + 1);
- } else {
- testlib = "";
- }
- testlib += "libunwindstack_local.so";
-
- void* handle = dlopen(testlib.c_str(), RTLD_NOW);
- ASSERT_TRUE(handle != nullptr);
-
- void (*unwind_function)(void*, void*) =
- reinterpret_cast<void (*)(void*, void*)>(dlsym(handle, "TestlibLevel1"));
- ASSERT_TRUE(unwind_function != nullptr);
-
- std::vector<LocalFrameData> frame_info;
- unwind_function(unwinder_.get(), &frame_info);
-
- ASSERT_EQ(0, dlclose(handle));
-
- std::vector<const char*> expected_function_names{"TestlibLevel1", "TestlibLevel2",
- "TestlibLevel3", "TestlibLevel4"};
-
- for (auto& frame : frame_info) {
- if (frame.function_name == expected_function_names.back()) {
- expected_function_names.pop_back();
- if (expected_function_names.empty()) {
- break;
- }
- }
- }
-
- ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, frame_info);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/LocalUpdatableMapsTest.cpp b/libunwindstack/tests/LocalUpdatableMapsTest.cpp
deleted file mode 100644
index 99afb0b..0000000
--- a/libunwindstack/tests/LocalUpdatableMapsTest.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-/*
- * 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 <stdint.h>
-#include <sys/mman.h>
-
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <android-base/file.h>
-#include <unwindstack/Maps.h>
-
-namespace unwindstack {
-
-class TestUpdatableMaps : public LocalUpdatableMaps {
- public:
- TestUpdatableMaps() : LocalUpdatableMaps() {}
- virtual ~TestUpdatableMaps() = default;
-
- const std::string GetMapsFile() const override { return maps_file_; }
-
- void TestSetMapsFile(const std::string& maps_file) { maps_file_ = maps_file; }
-
- const std::vector<std::unique_ptr<MapInfo>>& TestGetSavedMaps() { return saved_maps_; }
-
- private:
- std::string maps_file_;
-};
-
-class LocalUpdatableMapsTest : public ::testing::Test {
- protected:
- static const std::string GetDefaultMapString() {
- return "3000-4000 r-xp 00000 00:00 0\n8000-9000 r-xp 00000 00:00 0\n";
- }
-
- void SetUp() override {
- TemporaryFile tf;
- ASSERT_TRUE(android::base::WriteStringToFile(GetDefaultMapString(), tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Parse());
- ASSERT_EQ(2U, maps_.Total());
-
- MapInfo* map_info = maps_.Get(0);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = maps_.Get(1);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x8000U, map_info->start);
- EXPECT_EQ(0x9000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
- }
-
- TestUpdatableMaps maps_;
-};
-
-TEST_F(LocalUpdatableMapsTest, same_map) {
- TemporaryFile tf;
- ASSERT_TRUE(android::base::WriteStringToFile(GetDefaultMapString(), tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(2U, maps_.Total());
- EXPECT_EQ(0U, maps_.TestGetSavedMaps().size());
-
- MapInfo* map_info = maps_.Get(0);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = maps_.Get(1);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x8000U, map_info->start);
- EXPECT_EQ(0x9000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-}
-
-TEST_F(LocalUpdatableMapsTest, same_map_new_perms) {
- TemporaryFile tf;
- ASSERT_TRUE(
- android::base::WriteStringToFile("3000-4000 rwxp 00000 00:00 0\n"
- "8000-9000 r-xp 00000 00:00 0\n",
- tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(2U, maps_.Total());
-
- MapInfo* map_info = maps_.Get(0);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = maps_.Get(1);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x8000U, map_info->start);
- EXPECT_EQ(0x9000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- auto& saved_maps = maps_.TestGetSavedMaps();
- ASSERT_EQ(1U, saved_maps.size());
- map_info = saved_maps[0].get();
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-}
-
-TEST_F(LocalUpdatableMapsTest, same_map_new_name) {
- TemporaryFile tf;
- ASSERT_TRUE(
- android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
- "8000-9000 r-xp 00000 00:00 0\n",
- tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(2U, maps_.Total());
-
- MapInfo* map_info = maps_.Get(0);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_EQ("/fake/lib.so", map_info->name);
-
- map_info = maps_.Get(1);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x8000U, map_info->start);
- EXPECT_EQ(0x9000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- auto& saved_maps = maps_.TestGetSavedMaps();
- ASSERT_EQ(1U, saved_maps.size());
- map_info = saved_maps[0].get();
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-}
-
-TEST_F(LocalUpdatableMapsTest, only_add_maps) {
- TemporaryFile tf;
- ASSERT_TRUE(
- android::base::WriteStringToFile("1000-2000 r-xp 00000 00:00 0\n"
- "3000-4000 r-xp 00000 00:00 0\n"
- "8000-9000 r-xp 00000 00:00 0\n"
- "a000-f000 r-xp 00000 00:00 0\n",
- tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(4U, maps_.Total());
- EXPECT_EQ(0U, maps_.TestGetSavedMaps().size());
-
- MapInfo* map_info = maps_.Get(0);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x1000U, map_info->start);
- EXPECT_EQ(0x2000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = maps_.Get(1);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = maps_.Get(2);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x8000U, map_info->start);
- EXPECT_EQ(0x9000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = maps_.Get(3);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0xa000U, map_info->start);
- EXPECT_EQ(0xf000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-}
-
-TEST_F(LocalUpdatableMapsTest, all_new_maps) {
- TemporaryFile tf;
- ASSERT_TRUE(
- android::base::WriteStringToFile("1000-2000 r-xp 00000 00:00 0\n"
- "a000-f000 r-xp 00000 00:00 0\n",
- tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(2U, maps_.Total());
-
- MapInfo* map_info = maps_.Get(0);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x1000U, map_info->start);
- EXPECT_EQ(0x2000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = maps_.Get(1);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0xa000U, map_info->start);
- EXPECT_EQ(0xf000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- auto& saved_maps = maps_.TestGetSavedMaps();
- ASSERT_EQ(2U, saved_maps.size());
- map_info = saved_maps[0].get();
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x3000U, map_info->start);
- EXPECT_EQ(0x4000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-
- map_info = saved_maps[1].get();
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x8000U, map_info->start);
- EXPECT_EQ(0x9000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
-}
-
-TEST_F(LocalUpdatableMapsTest, add_map_prev_name_updated) {
- TemporaryFile tf;
- ASSERT_TRUE(
- android::base::WriteStringToFile("3000-4000 rwxp 00000 00:00 0\n"
- "8000-9000 r-xp 00000 00:00 0\n"
- "9000-a000 r-xp 00000 00:00 0\n",
- tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(3U, maps_.Total());
-
- MapInfo* map_info = maps_.Get(2);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x9000U, map_info->start);
- EXPECT_EQ(0xA000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_TRUE(map_info->name.empty());
- EXPECT_EQ(maps_.Get(1), map_info->prev_map);
-}
-
-TEST_F(LocalUpdatableMapsTest, add_map_prev_real_name_updated) {
- TemporaryFile tf;
- ASSERT_TRUE(
- android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
- "4000-5000 ---p 00000 00:00 0\n"
- "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
- "8000-9000 ---p 00000 00:00 0\n",
- tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(4U, maps_.Total());
-
- MapInfo* map_info = maps_.Get(2);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x7000U, map_info->start);
- EXPECT_EQ(0x8000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_EQ(maps_.Get(0), map_info->prev_real_map);
- EXPECT_EQ(maps_.Get(1), map_info->prev_map);
- EXPECT_EQ("/fake/lib1.so", map_info->name);
-
- map_info = maps_.Get(3);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x8000U, map_info->start);
- EXPECT_EQ(0x9000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_TRUE(map_info->IsBlank());
- EXPECT_EQ(maps_.Get(2), map_info->prev_real_map);
- EXPECT_EQ(maps_.Get(2), map_info->prev_map);
- EXPECT_TRUE(map_info->name.empty());
-
- ASSERT_TRUE(
- android::base::WriteStringToFile("3000-4000 r-xp 00000 00:00 0 /fake/lib.so\n"
- "4000-5000 ---p 00000 00:00 0\n"
- "7000-8000 r-xp 00000 00:00 0 /fake/lib1.so\n"
- "8000-9000 ---p 00000 00:00 0\n"
- "9000-a000 r-xp 00000 00:00 0 /fake/lib2.so\n"
- "a000-b000 r-xp 00000 00:00 0 /fake/lib3.so\n",
- tf.path));
-
- maps_.TestSetMapsFile(tf.path);
- ASSERT_TRUE(maps_.Reparse());
- ASSERT_EQ(6U, maps_.Total());
-
- map_info = maps_.Get(2);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x7000U, map_info->start);
- EXPECT_EQ(0x8000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_EQ("/fake/lib1.so", map_info->name);
- EXPECT_EQ(maps_.Get(1), map_info->prev_map);
- EXPECT_EQ(maps_.Get(0), map_info->prev_real_map);
-
- map_info = maps_.Get(4);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0x9000U, map_info->start);
- EXPECT_EQ(0xA000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_EQ("/fake/lib2.so", map_info->name);
- EXPECT_EQ(maps_.Get(3), map_info->prev_map);
- EXPECT_EQ(maps_.Get(2), map_info->prev_real_map);
-
- map_info = maps_.Get(5);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_EQ(0xA000U, map_info->start);
- EXPECT_EQ(0xB000U, map_info->end);
- EXPECT_EQ(0U, map_info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, map_info->flags);
- EXPECT_EQ("/fake/lib3.so", map_info->name);
- EXPECT_EQ(maps_.Get(4), map_info->prev_map);
- EXPECT_EQ(maps_.Get(4), map_info->prev_real_map);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/LogFake.cpp b/libunwindstack/tests/LogFake.cpp
deleted file mode 100644
index 537ccaf..0000000
--- a/libunwindstack/tests/LogFake.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2015 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 <errno.h>
-#include <stdarg.h>
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-
-#include "LogFake.h"
-
-// Forward declarations.
-struct EventTagMap;
-struct AndroidLogEntry;
-
-std::string g_fake_log_buf;
-
-std::string g_fake_log_print;
-
-namespace unwindstack {
-
-void ResetLogs() {
- g_fake_log_buf = "";
- g_fake_log_print = "";
-}
-
-std::string GetFakeLogBuf() {
- return g_fake_log_buf;
-}
-
-std::string GetFakeLogPrint() {
- return g_fake_log_print;
-}
-
-} // namespace unwindstack
-
-extern "C" int __android_log_buf_write(int bufId, int prio, const char* tag, const char* msg) {
- g_fake_log_buf += std::to_string(bufId) + ' ' + std::to_string(prio) + ' ';
- g_fake_log_buf += tag;
- g_fake_log_buf += ' ';
- g_fake_log_buf += msg;
- return 1;
-}
-
-extern "C" int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- int val = __android_log_vprint(prio, tag, fmt, ap);
- va_end(ap);
-
- return val;
-}
-
-extern "C" int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
- g_fake_log_print += std::to_string(prio) + ' ';
- g_fake_log_print += tag;
- g_fake_log_print += ' ';
-
- android::base::StringAppendV(&g_fake_log_print, fmt, ap);
-
- g_fake_log_print += '\n';
-
- return 1;
-}
-
-extern "C" log_id_t android_name_to_log_id(const char*) {
- return LOG_ID_SYSTEM;
-}
-
-extern "C" struct logger_list* android_logger_list_open(log_id_t, int, unsigned int, pid_t) {
- errno = EACCES;
- return nullptr;
-}
-
-extern "C" int android_logger_list_read(struct logger_list*, struct log_msg*) {
- return 0;
-}
-
-extern "C" EventTagMap* android_openEventTagMap(const char*) {
- return nullptr;
-}
-
-extern "C" int android_log_processBinaryLogBuffer(
- struct logger_entry*,
- AndroidLogEntry*, const EventTagMap*, char*, int) {
- return 0;
-}
-
-extern "C" void android_logger_list_free(struct logger_list*) {
-}
diff --git a/libunwindstack/tests/LogFake.h b/libunwindstack/tests/LogFake.h
deleted file mode 100644
index e1dc50d..0000000
--- a/libunwindstack/tests/LogFake.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2015 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_TESTS_LOG_FAKE_H
-#define _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
-
-#include <string>
-
-namespace unwindstack {
-
-void ResetLogs();
-std::string GetFakeLogBuf();
-std::string GetFakeLogPrint();
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_LOG_FAKE_H
diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
deleted file mode 100644
index 6d8d58e..0000000
--- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <memory>
-#include <vector>
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-#include "ElfTestUtils.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class MapInfoCreateMemoryTest : public ::testing::Test {
- protected:
- template <typename Ehdr, typename Shdr>
- static void InitElf(int fd, uint64_t file_offset, uint64_t sh_offset, uint8_t class_type) {
- std::vector<uint8_t> buffer(20000);
- memset(buffer.data(), 0, buffer.size());
-
- Ehdr ehdr;
- memset(&ehdr, 0, sizeof(ehdr));
- memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
- ehdr.e_ident[EI_CLASS] = class_type;
- ehdr.e_shoff = sh_offset;
- ehdr.e_shentsize = sizeof(Shdr) + 100;
- ehdr.e_shnum = 4;
- memcpy(&buffer[file_offset], &ehdr, sizeof(ehdr));
-
- ASSERT_TRUE(android::base::WriteFully(fd, buffer.data(), buffer.size()));
- }
-
- void SetUp() override {
- std::vector<uint8_t> buffer(12288, 0);
- memcpy(buffer.data(), ELFMAG, SELFMAG);
- buffer[EI_CLASS] = ELFCLASS32;
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), 1024));
-
- memset(buffer.data(), 0, buffer.size());
- memcpy(&buffer[0x1000], ELFMAG, SELFMAG);
- buffer[0x1000 + EI_CLASS] = ELFCLASS64;
- buffer[0x2000] = 0xff;
- ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, buffer.data(), buffer.size()));
-
- InitElf<Elf32_Ehdr, Elf32_Shdr>(elf32_at_map_.fd, 0x1000, 0x2000, ELFCLASS32);
- InitElf<Elf64_Ehdr, Elf64_Shdr>(elf64_at_map_.fd, 0x2000, 0x3000, ELFCLASS64);
-
- memory_ = new MemoryFake;
- process_memory_.reset(memory_);
- }
-
- MemoryFake* memory_;
- std::shared_ptr<Memory> process_memory_;
-
- TemporaryFile elf_;
-
- TemporaryFile elf_at_1000_;
-
- TemporaryFile elf32_at_map_;
- TemporaryFile elf64_at_map_;
-};
-
-TEST_F(MapInfoCreateMemoryTest, end_le_start) {
- MapInfo info(nullptr, nullptr, 0x100, 0x100, 0, 0, elf_.path);
-
- std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() == nullptr);
-
- info.end = 0xff;
- memory.reset(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() == nullptr);
-
- // Make sure this test is valid.
- info.end = 0x101;
- memory.reset(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
-}
-
-// Verify that if the offset is non-zero but there is no elf at the offset,
-// that the full file is used.
-TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) {
- MapInfo info(nullptr, nullptr, 0x100, 0x200, 0x100, 0, elf_.path);
-
- std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0x100U, info.elf_offset);
- EXPECT_EQ(0x100U, info.elf_start_offset);
-
- // Read the entire file.
- std::vector<uint8_t> buffer(1024);
- ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 1024));
- ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
- ASSERT_EQ(ELFCLASS32, buffer[EI_CLASS]);
- for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
- ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
- }
-
- ASSERT_FALSE(memory->ReadFully(1024, buffer.data(), 1));
-
- // Now verify the elf start offset is set correctly based on the previous
- // info.
- MapInfo prev_info(nullptr, nullptr, 0, 0x100, 0x10, 0, "");
- info.prev_map = &prev_info;
- info.prev_real_map = &prev_info;
-
- // No preconditions met, change each one until it should set the elf start
- // offset to zero.
- info.elf_offset = 0;
- info.elf_start_offset = 0;
- info.memory_backed_elf = false;
- memory.reset(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0x100U, info.elf_offset);
- EXPECT_EQ(0x100U, info.elf_start_offset);
-
- prev_info.offset = 0;
- info.elf_offset = 0;
- info.elf_start_offset = 0;
- info.memory_backed_elf = false;
- memory.reset(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0x100U, info.elf_offset);
- EXPECT_EQ(0x100U, info.elf_start_offset);
-
- prev_info.flags = PROT_READ;
- info.elf_offset = 0;
- info.elf_start_offset = 0;
- info.memory_backed_elf = false;
- memory.reset(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0x100U, info.elf_offset);
- EXPECT_EQ(0x100U, info.elf_start_offset);
-
- prev_info.name = info.name;
- info.elf_offset = 0;
- info.elf_start_offset = 0;
- info.memory_backed_elf = false;
- memory.reset(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0x100U, info.elf_offset);
- EXPECT_EQ(0U, info.elf_start_offset);
-}
-
-// Verify that if the offset is non-zero and there is an elf at that
-// offset, that only part of the file is used.
-TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) {
- MapInfo info(nullptr, nullptr, 0x100, 0x200, 0x1000, 0, elf_at_1000_.path);
-
- std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0U, info.elf_offset);
- EXPECT_EQ(0x1000U, info.elf_start_offset);
-
- // Read the valid part of the file.
- std::vector<uint8_t> buffer(0x100);
- ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
- ASSERT_TRUE(memcmp(buffer.data(), ELFMAG, SELFMAG) == 0);
- ASSERT_EQ(ELFCLASS64, buffer[EI_CLASS]);
- for (size_t i = EI_CLASS + 1; i < buffer.size(); i++) {
- ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
- }
-
- ASSERT_FALSE(memory->ReadFully(0x100, buffer.data(), 1));
-}
-
-// Verify that if the offset is non-zero and there is an elf at that
-// offset, that only part of the file is used. Further verify that if the
-// embedded elf is bigger than the initial map, the new object is larger
-// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
-TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
- MapInfo info(nullptr, nullptr, 0x5000, 0x6000, 0x1000, 0, elf32_at_map_.path);
-
- std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0U, info.elf_offset);
- EXPECT_EQ(0x1000U, info.elf_start_offset);
-
- // Verify the memory is a valid elf.
- uint8_t e_ident[SELFMAG + 1];
- ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
- ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
-
- // Read past the end of what would normally be the size of the map.
- ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
-}
-
-TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
- MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x2000, 0, elf64_at_map_.path);
-
- std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(info.memory_backed_elf);
- ASSERT_EQ(0U, info.elf_offset);
- EXPECT_EQ(0x2000U, info.elf_start_offset);
-
- // Verify the memory is a valid elf.
- uint8_t e_ident[SELFMAG + 1];
- ASSERT_TRUE(memory->ReadFully(0, e_ident, SELFMAG));
- ASSERT_EQ(0, memcmp(e_ident, ELFMAG, SELFMAG));
-
- // Read past the end of what would normally be the size of the map.
- ASSERT_TRUE(memory->ReadFully(0x1000, e_ident, 1));
-}
-
-// Verify that device file names will never result in Memory object creation.
-TEST_F(MapInfoCreateMemoryTest, check_device_maps) {
- // Set up some memory so that a valid local memory object would
- // be returned if the file mapping fails, but the device check is incorrect.
- std::vector<uint8_t> buffer(1024);
- uint64_t start = reinterpret_cast<uint64_t>(buffer.data());
- MapInfo info(nullptr, nullptr, start, start + buffer.size(), 0, 0x8000, "/dev/something");
-
- std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() == nullptr);
-}
-
-TEST_F(MapInfoCreateMemoryTest, process_memory) {
- MapInfo info(nullptr, nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
-
- Elf32_Ehdr ehdr = {};
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- std::vector<uint8_t> buffer(1024);
- memcpy(buffer.data(), &ehdr, sizeof(ehdr));
-
- // Verify that the the process_memory object is used, so seed it
- // with memory.
- for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
- buffer[i] = i % 256;
- }
- memory_->SetMemory(info.start, buffer.data(), buffer.size());
-
- std::unique_ptr<Memory> memory(info.CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_TRUE(info.memory_backed_elf);
-
- memset(buffer.data(), 0, buffer.size());
- ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size()));
- ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
- for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
- ASSERT_EQ(i % 256, buffer[i]) << "Failed at byte " << i;
- }
-
- // Try to read outside of the map size.
- ASSERT_FALSE(memory->ReadFully(buffer.size(), buffer.data(), 1));
-}
-
-TEST_F(MapInfoCreateMemoryTest, valid_rosegment_zero_offset) {
- Maps maps;
- maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
- maps.Add(0x1000, 0x2600, 0, PROT_READ, "/only/in/memory.so", 0);
- maps.Add(0x3000, 0x5000, 0x4000, PROT_READ | PROT_EXEC, "/only/in/memory.so", 0);
-
- Elf32_Ehdr ehdr = {};
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
- memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x1600 - sizeof(ehdr), 0xab);
-
- // Set the memory in the r-x map.
- memory_->SetMemoryBlock(0x3000, 0x2000, 0x5d);
-
- MapInfo* map_info = maps.Find(0x3000);
- ASSERT_TRUE(map_info != nullptr);
-
- std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
- ASSERT_TRUE(mem.get() != nullptr);
- EXPECT_TRUE(map_info->memory_backed_elf);
- EXPECT_EQ(0x4000UL, map_info->elf_offset);
- EXPECT_EQ(0x4000UL, map_info->offset);
- EXPECT_EQ(0U, map_info->elf_start_offset);
-
- // Verify that reading values from this memory works properly.
- std::vector<uint8_t> buffer(0x4000);
- size_t bytes = mem->Read(0, buffer.data(), buffer.size());
- ASSERT_EQ(0x1600UL, bytes);
- ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
- for (size_t i = sizeof(ehdr); i < bytes; i++) {
- ASSERT_EQ(0xab, buffer[i]) << "Failed at byte " << i;
- }
-
- bytes = mem->Read(0x4000, buffer.data(), buffer.size());
- ASSERT_EQ(0x2000UL, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x5d, buffer[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) {
- Maps maps;
- maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
- maps.Add(0x1000, 0x2000, 0, PROT_READ, "/only/in/memory.apk", 0);
- maps.Add(0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0);
- maps.Add(0x3000, 0x4000, 0xa000, PROT_READ, "/only/in/memory.apk", 0);
- maps.Add(0x4000, 0x5000, 0xb000, PROT_READ | PROT_EXEC, "/only/in/memory.apk", 0);
-
- Elf32_Ehdr ehdr = {};
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
-
- // Setup an elf at offset 0x1000 in memory.
- memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
- memory_->SetMemoryBlock(0x1000 + sizeof(ehdr), 0x2000 - sizeof(ehdr), 0x12);
- memory_->SetMemoryBlock(0x2000, 0x1000, 0x23);
-
- // Setup an elf at offset 0x3000 in memory..
- memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
- memory_->SetMemoryBlock(0x3000 + sizeof(ehdr), 0x4000 - sizeof(ehdr), 0x34);
- memory_->SetMemoryBlock(0x4000, 0x1000, 0x43);
-
- MapInfo* map_info = maps.Find(0x4000);
- ASSERT_TRUE(map_info != nullptr);
-
- std::unique_ptr<Memory> mem(map_info->CreateMemory(process_memory_));
- ASSERT_TRUE(mem.get() != nullptr);
- EXPECT_TRUE(map_info->memory_backed_elf);
- EXPECT_EQ(0x1000UL, map_info->elf_offset);
- EXPECT_EQ(0xb000UL, map_info->offset);
- EXPECT_EQ(0xa000UL, map_info->elf_start_offset);
-
- // Verify that reading values from this memory works properly.
- std::vector<uint8_t> buffer(0x4000);
- size_t bytes = mem->Read(0, buffer.data(), buffer.size());
- ASSERT_EQ(0x1000UL, bytes);
- ASSERT_EQ(0, memcmp(&ehdr, buffer.data(), sizeof(ehdr)));
- for (size_t i = sizeof(ehdr); i < bytes; i++) {
- ASSERT_EQ(0x34, buffer[i]) << "Failed at byte " << i;
- }
-
- bytes = mem->Read(0x1000, buffer.data(), buffer.size());
- ASSERT_EQ(0x1000UL, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x43, buffer[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) {
- Maps maps;
- maps.Add(0x500, 0x600, 0, PROT_READ, "something_else", 0);
- maps.Add(0x1000, 0x2000, 0x1000, PROT_READ, elf_at_1000_.path, 0);
- maps.Add(0x2000, 0x3000, 0x2000, PROT_READ | PROT_EXEC, elf_at_1000_.path, 0);
-
- MapInfo* map_info = maps.Find(0x2000);
- ASSERT_TRUE(map_info != nullptr);
-
- // Set up the size
- Elf64_Ehdr ehdr;
- ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
- ASSERT_TRUE(android::base::ReadFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
-
- // Will not give the elf memory, because the read-only entry does not
- // extend over the executable segment.
- std::unique_ptr<Memory> memory(map_info->CreateMemory(process_memory_));
- ASSERT_TRUE(memory.get() != nullptr);
- EXPECT_FALSE(map_info->memory_backed_elf);
- std::vector<uint8_t> buffer(0x100);
- EXPECT_EQ(0x2000U, map_info->offset);
- EXPECT_EQ(0U, map_info->elf_offset);
- EXPECT_EQ(0U, map_info->elf_start_offset);
- ASSERT_TRUE(memory->ReadFully(0, buffer.data(), 0x100));
- EXPECT_EQ(0xffU, buffer[0]);
-
- // Now init the elf data enough so that the file memory object will be used.
- ehdr.e_shoff = 0x4000;
- ehdr.e_shnum = 1;
- ehdr.e_shentsize = 0x100;
- ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET));
- ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr)));
-
- map_info->memory_backed_elf = false;
- memory.reset(map_info->CreateMemory(process_memory_));
- EXPECT_FALSE(map_info->memory_backed_elf);
- EXPECT_EQ(0x2000U, map_info->offset);
- EXPECT_EQ(0x1000U, map_info->elf_offset);
- EXPECT_EQ(0x1000U, map_info->elf_start_offset);
- Elf64_Ehdr ehdr_mem;
- ASSERT_TRUE(memory->ReadFully(0, &ehdr_mem, sizeof(ehdr_mem)));
- EXPECT_TRUE(memcmp(&ehdr, &ehdr_mem, sizeof(ehdr)) == 0);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp b/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
deleted file mode 100644
index 70e136b..0000000
--- a/libunwindstack/tests/MapInfoGetBuildIDTest.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * 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 <elf.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <memory>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <android-base/test_utils.h>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-#include "ElfFake.h"
-#include "ElfTestUtils.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class MapInfoGetBuildIDTest : public ::testing::Test {
- protected:
- void SetUp() override {
- tf_.reset(new TemporaryFile);
-
- memory_ = new MemoryFake;
- elf_ = new ElfFake(new MemoryFake);
- elf_interface_ = new ElfInterfaceFake(memory_);
- elf_->FakeSetInterface(elf_interface_);
- elf_container_.reset(elf_);
- map_info_.reset(
- new MapInfo(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, tf_->path));
- }
-
- void MultipleThreadTest(std::string expected_build_id);
-
- MemoryFake* memory_;
- ElfFake* elf_;
- ElfInterfaceFake* elf_interface_;
- std::unique_ptr<ElfFake> elf_container_;
- std::unique_ptr<MapInfo> map_info_;
- std::unique_ptr<TemporaryFile> tf_;
-};
-
-TEST_F(MapInfoGetBuildIDTest, no_elf_and_no_valid_elf_in_memory) {
- MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
-
- EXPECT_EQ("", info.GetBuildID());
- EXPECT_EQ("", info.GetPrintableBuildID());
-}
-
-TEST_F(MapInfoGetBuildIDTest, from_elf) {
- map_info_->elf.reset(elf_container_.release());
- elf_interface_->FakeSetBuildID("FAKE_BUILD_ID");
-
- EXPECT_EQ("FAKE_BUILD_ID", map_info_->GetBuildID());
- EXPECT_EQ("46414b455f4255494c445f4944", map_info_->GetPrintableBuildID());
-}
-
-TEST_F(MapInfoGetBuildIDTest, from_elf_no_sign_extension) {
- map_info_->elf.reset(elf_container_.release());
-
- std::string build_id = {static_cast<char>(0xfa), static_cast<char>(0xab), static_cast<char>(0x12),
- static_cast<char>(0x02)};
- elf_interface_->FakeSetBuildID(build_id);
-
- EXPECT_EQ("\xFA\xAB\x12\x2", map_info_->GetBuildID());
- EXPECT_EQ("faab1202", map_info_->GetPrintableBuildID());
-}
-
-void MapInfoGetBuildIDTest::MultipleThreadTest(std::string expected_build_id) {
- static constexpr size_t kNumConcurrentThreads = 100;
-
- std::string build_id_values[kNumConcurrentThreads];
- std::vector<std::thread*> threads;
-
- std::atomic_bool wait;
- wait = true;
- // Create all of the threads and have them do the GetLoadBias at the same time
- // to make it likely that a race will occur.
- for (size_t i = 0; i < kNumConcurrentThreads; i++) {
- std::thread* thread = new std::thread([i, this, &wait, &build_id_values]() {
- while (wait)
- ;
- build_id_values[i] = map_info_->GetBuildID();
- });
- threads.push_back(thread);
- }
-
- // Set them all going and wait for the threads to finish.
- wait = false;
- for (auto thread : threads) {
- thread->join();
- delete thread;
- }
-
- // Now verify that all of the elf files are exactly the same and valid.
- for (size_t i = 0; i < kNumConcurrentThreads; i++) {
- EXPECT_EQ(expected_build_id, build_id_values[i]) << "Thread " << i << " mismatched.";
- }
-}
-
-TEST_F(MapInfoGetBuildIDTest, multiple_thread_elf_exists) {
- map_info_->elf.reset(elf_container_.release());
- elf_interface_->FakeSetBuildID("FAKE_BUILD_ID");
-
- MultipleThreadTest("FAKE_BUILD_ID");
-}
-
-static void InitElfData(int fd) {
- Elf32_Ehdr ehdr;
- TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM);
- ehdr.e_shoff = 0x2000;
- ehdr.e_shnum = 3;
- ehdr.e_shentsize = sizeof(Elf32_Shdr);
- ehdr.e_shstrndx = 2;
- off_t offset = 0;
- ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
- ASSERT_EQ(static_cast<ssize_t>(sizeof(ehdr)), write(fd, &ehdr, sizeof(ehdr)));
-
- char note_section[128];
- Elf32_Nhdr note_header = {};
- note_header.n_namesz = sizeof("GNU");
- note_header.n_descsz = sizeof("ELF_BUILDID") - 1;
- 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], "GNU", note_header.n_namesz);
- note_offset += note_header.n_namesz;
- memcpy(¬e_section[note_offset], "ELF_BUILDID", note_header.n_descsz);
-
- Elf32_Shdr shdr = {};
- shdr.sh_type = SHT_NOTE;
- shdr.sh_name = 0x500;
- shdr.sh_offset = 0xb000;
- shdr.sh_size = sizeof(note_section);
- offset += ehdr.e_shoff + sizeof(shdr);
- ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
- ASSERT_EQ(static_cast<ssize_t>(sizeof(shdr)), write(fd, &shdr, sizeof(shdr)));
-
- // The string data for section header names.
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 0x20000;
- shdr.sh_offset = 0xf000;
- shdr.sh_size = 0x1000;
- offset += sizeof(shdr);
- ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
- ASSERT_EQ(static_cast<ssize_t>(sizeof(shdr)), write(fd, &shdr, sizeof(shdr)));
-
- offset = 0xf500;
- ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
- ASSERT_EQ(static_cast<ssize_t>(sizeof(".note.gnu.build-id")),
- write(fd, ".note.gnu.build-id", sizeof(".note.gnu.build-id")));
-
- offset = 0xb000;
- ASSERT_EQ(offset, lseek(fd, offset, SEEK_SET));
- ASSERT_EQ(static_cast<ssize_t>(sizeof(note_section)),
- write(fd, note_section, sizeof(note_section)));
-}
-
-TEST_F(MapInfoGetBuildIDTest, from_memory) {
- InitElfData(tf_->fd);
-
- EXPECT_EQ("ELF_BUILDID", map_info_->GetBuildID());
- EXPECT_EQ("454c465f4255494c444944", map_info_->GetPrintableBuildID());
-}
-
-TEST_F(MapInfoGetBuildIDTest, multiple_thread_elf_exists_in_memory) {
- InitElfData(tf_->fd);
-
- MultipleThreadTest("ELF_BUILDID");
-}
-
-TEST_F(MapInfoGetBuildIDTest, real_elf) {
- MapInfo map_info(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE,
- TestGetFileDirectory() + "offline/empty_arm64/libc.so");
- EXPECT_EQ("6df0590c4920f4c7b9f34fe833f37d54", map_info.GetPrintableBuildID());
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetElfTest.cpp b/libunwindstack/tests/MapInfoGetElfTest.cpp
deleted file mode 100644
index 7f97814..0000000
--- a/libunwindstack/tests/MapInfoGetElfTest.cpp
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <memory>
-#include <thread>
-#include <vector>
-
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-#include "ElfTestUtils.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class MapInfoGetElfTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_ = new MemoryFake;
- process_memory_.reset(memory_);
- }
-
- template <typename Ehdr, typename Shdr>
- static void InitElf(uint64_t sh_offset, Ehdr* ehdr, uint8_t class_type, uint8_t machine_type) {
- memset(ehdr, 0, sizeof(*ehdr));
- memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
- ehdr->e_ident[EI_CLASS] = class_type;
- ehdr->e_machine = machine_type;
- ehdr->e_shoff = sh_offset;
- ehdr->e_shentsize = sizeof(Shdr) + 100;
- ehdr->e_shnum = 4;
- }
-
- const size_t kMapSize = 4096;
-
- std::shared_ptr<Memory> process_memory_;
- MemoryFake* memory_;
-
- TemporaryFile elf_;
-};
-
-TEST_F(MapInfoGetElfTest, invalid) {
- MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
-
- // The map is empty, but this should still create an invalid elf object.
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_FALSE(elf->valid());
-}
-
-TEST_F(MapInfoGetElfTest, valid32) {
- MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
-
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
- EXPECT_EQ(ELFCLASS32, elf->class_type());
-
- // Now verify that an empty process memory returns an invalid elf object.
- info.elf.reset();
- elf = info.GetElf(std::shared_ptr<Memory>(), ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_FALSE(elf->valid());
-}
-
-TEST_F(MapInfoGetElfTest, valid64) {
- MapInfo info(nullptr, nullptr, 0x8000, 0x9000, 0, PROT_READ, "");
-
- Elf64_Ehdr ehdr;
- TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
- memory_->SetMemory(0x8000, &ehdr, sizeof(ehdr));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
- EXPECT_EQ(ELFCLASS64, elf->class_type());
-}
-
-TEST_F(MapInfoGetElfTest, invalid_arch_mismatch) {
- MapInfo info(nullptr, nullptr, 0x3000, 0x4000, 0, PROT_READ, "");
-
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memory_->SetMemory(0x3000, &ehdr, sizeof(ehdr));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_X86);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_FALSE(elf->valid());
-}
-
-TEST_F(MapInfoGetElfTest, gnu_debugdata_init32) {
- MapInfo info(nullptr, nullptr, 0x2000, 0x3000, 0, PROT_READ, "");
-
- TestInitGnuDebugdata<Elf32_Ehdr, Elf32_Shdr>(ELFCLASS32, EM_ARM, true,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(0x2000 + offset, ptr, size);
- });
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- EXPECT_EQ(static_cast<uint32_t>(EM_ARM), elf->machine_type());
- EXPECT_EQ(ELFCLASS32, elf->class_type());
- EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
-}
-
-TEST_F(MapInfoGetElfTest, gnu_debugdata_init64) {
- MapInfo info(nullptr, nullptr, 0x5000, 0x8000, 0, PROT_READ, "");
-
- TestInitGnuDebugdata<Elf64_Ehdr, Elf64_Shdr>(ELFCLASS64, EM_AARCH64, true,
- [&](uint64_t offset, const void* ptr, size_t size) {
- memory_->SetMemory(0x5000 + offset, ptr, size);
- });
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- EXPECT_EQ(static_cast<uint32_t>(EM_AARCH64), elf->machine_type());
- EXPECT_EQ(ELFCLASS64, elf->class_type());
- EXPECT_TRUE(elf->gnu_debugdata_interface() != nullptr);
-}
-
-TEST_F(MapInfoGetElfTest, end_le_start) {
- MapInfo info(nullptr, nullptr, 0x1000, 0x1000, 0, PROT_READ, elf_.path);
-
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, &ehdr, sizeof(ehdr)));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_FALSE(elf->valid());
-
- info.elf.reset();
- info.end = 0xfff;
- elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_FALSE(elf->valid());
-
- // Make sure this test is valid.
- info.elf.reset();
- info.end = 0x2000;
- elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
-}
-
-// Verify that if the offset is non-zero but there is no elf at the offset,
-// that the full file is used.
-TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_full_file) {
- MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x100, PROT_READ, elf_.path);
-
- std::vector<uint8_t> buffer(0x1000);
- memset(buffer.data(), 0, buffer.size());
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memcpy(buffer.data(), &ehdr, sizeof(ehdr));
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0x100U, info.elf_offset);
-
- // Read the entire file.
- memset(buffer.data(), 0, buffer.size());
- ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), buffer.size()));
- ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
- for (size_t i = sizeof(ehdr); i < buffer.size(); i++) {
- ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
- }
-
- ASSERT_FALSE(elf->memory()->ReadFully(buffer.size(), buffer.data(), 1));
-}
-
-// Verify that if the offset is non-zero and there is an elf at that
-// offset, that only part of the file is used.
-TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file) {
- MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0x2000, PROT_READ, elf_.path);
-
- std::vector<uint8_t> buffer(0x4000);
- memset(buffer.data(), 0, buffer.size());
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0U, info.elf_offset);
-
- // Read the valid part of the file.
- ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
- ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
- for (size_t i = sizeof(ehdr); i < 0x1000; i++) {
- ASSERT_EQ(0, buffer[i]) << "Failed at byte " << i;
- }
-
- ASSERT_FALSE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
-}
-
-// Verify that if the offset is non-zero and there is an elf at that
-// offset, that only part of the file is used. Further verify that if the
-// embedded elf is bigger than the initial map, the new object is larger
-// than the original map size. Do this for a 32 bit elf and a 64 bit elf.
-TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf32) {
- MapInfo info(nullptr, nullptr, 0x5000, 0x6000, 0x1000, PROT_READ, elf_.path);
-
- std::vector<uint8_t> buffer(0x4000);
- memset(buffer.data(), 0, buffer.size());
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- ehdr.e_shoff = 0x2000;
- ehdr.e_shentsize = sizeof(Elf32_Shdr) + 100;
- ehdr.e_shnum = 4;
- memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0U, info.elf_offset);
-
- // Verify the memory is a valid elf.
- memset(buffer.data(), 0, buffer.size());
- ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
- ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
-
- // Read past the end of what would normally be the size of the map.
- ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
-}
-
-TEST_F(MapInfoGetElfTest, file_backed_non_zero_offset_partial_file_whole_elf64) {
- MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, elf_.path);
-
- std::vector<uint8_t> buffer(0x4000);
- memset(buffer.data(), 0, buffer.size());
- Elf64_Ehdr ehdr;
- TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_AARCH64);
- ehdr.e_shoff = 0x2000;
- ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 4;
- memcpy(&buffer[info.offset], &ehdr, sizeof(ehdr));
- ASSERT_TRUE(android::base::WriteFully(elf_.fd, buffer.data(), buffer.size()));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_ARM64);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
- ASSERT_TRUE(elf->memory() != nullptr);
- ASSERT_EQ(0U, info.elf_offset);
-
- // Verify the memory is a valid elf.
- memset(buffer.data(), 0, buffer.size());
- ASSERT_TRUE(elf->memory()->ReadFully(0, buffer.data(), 0x1000));
- ASSERT_EQ(0, memcmp(buffer.data(), &ehdr, sizeof(ehdr)));
-
- // Read past the end of what would normally be the size of the map.
- ASSERT_TRUE(elf->memory()->ReadFully(0x1000, buffer.data(), 1));
-}
-
-TEST_F(MapInfoGetElfTest, check_device_maps) {
- MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ | MAPS_FLAGS_DEVICE_MAP,
- "/dev/something");
-
- // Create valid elf data in process memory for this to verify that only
- // the name is causing invalid elf data.
- Elf64_Ehdr ehdr;
- TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
- ehdr.e_shoff = 0x2000;
- ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 0;
- memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
-
- Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_FALSE(elf->valid());
-
- // Set the name to nothing to verify that it still fails.
- info.elf.reset();
- info.name = "";
- elf = info.GetElf(process_memory_, ARCH_X86_64);
- ASSERT_FALSE(elf->valid());
-
- // Change the flags and verify the elf is valid now.
- info.elf.reset();
- info.flags = PROT_READ;
- elf = info.GetElf(process_memory_, ARCH_X86_64);
- ASSERT_TRUE(elf->valid());
-}
-
-TEST_F(MapInfoGetElfTest, multiple_thread_get_elf) {
- static constexpr size_t kNumConcurrentThreads = 100;
-
- Elf64_Ehdr ehdr;
- TestInitEhdr<Elf64_Ehdr>(&ehdr, ELFCLASS64, EM_X86_64);
- ehdr.e_shoff = 0x2000;
- ehdr.e_shentsize = sizeof(Elf64_Shdr) + 100;
- ehdr.e_shnum = 0;
- memory_->SetMemory(0x7000, &ehdr, sizeof(ehdr));
-
- Elf* elf_in_threads[kNumConcurrentThreads];
- std::vector<std::thread*> threads;
-
- std::atomic_bool wait;
- wait = true;
- // Create all of the threads and have them do the GetElf at the same time
- // to make it likely that a race will occur.
- MapInfo info(nullptr, nullptr, 0x7000, 0x8000, 0x1000, PROT_READ, "");
- for (size_t i = 0; i < kNumConcurrentThreads; i++) {
- std::thread* thread = new std::thread([i, this, &wait, &info, &elf_in_threads]() {
- while (wait)
- ;
- Elf* elf = info.GetElf(process_memory_, ARCH_X86_64);
- elf_in_threads[i] = elf;
- });
- threads.push_back(thread);
- }
- ASSERT_TRUE(info.elf == nullptr);
-
- // Set them all going and wait for the threads to finish.
- wait = false;
- for (auto thread : threads) {
- thread->join();
- delete thread;
- }
-
- // Now verify that all of the elf files are exactly the same and valid.
- Elf* elf = info.elf.get();
- ASSERT_TRUE(elf != nullptr);
- EXPECT_TRUE(elf->valid());
- for (size_t i = 0; i < kNumConcurrentThreads; i++) {
- EXPECT_EQ(elf, elf_in_threads[i]) << "Thread " << i << " mismatched.";
- }
-}
-
-// Verify that previous maps don't automatically get the same elf object.
-TEST_F(MapInfoGetElfTest, prev_map_elf_not_set) {
- MapInfo info1(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "/not/present");
- MapInfo info2(&info1, &info1, 0x2000, 0x3000, 0, PROT_READ, elf_.path);
-
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memory_->SetMemory(0x2000, &ehdr, sizeof(ehdr));
- Elf* elf = info2.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
-
- ASSERT_NE(elf, info1.GetElf(process_memory_, ARCH_ARM));
-}
-
-// Verify that a read-only map followed by a read-execute map will result
-// in the same elf object in both maps.
-TEST_F(MapInfoGetElfTest, read_only_followed_by_read_exec_share_elf) {
- MapInfo r_info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path);
- MapInfo rw_info(&r_info, &r_info, 0x2000, 0x3000, 0x1000, PROT_READ | PROT_EXEC, elf_.path);
-
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
- Elf* elf = rw_info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
-
- ASSERT_EQ(elf, r_info.GetElf(process_memory_, ARCH_ARM));
-}
-
-// Verify that a read-only map followed by an empty map, then followed by
-// a read-execute map will result in the same elf object in both maps.
-TEST_F(MapInfoGetElfTest, read_only_followed_by_empty_then_read_exec_share_elf) {
- MapInfo r_info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, elf_.path);
- MapInfo empty(&r_info, &r_info, 0x2000, 0x3000, 0, 0, "");
- MapInfo rw_info(&empty, &r_info, 0x3000, 0x4000, 0x2000, PROT_READ | PROT_EXEC, elf_.path);
-
- Elf32_Ehdr ehdr;
- TestInitEhdr<Elf32_Ehdr>(&ehdr, ELFCLASS32, EM_ARM);
- memory_->SetMemory(0x1000, &ehdr, sizeof(ehdr));
- Elf* elf = rw_info.GetElf(process_memory_, ARCH_ARM);
- ASSERT_TRUE(elf != nullptr);
- ASSERT_TRUE(elf->valid());
-
- ASSERT_EQ(elf, r_info.GetElf(process_memory_, ARCH_ARM));
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp b/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
deleted file mode 100644
index 971d452..0000000
--- a/libunwindstack/tests/MapInfoGetLoadBiasTest.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <atomic>
-#include <memory>
-#include <thread>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/test_utils.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-
-#include "ElfFake.h"
-#include "ElfTestUtils.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class MapInfoGetLoadBiasTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_ = new MemoryFake;
- process_memory_.reset(memory_);
- elf_ = new ElfFake(new MemoryFake);
- elf_container_.reset(elf_);
- map_info_.reset(new MapInfo(nullptr, nullptr, 0x1000, 0x20000, 0, PROT_READ | PROT_WRITE, ""));
- }
-
- void MultipleThreadTest(uint64_t expected_load_bias);
-
- std::shared_ptr<Memory> process_memory_;
- MemoryFake* memory_;
- ElfFake* elf_;
- std::unique_ptr<ElfFake> elf_container_;
- std::unique_ptr<MapInfo> map_info_;
-};
-
-TEST_F(MapInfoGetLoadBiasTest, no_elf_and_no_valid_elf_in_memory) {
- MapInfo info(nullptr, nullptr, 0x1000, 0x2000, 0, PROT_READ, "");
-
- EXPECT_EQ(0U, info.GetLoadBias(process_memory_));
-}
-
-TEST_F(MapInfoGetLoadBiasTest, load_bias_cached_from_elf) {
- map_info_->elf.reset(elf_container_.release());
-
- elf_->FakeSetLoadBias(0);
- EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
-
- elf_->FakeSetLoadBias(0x1000);
- EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
-}
-
-TEST_F(MapInfoGetLoadBiasTest, elf_exists) {
- map_info_->elf.reset(elf_container_.release());
-
- elf_->FakeSetLoadBias(0);
- EXPECT_EQ(0U, map_info_->GetLoadBias(process_memory_));
-
- map_info_->load_bias = INT64_MAX;
- elf_->FakeSetLoadBias(0x1000);
- EXPECT_EQ(0x1000U, map_info_->GetLoadBias(process_memory_));
-}
-
-void MapInfoGetLoadBiasTest::MultipleThreadTest(uint64_t expected_load_bias) {
- static constexpr size_t kNumConcurrentThreads = 100;
-
- uint64_t load_bias_values[kNumConcurrentThreads];
- std::vector<std::thread*> threads;
-
- std::atomic_bool wait;
- wait = true;
- // Create all of the threads and have them do the GetLoadBias at the same time
- // to make it likely that a race will occur.
- for (size_t i = 0; i < kNumConcurrentThreads; i++) {
- std::thread* thread = new std::thread([i, this, &wait, &load_bias_values]() {
- while (wait)
- ;
- load_bias_values[i] = map_info_->GetLoadBias(process_memory_);
- });
- threads.push_back(thread);
- }
-
- // Set them all going and wait for the threads to finish.
- wait = false;
- for (auto thread : threads) {
- thread->join();
- delete thread;
- }
-
- // Now verify that all of the elf files are exactly the same and valid.
- for (size_t i = 0; i < kNumConcurrentThreads; i++) {
- EXPECT_EQ(expected_load_bias, load_bias_values[i]) << "Thread " << i << " mismatched.";
- }
-}
-
-TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists) {
- map_info_->elf.reset(elf_container_.release());
- elf_->FakeSetLoadBias(0x1000);
-
- MultipleThreadTest(0x1000);
-}
-
-static void InitElfData(MemoryFake* memory, uint64_t offset) {
- Elf32_Ehdr ehdr;
- TestInitEhdr(&ehdr, ELFCLASS32, EM_ARM);
- ehdr.e_phoff = 0x5000;
- ehdr.e_phnum = 2;
- ehdr.e_phentsize = sizeof(Elf32_Phdr);
- memory->SetMemory(offset, &ehdr, sizeof(ehdr));
-
- Elf32_Phdr phdr;
- memset(&phdr, 0, sizeof(phdr));
- phdr.p_type = PT_NULL;
- memory->SetMemory(offset + 0x5000, &phdr, sizeof(phdr));
- phdr.p_type = PT_LOAD;
- phdr.p_flags = PF_X;
- phdr.p_offset = 0;
- phdr.p_vaddr = 0xe000;
- memory->SetMemory(offset + 0x5000 + sizeof(phdr), &phdr, sizeof(phdr));
-}
-
-TEST_F(MapInfoGetLoadBiasTest, elf_exists_in_memory) {
- InitElfData(memory_, map_info_->start);
-
- EXPECT_EQ(0xe000U, map_info_->GetLoadBias(process_memory_));
-}
-
-TEST_F(MapInfoGetLoadBiasTest, elf_exists_in_memory_cached) {
- InitElfData(memory_, map_info_->start);
-
- EXPECT_EQ(0xe000U, map_info_->GetLoadBias(process_memory_));
-
- memory_->Clear();
- EXPECT_EQ(0xe000U, map_info_->GetLoadBias(process_memory_));
-}
-
-TEST_F(MapInfoGetLoadBiasTest, multiple_thread_elf_exists_in_memory) {
- InitElfData(memory_, map_info_->start);
-
- MultipleThreadTest(0xe000);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MapInfoTest.cpp b/libunwindstack/tests/MapInfoTest.cpp
deleted file mode 100644
index 98edc0e..0000000
--- a/libunwindstack/tests/MapInfoTest.cpp
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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 <gtest/gtest.h>
-
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/Maps.h>
-
-#include "ElfFake.h"
-
-namespace unwindstack {
-
-TEST(MapInfoTest, maps_constructor_const_char) {
- MapInfo prev_map(nullptr, nullptr, 0, 0, 0, 0, "");
- MapInfo map_info(&prev_map, &prev_map, 1, 2, 3, 4, "map");
-
- EXPECT_EQ(&prev_map, map_info.prev_map);
- EXPECT_EQ(1UL, map_info.start);
- EXPECT_EQ(2UL, map_info.end);
- EXPECT_EQ(3UL, map_info.offset);
- EXPECT_EQ(4UL, map_info.flags);
- EXPECT_EQ("map", map_info.name);
- EXPECT_EQ(INT64_MAX, map_info.load_bias);
- EXPECT_EQ(0UL, map_info.elf_offset);
- EXPECT_TRUE(map_info.elf.get() == nullptr);
-}
-
-TEST(MapInfoTest, maps_constructor_string) {
- std::string name("string_map");
- MapInfo prev_map(nullptr, nullptr, 0, 0, 0, 0, "");
- MapInfo map_info(&prev_map, &prev_map, 1, 2, 3, 4, name);
-
- EXPECT_EQ(&prev_map, map_info.prev_map);
- EXPECT_EQ(1UL, map_info.start);
- EXPECT_EQ(2UL, map_info.end);
- EXPECT_EQ(3UL, map_info.offset);
- EXPECT_EQ(4UL, map_info.flags);
- EXPECT_EQ("string_map", map_info.name);
- EXPECT_EQ(INT64_MAX, map_info.load_bias);
- EXPECT_EQ(0UL, map_info.elf_offset);
- EXPECT_TRUE(map_info.elf.get() == nullptr);
-}
-
-TEST(MapInfoTest, get_function_name) {
- ElfFake* elf = new ElfFake(nullptr);
- ElfInterfaceFake* interface = new ElfInterfaceFake(nullptr);
- elf->FakeSetInterface(interface);
- interface->FakePushFunctionData(FunctionData("function", 1000));
-
- MapInfo map_info(nullptr, nullptr, 1, 2, 3, 4, "");
- map_info.elf.reset(elf);
-
- std::string name;
- uint64_t offset;
- ASSERT_TRUE(map_info.GetFunctionName(1000, &name, &offset));
- EXPECT_EQ("function", name);
- EXPECT_EQ(1000UL, offset);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MapsTest.cpp b/libunwindstack/tests/MapsTest.cpp
deleted file mode 100644
index 724eeb5..0000000
--- a/libunwindstack/tests/MapsTest.cpp
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <sys/mman.h>
-
-#include <android-base/file.h>
-#include <android-base/stringprintf.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/Maps.h>
-
-namespace unwindstack {
-
-static void VerifyLine(std::string line, MapInfo* info) {
- BufferMaps maps(line.c_str());
-
- if (info == nullptr) {
- ASSERT_FALSE(maps.Parse()) << "Failed on: " + line;
- } else {
- ASSERT_TRUE(maps.Parse()) << "Failed on: " + line;
- MapInfo* element = maps.Get(0);
- ASSERT_TRUE(element != nullptr) << "Failed on: " + line;
- info->start = element->start;
- info->end = element->end;
- info->offset = element->offset;
- info->flags = element->flags;
- info->name = element->name;
- info->elf_offset = element->elf_offset;
- }
-}
-
-TEST(MapsTest, map_add) {
- Maps maps;
-
- maps.Add(0x1000, 0x2000, 0, PROT_READ, "fake_map", 0);
- maps.Add(0x3000, 0x4000, 0x10, 0, "", 0x1234);
- maps.Add(0x5000, 0x6000, 1, 2, "fake_map2", static_cast<uint64_t>(-1));
-
- ASSERT_EQ(3U, maps.Total());
- MapInfo* info = maps.Get(0);
- ASSERT_EQ(0x1000U, info->start);
- ASSERT_EQ(0x2000U, info->end);
- ASSERT_EQ(0U, info->offset);
- ASSERT_EQ(PROT_READ, info->flags);
- ASSERT_EQ("fake_map", info->name);
- ASSERT_EQ(0U, info->elf_offset);
- ASSERT_EQ(0U, info->load_bias.load());
-}
-
-TEST(MapsTest, map_move) {
- Maps maps;
-
- maps.Add(0x1000, 0x2000, 0, PROT_READ, "fake_map", 0);
- maps.Add(0x3000, 0x4000, 0x10, 0, "", 0x1234);
- maps.Add(0x5000, 0x6000, 1, 2, "fake_map2", static_cast<uint64_t>(-1));
-
- Maps maps2 = std::move(maps);
-
- ASSERT_EQ(3U, maps2.Total());
- MapInfo* info = maps2.Get(0);
- ASSERT_EQ(0x1000U, info->start);
- ASSERT_EQ(0x2000U, info->end);
- ASSERT_EQ(0U, info->offset);
- ASSERT_EQ(PROT_READ, info->flags);
- ASSERT_EQ("fake_map", info->name);
- ASSERT_EQ(0U, info->elf_offset);
- ASSERT_EQ(0U, info->load_bias.load());
-}
-
-TEST(MapsTest, verify_parse_line) {
- MapInfo info(nullptr, nullptr, 0, 0, 0, 0, "");
-
- VerifyLine("01-02 rwxp 03 04:05 06\n", &info);
- EXPECT_EQ(1U, info.start);
- EXPECT_EQ(2U, info.end);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
- EXPECT_EQ(3U, info.offset);
- EXPECT_EQ("", info.name);
-
- VerifyLine("0a-0b ---s 0c 0d:0e 06 /fake/name\n", &info);
- EXPECT_EQ(0xaU, info.start);
- EXPECT_EQ(0xbU, info.end);
- EXPECT_EQ(0U, info.flags);
- EXPECT_EQ(0xcU, info.offset);
- EXPECT_EQ("/fake/name", info.name);
-
- VerifyLine("01-02 rwxp 03 04:05 06 /fake/name/again\n", &info);
- EXPECT_EQ(1U, info.start);
- EXPECT_EQ(2U, info.end);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
- EXPECT_EQ(3U, info.offset);
- EXPECT_EQ("/fake/name/again", info.name);
-
- VerifyLine("-00 rwxp 00 00:00 0\n", nullptr);
- VerifyLine("00- rwxp 00 00:00 0\n", nullptr);
- VerifyLine("00-00 rwxp 00 :00 0\n", nullptr);
- VerifyLine("00-00 rwxp 00 00:00 \n", nullptr);
- VerifyLine("x-00 rwxp 00 00:00 0\n", nullptr);
- VerifyLine("00 -00 rwxp 00 00:00 0\n", nullptr);
- VerifyLine("00-x rwxp 00 00:00 0\n", nullptr);
- VerifyLine("00-x rwxp 00 00:00 0\n", nullptr);
- VerifyLine("00-00x rwxp 00 00:00 0\n", nullptr);
- VerifyLine("00-00 rwxp0 00 00:00 0\n", nullptr);
- VerifyLine("00-00 rwxp0 00 00:00 0\n", nullptr);
- VerifyLine("00-00 rwp 00 00:00 0\n", nullptr);
- VerifyLine("00-00 rwxp 0000:00 0\n", nullptr);
- VerifyLine("00-00 rwxp 00 00 :00 0\n", nullptr);
- VerifyLine("00-00 rwxp 00 00: 00 0\n", nullptr);
- VerifyLine("00-00 rwxp 00 00:000\n", nullptr);
- VerifyLine("00-00 rwxp 00 00:00 0/fake\n", nullptr);
- VerifyLine("00-00 xxxx 00 00:00 0 /fake\n", nullptr);
- VerifyLine("00-00 ywxp 00 00:00 0 /fake\n", nullptr);
- VerifyLine("00-00 ryxp 00 00:00 0 /fake\n", nullptr);
- VerifyLine("00-00 rwyp 00 00:00 0 /fake\n", nullptr);
- VerifyLine("00-00 rwx- 00 00:00 0 /fake\n", nullptr);
- VerifyLine("0\n", nullptr);
- VerifyLine("00\n", nullptr);
- VerifyLine("00-\n", nullptr);
- VerifyLine("00-0\n", nullptr);
- VerifyLine("00-00\n", nullptr);
- VerifyLine("00-00 \n", nullptr);
- VerifyLine("00-00 -\n", nullptr);
- VerifyLine("00-00 r\n", nullptr);
- VerifyLine("00-00 --\n", nullptr);
- VerifyLine("00-00 rw\n", nullptr);
- VerifyLine("00-00 ---\n", nullptr);
- VerifyLine("00-00 rwx\n", nullptr);
- VerifyLine("00-00 ---s\n", nullptr);
- VerifyLine("00-00 ---p\n", nullptr);
- VerifyLine("00-00 ---s 0\n", nullptr);
- VerifyLine("00-00 ---p 0 \n", nullptr);
- VerifyLine("00-00 ---p 0 0\n", nullptr);
- VerifyLine("00-00 ---p 0 0:\n", nullptr);
- VerifyLine("00-00 ---p 0 0:0\n", nullptr);
- VerifyLine("00-00 ---p 0 0:0 \n", nullptr);
-
- // Line to verify that the parser will detect a completely malformed line
- // properly.
- VerifyLine("7ffff7dda000-7ffff7dfd7ffff7ff3000-7ffff7ff4000 ---p 0000f000 fc:02 44171565\n",
- nullptr);
-}
-
-TEST(MapsTest, verify_large_values) {
- MapInfo info(nullptr, nullptr, 0, 0, 0, 0, "");
-#if defined(__LP64__)
- VerifyLine("fabcdef012345678-f12345678abcdef8 rwxp f0b0d0f010305070 00:00 0\n", &info);
- EXPECT_EQ(0xfabcdef012345678UL, info.start);
- EXPECT_EQ(0xf12345678abcdef8UL, info.end);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
- EXPECT_EQ(0xf0b0d0f010305070UL, info.offset);
-#else
- VerifyLine("f2345678-fabcdef8 rwxp f0305070 00:00 0\n", &info);
- EXPECT_EQ(0xf2345678UL, info.start);
- EXPECT_EQ(0xfabcdef8UL, info.end);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info.flags);
- EXPECT_EQ(0xf0305070UL, info.offset);
-#endif
-}
-
-TEST(MapsTest, parse_permissions) {
- BufferMaps maps(
- "1000-2000 ---s 00000000 00:00 0\n"
- "2000-3000 r--s 00000000 00:00 0\n"
- "3000-4000 -w-s 00000000 00:00 0\n"
- "4000-5000 --xp 00000000 00:00 0\n"
- "5000-6000 rwxp 00000000 00:00 0\n");
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(5U, maps.Total());
-
- MapInfo* info = maps.Get(0);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(PROT_NONE, info->flags);
- EXPECT_EQ(0x1000U, info->start);
- EXPECT_EQ(0x2000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ("", info->name);
-
- info = maps.Get(1);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(PROT_READ, info->flags);
- EXPECT_EQ(0x2000U, info->start);
- EXPECT_EQ(0x3000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ("", info->name);
-
- info = maps.Get(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(PROT_WRITE, info->flags);
- EXPECT_EQ(0x3000U, info->start);
- EXPECT_EQ(0x4000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ("", info->name);
-
- info = maps.Get(3);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(PROT_EXEC, info->flags);
- EXPECT_EQ(0x4000U, info->start);
- EXPECT_EQ(0x5000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ("", info->name);
-
- info = maps.Get(4);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
- EXPECT_EQ(0x5000U, info->start);
- EXPECT_EQ(0x6000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ("", info->name);
-
- ASSERT_TRUE(maps.Get(5) == nullptr);
-}
-
-TEST(MapsTest, parse_name) {
- BufferMaps maps(
- "7b29b000-7b29e000 rw-p 00000000 00:00 0\n"
- "7b29e000-7b29f000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
- "7b29f000-7b2a0000 rw-p 00000000 00:00 0");
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(3U, maps.Total());
-
- MapInfo* info = maps.Get(0);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ("", info->name);
- EXPECT_EQ(0x7b29b000U, info->start);
- EXPECT_EQ(0x7b29e000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
-
- info = maps.Get(1);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ("/system/lib/fake.so", info->name);
- EXPECT_EQ(0x7b29e000U, info->start);
- EXPECT_EQ(0x7b29f000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
-
- info = maps.Get(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ("", info->name);
- EXPECT_EQ(0x7b29f000U, info->start);
- EXPECT_EQ(0x7b2a0000U, info->end);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
-
- ASSERT_TRUE(maps.Get(3) == nullptr);
-}
-
-TEST(MapsTest, parse_offset) {
- BufferMaps maps(
- "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
- "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(2U, maps.Total());
-
- MapInfo* info = maps.Get(0);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0U, info->offset);
- EXPECT_EQ(0xa000U, info->start);
- EXPECT_EQ(0xe000U, info->end);
- EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
- EXPECT_EQ("/system/lib/fake.so", info->name);
-
- info = maps.Get(1);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0xa12345U, info->offset);
- EXPECT_EQ(0xe000U, info->start);
- EXPECT_EQ(0xf000U, info->end);
- EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
- EXPECT_EQ("/system/lib/fake.so", info->name);
-
- ASSERT_TRUE(maps.Get(2) == nullptr);
-}
-
-TEST(MapsTest, iterate) {
- BufferMaps maps(
- "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
- "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(2U, maps.Total());
-
- Maps::iterator it = maps.begin();
- EXPECT_EQ(0xa000U, (*it)->start);
- EXPECT_EQ(0xe000U, (*it)->end);
- ++it;
- EXPECT_EQ(0xe000U, (*it)->start);
- EXPECT_EQ(0xf000U, (*it)->end);
- ++it;
- EXPECT_EQ(maps.end(), it);
-}
-
-TEST(MapsTest, const_iterate) {
- BufferMaps maps(
- "a000-e000 rw-p 00000000 00:00 0 /system/lib/fake.so\n"
- "e000-f000 rw-p 00a12345 00:00 0 /system/lib/fake.so\n");
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(2U, maps.Total());
-
- Maps::const_iterator it = maps.begin();
- EXPECT_EQ(0xa000U, (*it)->start);
- EXPECT_EQ(0xe000U, (*it)->end);
- ++it;
- EXPECT_EQ(0xe000U, (*it)->start);
- EXPECT_EQ(0xf000U, (*it)->end);
- ++it;
- EXPECT_EQ(maps.end(), it);
-}
-
-TEST(MapsTest, device) {
- BufferMaps maps(
- "a000-e000 rw-p 00000000 00:00 0 /dev/\n"
- "f000-f100 rw-p 00000000 00:00 0 /dev/does_not_exist\n"
- "f100-f200 rw-p 00000000 00:00 0 /dev/ashmem/does_not_exist\n"
- "f200-f300 rw-p 00000000 00:00 0 /devsomething/does_not_exist\n");
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(4U, maps.Total());
-
- MapInfo* info = maps.Get(0);
- ASSERT_TRUE(info != nullptr);
- EXPECT_TRUE(info->flags & 0x8000);
- EXPECT_EQ("/dev/", info->name);
-
- info = maps.Get(1);
- EXPECT_TRUE(info->flags & 0x8000);
- EXPECT_EQ("/dev/does_not_exist", info->name);
-
- info = maps.Get(2);
- EXPECT_FALSE(info->flags & 0x8000);
- EXPECT_EQ("/dev/ashmem/does_not_exist", info->name);
-
- info = maps.Get(3);
- EXPECT_FALSE(info->flags & 0x8000);
- EXPECT_EQ("/devsomething/does_not_exist", info->name);
-}
-
-TEST(MapsTest, file_smoke) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_TRUE(
- android::base::WriteStringToFile("7b29b000-7b29e000 r-xp a0000000 00:00 0 /fake.so\n"
- "7b2b0000-7b2e0000 r-xp b0000000 00:00 0 /fake2.so\n"
- "7b2e0000-7b2f0000 r-xp c0000000 00:00 0 /fake3.so\n",
- tf.path, 0660, getuid(), getgid()));
-
- FileMaps maps(tf.path);
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(3U, maps.Total());
-
- MapInfo* info = maps.Get(0);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x7b29b000U, info->start);
- EXPECT_EQ(0x7b29e000U, info->end);
- EXPECT_EQ(0xa0000000U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
- EXPECT_EQ("/fake.so", info->name);
-
- info = maps.Get(1);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x7b2b0000U, info->start);
- EXPECT_EQ(0x7b2e0000U, info->end);
- EXPECT_EQ(0xb0000000U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
- EXPECT_EQ("/fake2.so", info->name);
-
- info = maps.Get(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x7b2e0000U, info->start);
- EXPECT_EQ(0x7b2f0000U, info->end);
- EXPECT_EQ(0xc0000000U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
- EXPECT_EQ("/fake3.so", info->name);
-
- ASSERT_TRUE(maps.Get(3) == nullptr);
-}
-
-TEST(MapsTest, file_no_map_name) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_TRUE(
- android::base::WriteStringToFile("7b29b000-7b29e000 r-xp a0000000 00:00 0\n"
- "7b2b0000-7b2e0000 r-xp b0000000 00:00 0 /fake2.so\n"
- "7b2e0000-7b2f0000 r-xp c0000000 00:00 0 \n",
- tf.path, 0660, getuid(), getgid()));
-
- FileMaps maps(tf.path);
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(3U, maps.Total());
-
- MapInfo* info = maps.Get(0);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x7b29b000U, info->start);
- EXPECT_EQ(0x7b29e000U, info->end);
- EXPECT_EQ(0xa0000000U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
- EXPECT_EQ("", info->name);
-
- info = maps.Get(1);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x7b2b0000U, info->start);
- EXPECT_EQ(0x7b2e0000U, info->end);
- EXPECT_EQ(0xb0000000U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
- EXPECT_EQ("/fake2.so", info->name);
-
- info = maps.Get(2);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x7b2e0000U, info->start);
- EXPECT_EQ(0x7b2f0000U, info->end);
- EXPECT_EQ(0xc0000000U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_EXEC, info->flags);
- EXPECT_EQ("", info->name);
-
- ASSERT_TRUE(maps.Get(3) == nullptr);
-}
-
-// Verify that a file that crosses a buffer is parsed correctly.
-static std::string CreateEntry(size_t index) {
- return android::base::StringPrintf("%08zx-%08zx rwxp 0000 00:00 0\n", index * 4096,
- (index + 1) * 4096);
-}
-
-TEST(MapsTest, file_buffer_cross) {
- constexpr size_t kBufferSize = 2048;
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- // Compute how many to add in the first buffer.
- size_t entry_len = CreateEntry(0).size();
- size_t index;
- std::string file_data;
- for (index = 0; index < kBufferSize / entry_len; index++) {
- file_data += CreateEntry(index);
- }
- // Add a long name to make sure that the first buffer does not contain a
- // complete line.
- // Remove the last newline.
- size_t extra = 0;
- size_t leftover = kBufferSize % entry_len;
- size_t overlap1_index = 0;
- std::string overlap1_name;
- if (leftover == 0) {
- // Exact match, add a long name to cross over the value.
- overlap1_name = "/fake/name/is/long/on/purpose";
- file_data.erase(file_data.size() - 1);
- file_data += ' ' + overlap1_name + '\n';
- extra = entry_len + overlap1_name.size() + 1;
- overlap1_index = index;
- }
-
- // Compute how many need to go in to hit the buffer boundary exactly.
- size_t bytes_left_in_buffer = kBufferSize - extra;
- size_t entries_to_add = bytes_left_in_buffer / entry_len + index;
- for (; index < entries_to_add; index++) {
- file_data += CreateEntry(index);
- }
-
- // Now figure out how many bytes to add to get exactly to the buffer boundary.
- leftover = bytes_left_in_buffer % entry_len;
- std::string overlap2_name;
- size_t overlap2_index = 0;
- if (leftover != 0) {
- file_data.erase(file_data.size() - 1);
- file_data += ' ';
- overlap2_name = std::string(leftover - 1, 'x');
- file_data += overlap2_name + '\n';
- overlap2_index = index - 1;
- }
-
- // Now add a few entries on the next page.
- for (size_t start = index; index < start + 10; index++) {
- file_data += CreateEntry(index);
- }
-
- ASSERT_TRUE(android::base::WriteStringToFile(file_data, tf.path, 0660, getuid(), getgid()));
-
- FileMaps maps(tf.path);
- ASSERT_TRUE(maps.Parse());
- EXPECT_EQ(index, maps.Total());
- // Verify all of the maps.
- for (size_t i = 0; i < index; i++) {
- MapInfo* info = maps.Get(i);
- ASSERT_TRUE(info != nullptr) << "Failed verifying index " + std::to_string(i);
- EXPECT_EQ(i * 4096, info->start) << "Failed verifying index " + std::to_string(i);
- EXPECT_EQ((i + 1) * 4096, info->end) << "Failed verifying index " + std::to_string(i);
- EXPECT_EQ(0U, info->offset) << "Failed verifying index " + std::to_string(i);
- if (overlap1_index != 0 && i == overlap1_index) {
- EXPECT_EQ(overlap1_name, info->name) << "Failed verifying overlap1 name " + std::to_string(i);
- } else if (overlap2_index != 0 && i == overlap2_index) {
- EXPECT_EQ(overlap2_name, info->name) << "Failed verifying overlap2 name " + std::to_string(i);
- } else {
- EXPECT_EQ("", info->name) << "Failed verifying index " + std::to_string(i);
- }
- }
-}
-
-TEST(MapsTest, file_should_fail) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- ASSERT_TRUE(android::base::WriteStringToFile(
- "7ffff7dda000-7ffff7dfd7ffff7ff3000-7ffff7ff4000 ---p 0000f000 fc:02 44171565\n", tf.path,
- 0660, getuid(), getgid()));
-
- FileMaps maps(tf.path);
-
- ASSERT_FALSE(maps.Parse());
-}
-
-// Create a maps file that is extremely large.
-TEST(MapsTest, large_file) {
- TemporaryFile tf;
- ASSERT_TRUE(tf.fd != -1);
-
- std::string file_data;
- uint64_t start = 0x700000;
- for (size_t i = 0; i < 5000; i++) {
- file_data +=
- android::base::StringPrintf("%" PRIx64 "-%" PRIx64 " r-xp 1000 00:0 0 /fake%zu.so\n",
- start + i * 4096, start + (i + 1) * 4096, i);
- }
-
- ASSERT_TRUE(android::base::WriteStringToFile(file_data, tf.path, 0660, getuid(), getgid()));
-
- FileMaps maps(tf.path);
-
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(5000U, maps.Total());
- for (size_t i = 0; i < 5000; i++) {
- MapInfo* info = maps.Get(i);
- EXPECT_EQ(start + i * 4096, info->start) << "Failed at map " + std::to_string(i);
- EXPECT_EQ(start + (i + 1) * 4096, info->end) << "Failed at map " + std::to_string(i);
- std::string name = "/fake" + std::to_string(i) + ".so";
- EXPECT_EQ(name, info->name) << "Failed at map " + std::to_string(i);
- }
-}
-
-TEST(MapsTest, find) {
- BufferMaps maps(
- "1000-2000 r--p 00000010 00:00 0 /system/lib/fake1.so\n"
- "3000-4000 -w-p 00000020 00:00 0 /system/lib/fake2.so\n"
- "6000-8000 --xp 00000030 00:00 0 /system/lib/fake3.so\n"
- "a000-b000 rw-p 00000040 00:00 0 /system/lib/fake4.so\n"
- "e000-f000 rwxp 00000050 00:00 0 /system/lib/fake5.so\n");
- ASSERT_TRUE(maps.Parse());
- ASSERT_EQ(5U, maps.Total());
-
- EXPECT_TRUE(maps.Find(0x500) == nullptr);
- EXPECT_TRUE(maps.Find(0x2000) == nullptr);
- EXPECT_TRUE(maps.Find(0x5010) == nullptr);
- EXPECT_TRUE(maps.Find(0x9a00) == nullptr);
- EXPECT_TRUE(maps.Find(0xf000) == nullptr);
- EXPECT_TRUE(maps.Find(0xf010) == nullptr);
-
- MapInfo* info = maps.Find(0x1000);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x1000U, info->start);
- EXPECT_EQ(0x2000U, info->end);
- EXPECT_EQ(0x10U, info->offset);
- EXPECT_EQ(PROT_READ, info->flags);
- EXPECT_EQ("/system/lib/fake1.so", info->name);
-
- info = maps.Find(0x3020);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x3000U, info->start);
- EXPECT_EQ(0x4000U, info->end);
- EXPECT_EQ(0x20U, info->offset);
- EXPECT_EQ(PROT_WRITE, info->flags);
- EXPECT_EQ("/system/lib/fake2.so", info->name);
-
- info = maps.Find(0x6020);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x6000U, info->start);
- EXPECT_EQ(0x8000U, info->end);
- EXPECT_EQ(0x30U, info->offset);
- EXPECT_EQ(PROT_EXEC, info->flags);
- EXPECT_EQ("/system/lib/fake3.so", info->name);
-
- info = maps.Find(0xafff);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0xa000U, info->start);
- EXPECT_EQ(0xb000U, info->end);
- EXPECT_EQ(0x40U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_WRITE, info->flags);
- EXPECT_EQ("/system/lib/fake4.so", info->name);
-
- info = maps.Find(0xe500);
- ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0xe000U, info->start);
- EXPECT_EQ(0xf000U, info->end);
- EXPECT_EQ(0x50U, info->offset);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, info->flags);
- EXPECT_EQ("/system/lib/fake5.so", info->name);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryBufferTest.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
deleted file mode 100644
index a6c12aa..0000000
--- a/libunwindstack/tests/MemoryBufferTest.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "LogFake.h"
-#include "MemoryBuffer.h"
-
-namespace unwindstack {
-
-class MemoryBufferTest : public ::testing::Test {
- protected:
- void SetUp() override {
- ResetLogs();
- memory_.reset(new MemoryBuffer);
- }
- std::unique_ptr<MemoryBuffer> memory_;
-};
-
-TEST_F(MemoryBufferTest, empty) {
- ASSERT_EQ(0U, memory_->Size());
- std::vector<uint8_t> buffer(1024);
- ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 1));
- ASSERT_EQ(nullptr, memory_->GetPtr(0));
- ASSERT_EQ(nullptr, memory_->GetPtr(1));
-}
-
-TEST_F(MemoryBufferTest, write_read) {
- memory_->Resize(256);
- ASSERT_EQ(256U, memory_->Size());
- ASSERT_TRUE(memory_->GetPtr(0) != nullptr);
- ASSERT_TRUE(memory_->GetPtr(1) != nullptr);
- ASSERT_TRUE(memory_->GetPtr(255) != nullptr);
- ASSERT_TRUE(memory_->GetPtr(256) == nullptr);
-
- uint8_t* data = memory_->GetPtr(0);
- for (size_t i = 0; i < memory_->Size(); i++) {
- data[i] = i;
- }
-
- std::vector<uint8_t> buffer(memory_->Size());
- ASSERT_TRUE(memory_->ReadFully(0, buffer.data(), buffer.size()));
- for (size_t i = 0; i < buffer.size(); i++) {
- ASSERT_EQ(i, buffer[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MemoryBufferTest, read_failures) {
- memory_->Resize(100);
- std::vector<uint8_t> buffer(200);
- ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 101));
- ASSERT_FALSE(memory_->ReadFully(100, buffer.data(), 1));
- ASSERT_FALSE(memory_->ReadFully(101, buffer.data(), 2));
- ASSERT_FALSE(memory_->ReadFully(99, buffer.data(), 2));
- ASSERT_TRUE(memory_->ReadFully(99, buffer.data(), 1));
-}
-
-TEST_F(MemoryBufferTest, read_failure_overflow) {
- memory_->Resize(100);
- std::vector<uint8_t> buffer(200);
-
- ASSERT_FALSE(memory_->ReadFully(UINT64_MAX - 100, buffer.data(), 200));
-}
-
-TEST_F(MemoryBufferTest, Read) {
- memory_->Resize(256);
- ASSERT_EQ(256U, memory_->Size());
- ASSERT_TRUE(memory_->GetPtr(0) != nullptr);
- ASSERT_TRUE(memory_->GetPtr(1) != nullptr);
- ASSERT_TRUE(memory_->GetPtr(255) != nullptr);
- ASSERT_TRUE(memory_->GetPtr(256) == nullptr);
-
- uint8_t* data = memory_->GetPtr(0);
- for (size_t i = 0; i < memory_->Size(); i++) {
- data[i] = i;
- }
-
- std::vector<uint8_t> buffer(memory_->Size());
- ASSERT_EQ(128U, memory_->Read(128, buffer.data(), buffer.size()));
- for (size_t i = 0; i < 128; i++) {
- ASSERT_EQ(128 + i, buffer[i]) << "Failed at byte " << i;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
deleted file mode 100644
index 3bd3e4d..0000000
--- a/libunwindstack/tests/MemoryCacheTest.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * 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 <vector>
-
-#include <gtest/gtest.h>
-
-#include "MemoryCache.h"
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class MemoryCacheTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_ = new MemoryFake;
- memory_cache_.reset(new MemoryCache(memory_));
-
- memory_->SetMemoryBlock(0x8000, 4096, 0xab);
- memory_->SetMemoryBlock(0x9000, 4096, 0xde);
- memory_->SetMemoryBlock(0xa000, 3000, 0x50);
- }
-
- MemoryFake* memory_;
- std::unique_ptr<MemoryCache> memory_cache_;
-
- constexpr static size_t kMaxCachedSize = 64;
-};
-
-TEST_F(MemoryCacheTest, cached_read) {
- for (size_t i = 1; i <= kMaxCachedSize; i++) {
- std::vector<uint8_t> buffer(i);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
- << "Read failed at size " << i;
- ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
- }
-
- // Verify the cached data is used.
- memory_->SetMemoryBlock(0x8000, 4096, 0xff);
- for (size_t i = 1; i <= kMaxCachedSize; i++) {
- std::vector<uint8_t> buffer(i);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
- << "Read failed at size " << i;
- ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
- }
-}
-
-TEST_F(MemoryCacheTest, no_cached_read_after_clear) {
- for (size_t i = 1; i <= kMaxCachedSize; i++) {
- std::vector<uint8_t> buffer(i);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
- << "Read failed at size " << i;
- ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
- }
-
- // Verify the cached data is not used after a reset.
- memory_cache_->Clear();
- memory_->SetMemoryBlock(0x8000, 4096, 0xff);
- for (size_t i = 1; i <= kMaxCachedSize; i++) {
- std::vector<uint8_t> buffer(i);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
- << "Read failed at size " << i;
- ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
- }
-}
-
-TEST_F(MemoryCacheTest, cached_read_across_caches) {
- std::vector<uint8_t> expect(16, 0xab);
- expect.resize(32, 0xde);
-
- std::vector<uint8_t> buffer(32);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
- ASSERT_EQ(expect, buffer);
-
- // Verify the cached data is used.
- memory_->SetMemoryBlock(0x8000, 4096, 0xff);
- memory_->SetMemoryBlock(0x9000, 4096, 0xff);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8ff0, buffer.data(), 32));
- ASSERT_EQ(expect, buffer);
-}
-
-TEST_F(MemoryCacheTest, no_cache_read) {
- for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
- std::vector<uint8_t> buffer(i);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
- << "Read failed at size " << i;
- ASSERT_EQ(std::vector<uint8_t>(i, 0xab), buffer) << "Failed at size " << i;
- }
-
- // Verify the cached data is not used.
- memory_->SetMemoryBlock(0x8000, 4096, 0xff);
- for (size_t i = kMaxCachedSize + 1; i < 2 * kMaxCachedSize; i++) {
- std::vector<uint8_t> buffer(i);
- ASSERT_TRUE(memory_cache_->ReadFully(0x8000 + i, buffer.data(), i))
- << "Read failed at size " << i;
- ASSERT_EQ(std::vector<uint8_t>(i, 0xff), buffer) << "Failed at size " << i;
- }
-}
-
-TEST_F(MemoryCacheTest, read_for_cache_fail) {
- std::vector<uint8_t> buffer(kMaxCachedSize);
- ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
- ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0x50), buffer);
-
- // Verify the cached data is not used.
- memory_->SetMemoryBlock(0xa000, 3000, 0xff);
- ASSERT_TRUE(memory_cache_->ReadFully(0xa010, buffer.data(), kMaxCachedSize));
- ASSERT_EQ(std::vector<uint8_t>(kMaxCachedSize, 0xff), buffer);
-}
-
-TEST_F(MemoryCacheTest, read_for_cache_fail_cross) {
- std::vector<uint8_t> expect(16, 0xde);
- expect.resize(32, 0x50);
-
- std::vector<uint8_t> buffer(32);
- ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
- ASSERT_EQ(expect, buffer);
-
- // Verify the cached data is not used for the second half but for the first.
- memory_->SetMemoryBlock(0xa000, 3000, 0xff);
- ASSERT_TRUE(memory_cache_->ReadFully(0x9ff0, buffer.data(), 32));
- expect.resize(16);
- expect.resize(32, 0xff);
- ASSERT_EQ(expect, buffer);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.cpp b/libunwindstack/tests/MemoryFake.cpp
deleted file mode 100644
index 5695dfc..0000000
--- a/libunwindstack/tests/MemoryFake.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-void MemoryFake::SetMemoryBlock(uint64_t addr, size_t length, uint8_t value) {
- for (size_t i = 0; i < length; i++, addr++) {
- auto entry = data_.find(addr);
- if (entry != data_.end()) {
- entry->second = value;
- } else {
- data_.insert({addr, value});
- }
- }
-}
-
-void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) {
- const uint8_t* src = reinterpret_cast<const uint8_t*>(memory);
- for (size_t i = 0; i < length; i++, addr++) {
- auto value = data_.find(addr);
- if (value != data_.end()) {
- value->second = src[i];
- } else {
- data_.insert({ addr, src[i] });
- }
- }
-}
-
-size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) {
- uint8_t* dst = reinterpret_cast<uint8_t*>(memory);
- for (size_t i = 0; i < size; i++, addr++) {
- auto value = data_.find(addr);
- if (value == data_.end()) {
- return i;
- }
- dst[i] = value->second;
- }
- return size;
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryFake.h b/libunwindstack/tests/MemoryFake.h
deleted file mode 100644
index 20610a5..0000000
--- a/libunwindstack/tests/MemoryFake.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
-#define _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-#include <unordered_map>
-
-#include <unwindstack/Memory.h>
-
-namespace unwindstack {
-
-class MemoryFake : public Memory {
- public:
- MemoryFake() = default;
- virtual ~MemoryFake() = default;
-
- size_t Read(uint64_t addr, void* buffer, size_t size) override;
-
- void SetMemory(uint64_t addr, const void* memory, size_t length);
-
- void SetMemoryBlock(uint64_t addr, size_t length, uint8_t value);
-
- void SetData8(uint64_t addr, uint8_t value) {
- SetMemory(addr, &value, sizeof(value));
- }
-
- void SetData16(uint64_t addr, uint16_t value) {
- SetMemory(addr, &value, sizeof(value));
- }
-
- void SetData32(uint64_t addr, uint32_t value) {
- SetMemory(addr, &value, sizeof(value));
- }
-
- void SetData64(uint64_t addr, uint64_t value) {
- SetMemory(addr, &value, sizeof(value));
- }
-
- void SetMemory(uint64_t addr, std::vector<uint8_t> values) {
- SetMemory(addr, values.data(), values.size());
- }
-
- void SetMemory(uint64_t addr, std::string string) {
- SetMemory(addr, string.c_str(), string.size() + 1);
- }
-
- void Clear() { data_.clear(); }
-
- private:
- std::unordered_map<uint64_t, uint8_t> data_;
-};
-
-class MemoryFakeAlwaysReadZero : public Memory {
- public:
- MemoryFakeAlwaysReadZero() = default;
- virtual ~MemoryFakeAlwaysReadZero() = default;
-
- size_t Read(uint64_t, void* buffer, size_t size) override {
- memset(buffer, 0, size);
- return size;
- }
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_MEMORY_FAKE_H
diff --git a/libunwindstack/tests/MemoryFileTest.cpp b/libunwindstack/tests/MemoryFileTest.cpp
deleted file mode 100644
index 4124a49..0000000
--- a/libunwindstack/tests/MemoryFileTest.cpp
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-#include <vector>
-
-#include <android-base/test_utils.h>
-#include <android-base/file.h>
-#include <gtest/gtest.h>
-
-#include "MemoryFileAtOffset.h"
-
-namespace unwindstack {
-
-class MemoryFileTest : public ::testing::Test {
- protected:
- void SetUp() override {
- tf_ = new TemporaryFile;
- }
-
- void TearDown() override {
- delete tf_;
- }
-
- void WriteTestData() {
- ASSERT_TRUE(android::base::WriteStringToFd("0123456789abcdefghijklmnopqrstuvxyz", tf_->fd));
- }
-
- MemoryFileAtOffset memory_;
-
- TemporaryFile* tf_ = nullptr;
-};
-
-TEST_F(MemoryFileTest, init_offset_0) {
- WriteTestData();
-
- ASSERT_TRUE(memory_.Init(tf_->path, 0));
- std::vector<char> buffer(11);
- ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
- buffer[10] = '\0';
- ASSERT_STREQ("0123456789", buffer.data());
-}
-
-TEST_F(MemoryFileTest, init_offset_non_zero) {
- WriteTestData();
-
- ASSERT_TRUE(memory_.Init(tf_->path, 10));
- std::vector<char> buffer(11);
- ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
- buffer[10] = '\0';
- ASSERT_STREQ("abcdefghij", buffer.data());
-}
-
-TEST_F(MemoryFileTest, init_offset_non_zero_larger_than_pagesize) {
- size_t pagesize = getpagesize();
- std::string large_string;
- for (size_t i = 0; i < pagesize; i++) {
- large_string += '1';
- }
- large_string += "012345678901234abcdefgh";
- ASSERT_TRUE(android::base::WriteStringToFd(large_string, tf_->fd));
-
- ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 15));
- std::vector<char> buffer(9);
- ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 8));
- buffer[8] = '\0';
- ASSERT_STREQ("abcdefgh", buffer.data());
-}
-
-TEST_F(MemoryFileTest, init_offset_pagesize_aligned) {
- size_t pagesize = getpagesize();
- std::string data;
- for (size_t i = 0; i < 2 * pagesize; i++) {
- data += static_cast<char>((i / pagesize) + '0');
- data += static_cast<char>((i % 10) + '0');
- }
- ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
-
- ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize));
- std::vector<char> buffer(11);
- ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
- buffer[10] = '\0';
- std::string expected_str;
- for (size_t i = 0; i < 5; i++) {
- expected_str += '1';
- expected_str += static_cast<char>(((i + pagesize) % 10) + '0');
- }
- ASSERT_STREQ(expected_str.c_str(), buffer.data());
-}
-
-TEST_F(MemoryFileTest, init_offset_pagesize_aligned_plus_extra) {
- size_t pagesize = getpagesize();
- std::string data;
- for (size_t i = 0; i < 2 * pagesize; i++) {
- data += static_cast<char>((i / pagesize) + '0');
- data += static_cast<char>((i % 10) + '0');
- }
- ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
-
- ASSERT_TRUE(memory_.Init(tf_->path, 2 * pagesize + 10));
- std::vector<char> buffer(11);
- ASSERT_TRUE(memory_.ReadFully(0, buffer.data(), 10));
- buffer[10] = '\0';
- std::string expected_str;
- for (size_t i = 0; i < 5; i++) {
- expected_str += '1';
- expected_str += static_cast<char>(((i + pagesize + 5) % 10) + '0');
- }
- ASSERT_STREQ(expected_str.c_str(), buffer.data());
-}
-
-TEST_F(MemoryFileTest, init_offset_greater_than_filesize) {
- size_t pagesize = getpagesize();
- std::string data;
- uint64_t file_size = 2 * pagesize + pagesize / 2;
- for (size_t i = 0; i < file_size; i++) {
- data += static_cast<char>((i / pagesize) + '0');
- }
- ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
-
- // Check offset > file size fails and aligned_offset > file size.
- ASSERT_FALSE(memory_.Init(tf_->path, file_size + 2 * pagesize));
- // Check offset == filesize fails.
- ASSERT_FALSE(memory_.Init(tf_->path, file_size));
- // Check aligned_offset < filesize, but offset > filesize fails.
- ASSERT_FALSE(memory_.Init(tf_->path, 2 * pagesize + pagesize / 2 + pagesize / 4));
-}
-
-TEST_F(MemoryFileTest, read_error) {
- std::string data;
- for (size_t i = 0; i < 5000; i++) {
- data += static_cast<char>((i % 10) + '0');
- }
- ASSERT_TRUE(android::base::WriteStringToFd(data, tf_->fd));
-
- std::vector<char> buffer(100);
-
- // Read before init.
- ASSERT_FALSE(memory_.ReadFully(0, buffer.data(), 10));
-
- ASSERT_TRUE(memory_.Init(tf_->path, 0));
-
- ASSERT_FALSE(memory_.ReadFully(10000, buffer.data(), 10));
- ASSERT_FALSE(memory_.ReadFully(5000, buffer.data(), 10));
- ASSERT_FALSE(memory_.ReadFully(4990, buffer.data(), 11));
- ASSERT_TRUE(memory_.ReadFully(4990, buffer.data(), 10));
- ASSERT_FALSE(memory_.ReadFully(4999, buffer.data(), 2));
- ASSERT_TRUE(memory_.ReadFully(4999, buffer.data(), 1));
-
- // Check that overflow fails properly.
- ASSERT_FALSE(memory_.ReadFully(UINT64_MAX - 100, buffer.data(), 200));
-}
-
-TEST_F(MemoryFileTest, read_past_file_within_mapping) {
- size_t pagesize = getpagesize();
-
- ASSERT_TRUE(pagesize > 100);
- std::vector<uint8_t> buffer(pagesize - 100);
- for (size_t i = 0; i < pagesize - 100; i++) {
- buffer[i] = static_cast<uint8_t>((i % 0x5e) + 0x20);
- }
- ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
-
- ASSERT_TRUE(memory_.Init(tf_->path, 0));
-
- for (size_t i = 0; i < 100; i++) {
- uint8_t value;
- ASSERT_FALSE(memory_.ReadFully(buffer.size() + i, &value, 1))
- << "Should have failed at value " << i;
- }
-}
-
-TEST_F(MemoryFileTest, map_partial_offset_aligned) {
- size_t pagesize = getpagesize();
- std::vector<uint8_t> buffer(pagesize * 10);
- for (size_t i = 0; i < pagesize * 10; i++) {
- buffer[i] = i / pagesize + 1;
- }
- ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
-
- // Map in only two pages of the data, and after the first page.
- ASSERT_TRUE(memory_.Init(tf_->path, pagesize, pagesize * 2));
-
- std::vector<uint8_t> read_buffer(pagesize * 2);
- // Make sure that reading after mapped data is a failure.
- ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
- ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
- for (size_t i = 0; i < pagesize; i++) {
- ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
- }
- for (size_t i = pagesize; i < pagesize * 2; i++) {
- ASSERT_EQ(3, read_buffer[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MemoryFileTest, map_partial_offset_unaligned) {
- size_t pagesize = getpagesize();
- ASSERT_TRUE(pagesize > 0x100);
- std::vector<uint8_t> buffer(pagesize * 10);
- for (size_t i = 0; i < buffer.size(); i++) {
- buffer[i] = i / pagesize + 1;
- }
- ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
-
- // Map in only two pages of the data, and after the first page.
- ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, pagesize * 2));
-
- std::vector<uint8_t> read_buffer(pagesize * 2);
- // Make sure that reading after mapped data is a failure.
- ASSERT_FALSE(memory_.ReadFully(pagesize * 2, read_buffer.data(), 1));
- ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 2));
- for (size_t i = 0; i < pagesize - 0x100; i++) {
- ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
- }
- for (size_t i = pagesize - 0x100; i < 2 * pagesize - 0x100; i++) {
- ASSERT_EQ(3, read_buffer[i]) << "Failed at byte " << i;
- }
- for (size_t i = 2 * pagesize - 0x100; i < pagesize * 2; i++) {
- ASSERT_EQ(4, read_buffer[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MemoryFileTest, map_overflow) {
- size_t pagesize = getpagesize();
- ASSERT_TRUE(pagesize > 0x100);
- std::vector<uint8_t> buffer(pagesize * 10);
- for (size_t i = 0; i < buffer.size(); i++) {
- buffer[i] = i / pagesize + 1;
- }
- ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
-
- // Map in only two pages of the data, and after the first page.
- ASSERT_TRUE(memory_.Init(tf_->path, pagesize + 0x100, UINT64_MAX));
-
- std::vector<uint8_t> read_buffer(pagesize * 10);
- ASSERT_FALSE(memory_.ReadFully(pagesize * 9 - 0x100 + 1, read_buffer.data(), 1));
- ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize * 9 - 0x100));
-}
-
-TEST_F(MemoryFileTest, init_reinit) {
- size_t pagesize = getpagesize();
- std::vector<uint8_t> buffer(pagesize * 2);
- for (size_t i = 0; i < buffer.size(); i++) {
- buffer[i] = i / pagesize + 1;
- }
- ASSERT_TRUE(android::base::WriteFully(tf_->fd, buffer.data(), buffer.size()));
-
- ASSERT_TRUE(memory_.Init(tf_->path, 0));
- std::vector<uint8_t> read_buffer(buffer.size());
- ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
- for (size_t i = 0; i < pagesize; i++) {
- ASSERT_EQ(1, read_buffer[i]) << "Failed at byte " << i;
- }
-
- // Now reinit.
- ASSERT_TRUE(memory_.Init(tf_->path, pagesize));
- ASSERT_TRUE(memory_.ReadFully(0, read_buffer.data(), pagesize));
- for (size_t i = 0; i < pagesize; i++) {
- ASSERT_EQ(2, read_buffer[i]) << "Failed at byte " << i;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryLocalTest.cpp b/libunwindstack/tests/MemoryLocalTest.cpp
deleted file mode 100644
index c9e5dc0..0000000
--- a/libunwindstack/tests/MemoryLocalTest.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2017 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 <string.h>
-#include <sys/mman.h>
-
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "MemoryLocal.h"
-
-namespace unwindstack {
-
-TEST(MemoryLocalTest, read) {
- std::vector<uint8_t> src(1024);
- memset(src.data(), 0x4c, 1024);
-
- MemoryLocal local;
-
- std::vector<uint8_t> dst(1024);
- ASSERT_TRUE(local.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
- ASSERT_EQ(0, memcmp(src.data(), dst.data(), 1024));
- for (size_t i = 0; i < 1024; i++) {
- ASSERT_EQ(0x4cU, dst[i]);
- }
-
- memset(src.data(), 0x23, 512);
- ASSERT_TRUE(local.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
- ASSERT_EQ(0, memcmp(src.data(), dst.data(), 1024));
- for (size_t i = 0; i < 512; i++) {
- ASSERT_EQ(0x23U, dst[i]);
- }
- for (size_t i = 512; i < 1024; i++) {
- ASSERT_EQ(0x4cU, dst[i]);
- }
-}
-
-TEST(MemoryLocalTest, read_illegal) {
- MemoryLocal local;
-
- std::vector<uint8_t> dst(100);
- ASSERT_FALSE(local.ReadFully(0, dst.data(), 1));
- ASSERT_FALSE(local.ReadFully(0, dst.data(), 100));
-}
-
-TEST(MemoryLocalTest, read_overflow) {
- MemoryLocal local;
-
- // On 32 bit this test doesn't necessarily cause an overflow. The 64 bit
- // version will always go through the overflow check.
- std::vector<uint8_t> dst(100);
- uint64_t value;
- ASSERT_FALSE(local.ReadFully(reinterpret_cast<uint64_t>(&value), dst.data(), SIZE_MAX));
-}
-
-TEST(MemoryLocalTest, Read) {
- char* mapping = static_cast<char*>(
- mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
-
- ASSERT_NE(MAP_FAILED, mapping);
-
- mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE);
- memset(mapping + getpagesize() - 1024, 0x4c, 1024);
-
- MemoryLocal local;
-
- std::vector<uint8_t> dst(4096);
- ASSERT_EQ(1024U, local.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024),
- dst.data(), 4096));
- for (size_t i = 0; i < 1024; i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-
- ASSERT_EQ(0, munmap(mapping, 2 * getpagesize()));
-}
-
-TEST(MemoryLocalTest, read_hole) {
- void* mapping =
- mmap(nullptr, 3 * 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, mapping);
- memset(mapping, 0xFF, 3 * 4096);
- mprotect(static_cast<char*>(mapping) + 4096, 4096, PROT_NONE);
-
- MemoryLocal local;
- std::vector<uint8_t> dst(4096 * 3, 0xCC);
- ASSERT_EQ(4096U, local.Read(reinterpret_cast<uintptr_t>(mapping), dst.data(), 4096 * 3));
- for (size_t i = 0; i < 4096; ++i) {
- ASSERT_EQ(0xFF, dst[i]);
- }
- for (size_t i = 4096; i < 4096 * 3; ++i) {
- ASSERT_EQ(0xCC, dst[i]);
- }
- ASSERT_EQ(0, munmap(mapping, 3 * 4096));
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryMteTest.cpp b/libunwindstack/tests/MemoryMteTest.cpp
deleted file mode 100644
index 3ae322e..0000000
--- a/libunwindstack/tests/MemoryMteTest.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#if defined(ANDROID_EXPERIMENTAL_MTE)
-
-#include <sys/mman.h>
-#include <sys/types.h>
-
-#include <gtest/gtest.h>
-
-#include <bionic/mte.h>
-
-#include "MemoryLocal.h"
-#include "MemoryRemote.h"
-#include "TestUtils.h"
-
-namespace unwindstack {
-
-static uintptr_t CreateTagMapping() {
- uintptr_t mapping =
- reinterpret_cast<uintptr_t>(mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_MTE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
- if (reinterpret_cast<void*>(mapping) == MAP_FAILED) {
- return 0;
- }
-#if defined(__aarch64__)
- __asm__ __volatile__(".arch_extension mte; stg %0, [%0]"
- :
- : "r"(mapping + (1ULL << 56))
- : "memory");
-#endif
- return mapping;
-}
-
-TEST(MemoryMteTest, remote_read_tag) {
-#if !defined(__aarch64__)
- GTEST_SKIP() << "Requires aarch64";
-#else
- if (!mte_supported()) {
- GTEST_SKIP() << "Requires MTE";
- }
-#endif
-
- uintptr_t mapping = CreateTagMapping();
- ASSERT_NE(0U, mapping);
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true)
- ;
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
-
- EXPECT_EQ(1, remote.ReadTag(mapping));
- EXPECT_EQ(0, remote.ReadTag(mapping + 16));
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryMteTest, local_read_tag) {
-#if !defined(__aarch64__)
- GTEST_SKIP() << "Requires aarch64";
-#else
- if (!mte_supported()) {
- GTEST_SKIP() << "Requires MTE";
- }
-#endif
-
- uintptr_t mapping = CreateTagMapping();
- ASSERT_NE(0U, mapping);
-
- MemoryLocal local;
-
- EXPECT_EQ(1, local.ReadTag(mapping));
- EXPECT_EQ(0, local.ReadTag(mapping + 16));
-}
-
-} // namespace unwindstack
-
-#endif
diff --git a/libunwindstack/tests/MemoryOfflineBufferTest.cpp b/libunwindstack/tests/MemoryOfflineBufferTest.cpp
deleted file mode 100644
index 9531708..0000000
--- a/libunwindstack/tests/MemoryOfflineBufferTest.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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 <vector>
-
-#include <gtest/gtest.h>
-
-#include "LogFake.h"
-#include "MemoryOfflineBuffer.h"
-
-namespace unwindstack {
-
-class MemoryOfflineBufferTest : public ::testing::Test {
- protected:
- void SetUp() override {
- ResetLogs();
- memory_.reset(new MemoryOfflineBuffer(buffer_.data(), kStart, kEnd));
- }
-
- static void SetUpTestSuite() {
- buffer_.resize(kLength);
- for (size_t i = 0; i < kLength; i++) {
- buffer_[i] = i % 189;
- }
- }
-
- std::unique_ptr<MemoryOfflineBuffer> memory_;
-
- static constexpr size_t kLength = 0x2000;
- static constexpr uint64_t kStart = 0x1000;
- static constexpr uint64_t kEnd = kStart + kLength;
- static std::vector<uint8_t> buffer_;
-};
-
-std::vector<uint8_t> MemoryOfflineBufferTest::buffer_;
-
-static void VerifyBuffer(uint8_t* buffer, size_t start_value, size_t length) {
- for (size_t i = 0; i < length; i++) {
- ASSERT_EQ((start_value + i) % 189, buffer[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MemoryOfflineBufferTest, read_out_of_bounds) {
- std::vector<uint8_t> buffer(1024);
- ASSERT_FALSE(memory_->ReadFully(0, buffer.data(), 1));
- ASSERT_FALSE(memory_->ReadFully(0xfff, buffer.data(), 1));
- ASSERT_FALSE(memory_->ReadFully(0xfff, buffer.data(), 2));
- ASSERT_FALSE(memory_->ReadFully(0x3000, buffer.data(), 1));
- ASSERT_FALSE(memory_->ReadFully(0x3001, buffer.data(), 1));
-}
-
-TEST_F(MemoryOfflineBufferTest, read) {
- std::vector<uint8_t> buffer(1024);
- ASSERT_TRUE(memory_->ReadFully(kStart, buffer.data(), 10));
- ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 0, 10));
-
- ASSERT_TRUE(memory_->ReadFully(kStart + 555, buffer.data(), 40));
- ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 555, 40));
-
- ASSERT_TRUE(memory_->ReadFully(kStart + kLength - 105, buffer.data(), 105));
- ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), kLength - 105, 105));
-}
-
-TEST_F(MemoryOfflineBufferTest, read_past_end) {
- std::vector<uint8_t> buffer(1024);
- ASSERT_EQ(100U, memory_->Read(kStart + kLength - 100, buffer.data(), buffer.size()));
- VerifyBuffer(buffer.data(), kLength - 100, 100);
-}
-
-TEST_F(MemoryOfflineBufferTest, read_after_reset) {
- std::vector<uint8_t> buffer(1024);
- ASSERT_TRUE(memory_->ReadFully(kStart, buffer.data(), 100));
- ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 0, 100));
-
- memory_->Reset(&buffer_[10], 0x12000, 0x13000);
- ASSERT_TRUE(memory_->ReadFully(0x12000, buffer.data(), 100));
- ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 10, 100));
-
- ASSERT_EQ(50U, memory_->Read(0x13000 - 50, buffer.data(), buffer.size()));
- ASSERT_NO_FATAL_FAILURE(VerifyBuffer(buffer.data(), 0x1000 - 50 + 10, 50));
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryOfflineTest.cpp b/libunwindstack/tests/MemoryOfflineTest.cpp
deleted file mode 100644
index d0c441b..0000000
--- a/libunwindstack/tests/MemoryOfflineTest.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2017 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 <vector>
-
-#include <gtest/gtest.h>
-
-#include <android-base/file.h>
-
-#include "MemoryOffline.h"
-
-namespace unwindstack {
-
-class MemoryOfflineTest : public ::testing::Test {
- protected:
- void SetUp() override {
- for (size_t i = 0; i < 1024; ++i) {
- data.push_back(i & 0xff);
- }
-
- ASSERT_TRUE(android::base::WriteFully(temp_file.fd, &offset, sizeof(offset)));
- ASSERT_TRUE(android::base::WriteFully(temp_file.fd, data.data(), data.size()));
-
- memory = std::make_unique<MemoryOffline>();
- ASSERT_TRUE(memory != nullptr);
-
- ASSERT_TRUE(memory->Init(temp_file.path, 0));
- }
-
- TemporaryFile temp_file;
- uint64_t offset = 4096;
- std::vector<char> data;
- std::unique_ptr<MemoryOffline> memory;
-};
-
-TEST_F(MemoryOfflineTest, read_boundaries) {
- char buf = '\0';
- ASSERT_EQ(0U, memory->Read(offset - 1, &buf, 1));
- ASSERT_EQ(0U, memory->Read(offset + data.size(), &buf, 1));
- ASSERT_EQ(1U, memory->Read(offset, &buf, 1));
- ASSERT_EQ(buf, data.front());
- ASSERT_EQ(1U, memory->Read(offset + data.size() - 1, &buf, 1));
- ASSERT_EQ(buf, data.back());
-}
-
-TEST_F(MemoryOfflineTest, read_values) {
- std::vector<char> buf;
- buf.resize(2 * data.size());
- ASSERT_EQ(data.size(), memory->Read(offset, buf.data(), buf.size()));
- buf.resize(data.size());
- ASSERT_EQ(buf, data);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
deleted file mode 100644
index 2d4f141..0000000
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2017 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 <memory>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "MemoryFake.h"
-#include "MemoryRange.h"
-
-namespace unwindstack {
-
-class MemoryRangeTest : public ::testing::Test {
- protected:
- void SetUp() override {
- process_memory_.reset();
- memory_fake_ = new MemoryFake;
- process_memory_.reset(memory_fake_);
- }
-
- std::shared_ptr<Memory> process_memory_;
- MemoryFake* memory_fake_ = nullptr;
-};
-
-TEST_F(MemoryRangeTest, read_fully) {
- memory_fake_->SetMemoryBlock(9000, 2048, 0x4c);
-
- MemoryRange range(process_memory_, 9001, 1024, 0);
-
- std::vector<uint8_t> dst(1024);
- ASSERT_TRUE(range.ReadFully(0, dst.data(), dst.size()));
- for (size_t i = 0; i < dst.size(); i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MemoryRangeTest, read_fully_near_limit) {
- memory_fake_->SetMemoryBlock(0, 8192, 0x4c);
-
- MemoryRange range(process_memory_, 1000, 1024, 0);
-
- std::vector<uint8_t> dst(1024);
- ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
- for (size_t i = 0; i < 4; i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-
- // Verify that reads outside of the range will fail.
- ASSERT_FALSE(range.ReadFully(1020, dst.data(), 5));
- ASSERT_FALSE(range.ReadFully(1024, dst.data(), 1));
- ASSERT_FALSE(range.ReadFully(1024, dst.data(), 1024));
-
- // Verify that reading up to the end works.
- ASSERT_TRUE(range.ReadFully(1020, dst.data(), 4));
-}
-
-TEST_F(MemoryRangeTest, read_fully_overflow) {
- std::vector<uint8_t> buffer(100);
-
- std::shared_ptr<Memory> process_memory(new MemoryFakeAlwaysReadZero);
- std::unique_ptr<MemoryRange> overflow(new MemoryRange(process_memory, 100, 200, 0));
- ASSERT_FALSE(overflow->ReadFully(UINT64_MAX - 10, buffer.data(), 100));
-}
-
-TEST_F(MemoryRangeTest, read) {
- memory_fake_->SetMemoryBlock(0, 4096, 0x4c);
-
- MemoryRange range(process_memory_, 1000, 1024, 0);
-
- std::vector<uint8_t> dst(1024);
- ASSERT_EQ(4U, range.Read(1020, dst.data(), dst.size()));
- for (size_t i = 0; i < 4; i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MemoryRangeTest, read_non_zero_offset) {
- memory_fake_->SetMemoryBlock(1000, 1024, 0x12);
-
- MemoryRange range(process_memory_, 1000, 1024, 400);
-
- std::vector<uint8_t> dst(1024);
- ASSERT_EQ(1024U, range.Read(400, dst.data(), dst.size()));
- for (size_t i = 0; i < dst.size(); i++) {
- ASSERT_EQ(0x12U, dst[i]) << "Failed at byte " << i;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRangesTest.cpp b/libunwindstack/tests/MemoryRangesTest.cpp
deleted file mode 100644
index e4e9fc4..0000000
--- a/libunwindstack/tests/MemoryRangesTest.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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 <vector>
-
-#include <gtest/gtest.h>
-
-#include "MemoryFake.h"
-#include "MemoryRange.h"
-
-namespace unwindstack {
-
-class MemoryRangesTest : public ::testing::Test {
- protected:
- void SetUp() override {
- MemoryFake* memory = new MemoryFake;
- process_memory_.reset(memory);
- memory->SetMemoryBlock(1000, 5000, 0x15);
- memory->SetMemoryBlock(6000, 12000, 0x26);
- memory->SetMemoryBlock(14000, 20000, 0x37);
- memory->SetMemoryBlock(20000, 22000, 0x48);
-
- ranges_.reset(new MemoryRanges);
- ranges_->Insert(new MemoryRange(process_memory_, 15000, 100, 4000));
- ranges_->Insert(new MemoryRange(process_memory_, 10000, 2000, 2000));
- ranges_->Insert(new MemoryRange(process_memory_, 3000, 1000, 0));
- ranges_->Insert(new MemoryRange(process_memory_, 19000, 1000, 6000));
- ranges_->Insert(new MemoryRange(process_memory_, 20000, 1000, 7000));
- }
-
- std::shared_ptr<Memory> process_memory_;
- std::unique_ptr<MemoryRanges> ranges_;
-};
-
-TEST_F(MemoryRangesTest, read) {
- std::vector<uint8_t> dst(2000);
- size_t bytes = ranges_->Read(0, dst.data(), dst.size());
- ASSERT_EQ(1000UL, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x15U, dst[i]) << "Failed at byte " << i;
- }
-
- bytes = ranges_->Read(2000, dst.data(), dst.size());
- ASSERT_EQ(2000UL, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x26U, dst[i]) << "Failed at byte " << i;
- }
-
- bytes = ranges_->Read(4000, dst.data(), dst.size());
- ASSERT_EQ(100UL, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x37U, dst[i]) << "Failed at byte " << i;
- }
-}
-
-TEST_F(MemoryRangesTest, read_fail) {
- std::vector<uint8_t> dst(4096);
- ASSERT_EQ(0UL, ranges_->Read(1000, dst.data(), dst.size()));
- ASSERT_EQ(0UL, ranges_->Read(5000, dst.data(), dst.size()));
- ASSERT_EQ(0UL, ranges_->Read(8000, dst.data(), dst.size()));
-}
-
-TEST_F(MemoryRangesTest, read_across_ranges) {
- // The MemoryRanges object does not support reading across a range,
- // so this will only read in the first range.
- std::vector<uint8_t> dst(4096);
- size_t bytes = ranges_->Read(6000, dst.data(), dst.size());
- ASSERT_EQ(1000UL, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x37U, dst[i]) << "Failed at byte " << i;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
deleted file mode 100644
index 621893b..0000000
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/test_utils.h>
-#include <gtest/gtest.h>
-
-#include "MemoryRemote.h"
-
-#include "MemoryFake.h"
-#include "TestUtils.h"
-
-namespace unwindstack {
-
-TEST(MemoryRemoteTest, read) {
- std::vector<uint8_t> src(1024);
- memset(src.data(), 0x4c, 1024);
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true);
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
-
- std::vector<uint8_t> dst(1024);
- ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), 1024));
- for (size_t i = 0; i < 1024; i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryRemoteTest, read_large) {
- static constexpr size_t kTotalPages = 245;
- std::vector<uint8_t> src(kTotalPages * getpagesize());
- for (size_t i = 0; i < kTotalPages; i++) {
- memset(&src[i * getpagesize()], i, getpagesize());
- }
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true)
- ;
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
-
- std::vector<uint8_t> dst(kTotalPages * getpagesize());
- ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src.data()), dst.data(), src.size()));
- for (size_t i = 0; i < kTotalPages * getpagesize(); i++) {
- ASSERT_EQ(i / getpagesize(), dst[i]) << "Failed at byte " << i;
- }
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryRemoteTest, read_partial) {
- char* mapping = static_cast<char*>(
- mmap(nullptr, 4 * getpagesize(), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
- ASSERT_NE(MAP_FAILED, mapping);
- memset(mapping, 0x4c, 4 * getpagesize());
- ASSERT_EQ(0, mprotect(mapping + getpagesize(), getpagesize(), PROT_NONE));
- ASSERT_EQ(0, munmap(mapping + 3 * getpagesize(), getpagesize()));
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true)
- ;
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- // Unmap from our process.
- ASSERT_EQ(0, munmap(mapping, 3 * getpagesize()));
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
-
- std::vector<uint8_t> dst(4096);
- size_t bytes =
- remote.Read(reinterpret_cast<uint64_t>(mapping + getpagesize() - 1024), dst.data(), 4096);
- // Some read methods can read PROT_NONE maps, allow that.
- ASSERT_LE(1024U, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-
- // Now verify that reading stops at the end of a map.
- bytes =
- remote.Read(reinterpret_cast<uint64_t>(mapping + 3 * getpagesize() - 1024), dst.data(), 4096);
- ASSERT_EQ(1024U, bytes);
- for (size_t i = 0; i < bytes; i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryRemoteTest, read_fail) {
- int pagesize = getpagesize();
- void* src = mmap(nullptr, pagesize * 2, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,-1, 0);
- memset(src, 0x4c, pagesize * 2);
- ASSERT_NE(MAP_FAILED, src);
- // Put a hole right after the first page.
- ASSERT_EQ(0, munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(src) + pagesize),
- pagesize));
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true);
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
-
- std::vector<uint8_t> dst(pagesize);
- ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src), dst.data(), pagesize));
- for (size_t i = 0; i < 1024; i++) {
- ASSERT_EQ(0x4cU, dst[i]) << "Failed at byte " << i;
- }
-
- ASSERT_FALSE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize, dst.data(), 1));
- ASSERT_TRUE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize - 1, dst.data(), 1));
- ASSERT_FALSE(remote.ReadFully(reinterpret_cast<uint64_t>(src) + pagesize - 4, dst.data(), 8));
-
- // Check overflow condition is caught properly.
- ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
-
- ASSERT_EQ(0, munmap(src, pagesize));
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryRemoteTest, read_overflow) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true)
- ;
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
-
- // Check overflow condition is caught properly.
- std::vector<uint8_t> dst(200);
- ASSERT_FALSE(remote.ReadFully(UINT64_MAX - 100, dst.data(), 200));
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryRemoteTest, read_illegal) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true);
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
-
- std::vector<uint8_t> dst(100);
- ASSERT_FALSE(remote.ReadFully(0, dst.data(), 1));
- ASSERT_FALSE(remote.ReadFully(0, dst.data(), 100));
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryRemoteTest, read_mprotect_hole) {
- size_t page_size = getpagesize();
- void* mapping =
- mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, mapping);
- memset(mapping, 0xFF, 3 * page_size);
- ASSERT_EQ(0, mprotect(static_cast<char*>(mapping) + page_size, page_size, PROT_NONE));
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true);
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_EQ(0, munmap(mapping, 3 * page_size));
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
- std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
- size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
- // Some read methods can read PROT_NONE maps, allow that.
- ASSERT_LE(page_size, read_size);
- for (size_t i = 0; i < read_size; ++i) {
- ASSERT_EQ(0xFF, dst[i]);
- }
- for (size_t i = read_size; i < dst.size(); ++i) {
- ASSERT_EQ(0xCC, dst[i]);
- }
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-TEST(MemoryRemoteTest, read_munmap_hole) {
- size_t page_size = getpagesize();
- void* mapping =
- mmap(nullptr, 3 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, mapping);
- memset(mapping, 0xFF, 3 * page_size);
- ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + page_size, page_size));
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true)
- ;
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_EQ(0, munmap(mapping, page_size));
- ASSERT_EQ(0, munmap(static_cast<char*>(mapping) + 2 * page_size, page_size));
-
- ASSERT_TRUE(TestAttach(pid));
-
- MemoryRemote remote(pid);
- std::vector<uint8_t> dst(getpagesize() * 4, 0xCC);
- size_t read_size = remote.Read(reinterpret_cast<uint64_t>(mapping), dst.data(), page_size * 3);
- ASSERT_EQ(page_size, read_size);
- for (size_t i = 0; i < read_size; ++i) {
- ASSERT_EQ(0xFF, dst[i]);
- }
- for (size_t i = read_size; i < dst.size(); ++i) {
- ASSERT_EQ(0xCC, dst[i]);
- }
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-// Verify that the memory remote object chooses a memory read function
-// properly. Either process_vm_readv or ptrace.
-TEST(MemoryRemoteTest, read_choose_correctly) {
- size_t page_size = getpagesize();
- void* mapping =
- mmap(nullptr, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
- ASSERT_NE(MAP_FAILED, mapping);
- memset(mapping, 0xFC, 2 * page_size);
- ASSERT_EQ(0, mprotect(static_cast<char*>(mapping), page_size, PROT_NONE));
-
- pid_t pid;
- if ((pid = fork()) == 0) {
- while (true)
- ;
- exit(1);
- }
- ASSERT_LT(0, pid);
- TestScopedPidReaper reap(pid);
-
- ASSERT_EQ(0, munmap(mapping, 2 * page_size));
-
- ASSERT_TRUE(TestAttach(pid));
-
- // We know that process_vm_readv of a mprotect'd PROT_NONE region will fail.
- // Read from the PROT_NONE area first to force the choice of ptrace.
- MemoryRemote remote_ptrace(pid);
- uint32_t value;
- size_t bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
- ASSERT_EQ(sizeof(value), bytes);
- ASSERT_EQ(0xfcfcfcfcU, value);
- bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
- ASSERT_EQ(sizeof(value), bytes);
- ASSERT_EQ(0xfcfcfcfcU, value);
- bytes = remote_ptrace.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
- ASSERT_EQ(sizeof(value), bytes);
- ASSERT_EQ(0xfcfcfcfcU, value);
-
- // Now verify that choosing process_vm_readv results in failing reads of
- // the PROT_NONE part of the map. Read from a valid map first which
- // should prefer process_vm_readv, and keep that as the read function.
- MemoryRemote remote_readv(pid);
- bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
- ASSERT_EQ(sizeof(value), bytes);
- ASSERT_EQ(0xfcfcfcfcU, value);
- bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping), &value, sizeof(value));
- ASSERT_EQ(0U, bytes);
- bytes = remote_readv.Read(reinterpret_cast<uint64_t>(mapping) + page_size, &value, sizeof(value));
- ASSERT_EQ(sizeof(value), bytes);
- ASSERT_EQ(0xfcfcfcfcU, value);
-
- ASSERT_TRUE(TestDetach(pid));
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/MemoryTest.cpp b/libunwindstack/tests/MemoryTest.cpp
deleted file mode 100644
index 8a8eb24..0000000
--- a/libunwindstack/tests/MemoryTest.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2017 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 <string.h>
-
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Memory.h>
-
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-TEST(MemoryTest, read32) {
- MemoryFakeAlwaysReadZero memory;
-
- uint32_t data = 0xffffffff;
- ASSERT_TRUE(memory.Read32(0, &data));
- ASSERT_EQ(0U, data);
-}
-
-TEST(MemoryTest, read64) {
- MemoryFakeAlwaysReadZero memory;
-
- uint64_t data = 0xffffffffffffffffULL;
- ASSERT_TRUE(memory.Read64(0, &data));
- ASSERT_EQ(0U, data);
-}
-
-struct FakeStruct {
- int one;
- bool two;
- uint32_t three;
- uint64_t four;
-};
-
-TEST(MemoryTest, read_string) {
- std::string name("string_in_memory");
-
- MemoryFake memory;
-
- memory.SetMemory(100, name.c_str(), name.size() + 1);
-
- std::string dst_name;
- ASSERT_TRUE(memory.ReadString(100, &dst_name, 100));
- ASSERT_EQ("string_in_memory", dst_name);
-
- ASSERT_TRUE(memory.ReadString(107, &dst_name, 100));
- ASSERT_EQ("in_memory", dst_name);
-
- // Set size greater than string.
- ASSERT_TRUE(memory.ReadString(107, &dst_name, 10));
- ASSERT_EQ("in_memory", dst_name);
-
- ASSERT_FALSE(memory.ReadString(107, &dst_name, 9));
-}
-
-TEST(MemoryTest, read_string_error) {
- std::string name("short");
-
- MemoryFake memory;
-
- // Save everything except the terminating '\0'.
- memory.SetMemory(0, name.c_str(), name.size());
-
- std::string dst_name;
- // Read from a non-existant address.
- ASSERT_FALSE(memory.ReadString(100, &dst_name, 100));
-
- // This should fail because there is no terminating '\0'.
- ASSERT_FALSE(memory.ReadString(0, &dst_name, 100));
-
- // This should pass because there is a terminating '\0'.
- memory.SetData8(name.size(), '\0');
- ASSERT_TRUE(memory.ReadString(0, &dst_name, 100));
- ASSERT_EQ("short", dst_name);
-}
-
-TEST(MemoryTest, read_string_long) {
- // This string should be greater than 768 characters long (greater than 3 times
- // the buffer in the ReadString function) to read multiple blocks.
- static constexpr char kLongString[] =
- "one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen "
- "sixteen seventeen eightteen nineteen twenty twenty-one twenty-two twenty-three twenty-four "
- "twenty-five twenty-six twenty-seven twenty-eight twenty-nine thirty thirty-one thirty-two "
- "thirty-three thirty-four thirty-five thirty-six thirty-seven thirty-eight thirty-nine forty "
- "forty-one forty-two forty-three forty-four forty-five forty-size forty-seven forty-eight "
- "forty-nine fifty fifty-one fifty-two fifty-three fifty-four fifty-five fifty-six "
- "fifty-seven fifty-eight fifty-nine sixty sixty-one sixty-two sixty-three sixty-four "
- "sixty-five sixty-six sixty-seven sixty-eight sixty-nine seventy seventy-one seventy-two "
- "seventy-three seventy-four seventy-five seventy-six seventy-seven seventy-eight "
- "seventy-nine eighty";
-
- MemoryFake memory;
-
- memory.SetMemory(100, kLongString, sizeof(kLongString));
-
- std::string dst_name;
- ASSERT_TRUE(memory.ReadString(100, &dst_name, sizeof(kLongString)));
- ASSERT_EQ(kLongString, dst_name);
-
- std::string expected_str(kLongString, 255);
- memory.SetMemory(100, expected_str.data(), expected_str.length() + 1);
- ASSERT_TRUE(memory.ReadString(100, &dst_name, 256));
- ASSERT_EQ(expected_str, dst_name);
- ASSERT_FALSE(memory.ReadString(100, &dst_name, 255));
-
- expected_str = std::string(kLongString, 256);
- memory.SetMemory(100, expected_str.data(), expected_str.length() + 1);
- ASSERT_TRUE(memory.ReadString(100, &dst_name, 257));
- ASSERT_EQ(expected_str, dst_name);
- ASSERT_FALSE(memory.ReadString(100, &dst_name, 256));
-
- expected_str = std::string(kLongString, 299);
- memory.SetMemory(100, expected_str.data(), expected_str.length() + 1);
- ASSERT_TRUE(memory.ReadString(100, &dst_name, 300));
- ASSERT_EQ(expected_str, dst_name);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
deleted file mode 100644
index f67d7dc..0000000
--- a/libunwindstack/tests/RegsFake.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
-#define _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
-
-#include <stdint.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-
-#include "Check.h"
-
-namespace unwindstack {
-
-class RegsFake : public Regs {
- public:
- RegsFake(uint16_t total_regs) : Regs(total_regs, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
- virtual ~RegsFake() = default;
-
- ArchEnum Arch() override { return fake_arch_; }
- void* RawData() override { return nullptr; }
- uint64_t pc() override { return fake_pc_; }
- uint64_t sp() override { return fake_sp_; }
- void set_pc(uint64_t pc) override { fake_pc_ = pc; }
- void set_sp(uint64_t sp) override { fake_sp_ = sp; }
-
- bool SetPcFromReturnAddress(Memory*) override {
- if (!fake_return_address_valid_) {
- return false;
- }
- fake_pc_ = fake_return_address_;
- return true;
- }
-
- void IterateRegisters(std::function<void(const char*, uint64_t)>) override {}
-
- bool Is32Bit() {
- CHECK(fake_arch_ != ARCH_UNKNOWN);
- return fake_arch_ == ARCH_ARM || fake_arch_ == ARCH_X86 || fake_arch_ == ARCH_MIPS;
- }
-
- bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
-
- void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
- void FakeSetDexPc(uint64_t dex_pc) { dex_pc_ = dex_pc; }
- void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; }
- void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; }
-
- Regs* Clone() override { return nullptr; }
-
- private:
- ArchEnum fake_arch_ = ARCH_UNKNOWN;
- uint64_t fake_pc_ = 0;
- uint64_t fake_sp_ = 0;
- bool fake_return_address_valid_ = false;
- uint64_t fake_return_address_ = 0;
-};
-
-template <typename TypeParam>
-class RegsImplFake : public RegsImpl<TypeParam> {
- public:
- RegsImplFake(uint16_t total_regs)
- : RegsImpl<TypeParam>(total_regs, Regs::Location(Regs::LOCATION_UNKNOWN, 0)) {}
- virtual ~RegsImplFake() = default;
-
- ArchEnum Arch() override { return ARCH_UNKNOWN; }
- uint64_t pc() override { return fake_pc_; }
- uint64_t sp() override { return fake_sp_; }
- void set_pc(uint64_t pc) override { fake_pc_ = pc; }
- void set_sp(uint64_t sp) override { fake_sp_ = sp; }
- void set_pseudo_reg(uint64_t reg) { fake_pseudo_reg_ = reg; }
-
- bool SetPcFromReturnAddress(Memory*) override { return false; }
- bool StepIfSignalHandler(uint64_t, Elf*, Memory*) override { return false; }
-
- bool SetPseudoRegister(uint16_t reg, uint64_t value) override {
- if (fake_pseudo_reg_ != reg) {
- return false;
- }
- fake_pseudo_reg_value_ = value;
- return true;
- }
- bool GetPseudoRegister(uint16_t reg, uint64_t* value) override {
- if (fake_pseudo_reg_ != reg) {
- return false;
- }
- *value = fake_pseudo_reg_value_;
- return true;
- }
-
- Regs* Clone() override { return nullptr; }
-
- private:
- uint64_t fake_pc_ = 0;
- uint64_t fake_sp_ = 0;
- uint16_t fake_pseudo_reg_ = 0;
- uint64_t fake_pseudo_reg_value_ = 0;
-};
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_REGS_FAKE_H
diff --git a/libunwindstack/tests/RegsInfoTest.cpp b/libunwindstack/tests/RegsInfoTest.cpp
deleted file mode 100644
index a6bc2c5..0000000
--- a/libunwindstack/tests/RegsInfoTest.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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 <gtest/gtest.h>
-
-#include <unwindstack/Regs.h>
-
-#include "RegsFake.h"
-#include "RegsInfo.h"
-
-namespace unwindstack {
-
-TEST(RegsInfoTest, single_uint32_t) {
- RegsImplFake<uint32_t> regs(10);
- RegsInfo<uint32_t> info(®s);
-
- regs[1] = 0x100;
- ASSERT_FALSE(info.IsSaved(1));
- ASSERT_EQ(0x100U, info.Get(1));
- ASSERT_EQ(10, info.Total());
-
- uint32_t* value = info.Save(1);
- ASSERT_EQ(value, ®s[1]);
- regs[1] = 0x200;
- ASSERT_TRUE(info.IsSaved(1));
- ASSERT_EQ(0x100U, info.Get(1));
- ASSERT_EQ(0x200U, regs[1]);
-}
-
-TEST(RegsInfoTest, single_uint64_t) {
- RegsImplFake<uint64_t> regs(20);
- RegsInfo<uint64_t> info(®s);
-
- regs[3] = 0x300;
- ASSERT_FALSE(info.IsSaved(3));
- ASSERT_EQ(0x300U, info.Get(3));
- ASSERT_EQ(20, info.Total());
-
- uint64_t* value = info.Save(3);
- ASSERT_EQ(value, ®s[3]);
- regs[3] = 0x400;
- ASSERT_TRUE(info.IsSaved(3));
- ASSERT_EQ(0x300U, info.Get(3));
- ASSERT_EQ(0x400U, regs[3]);
-}
-
-TEST(RegsInfoTest, all) {
- RegsImplFake<uint64_t> regs(64);
- RegsInfo<uint64_t> info(®s);
-
- for (uint32_t i = 0; i < 64; i++) {
- regs[i] = i * 0x100;
- ASSERT_EQ(i * 0x100, info.Get(i)) << "Reg " + std::to_string(i) + " failed.";
- }
-
- for (uint32_t i = 0; i < 64; i++) {
- ASSERT_FALSE(info.IsSaved(i)) << "Reg " + std::to_string(i) + " failed.";
- uint64_t* reg = info.Save(i);
- ASSERT_EQ(reg, ®s[i]) << "Reg " + std::to_string(i) + " failed.";
- *reg = i * 0x1000 + 0x100;
- ASSERT_EQ(i * 0x1000 + 0x100, regs[i]) << "Reg " + std::to_string(i) + " failed.";
- }
-
- for (uint32_t i = 0; i < 64; i++) {
- ASSERT_TRUE(info.IsSaved(i)) << "Reg " + std::to_string(i) + " failed.";
- ASSERT_EQ(i * 0x100, info.Get(i)) << "Reg " + std::to_string(i) + " failed.";
- }
-}
-
-TEST(RegsInfoTest, invalid_register) {
- RegsImplFake<uint64_t> regs(64);
- RegsInfo<uint64_t> info(®s);
-
- EXPECT_DEATH(info.Save(RegsInfo<uint64_t>::MAX_REGISTERS), "");
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
deleted file mode 100644
index 47e605a..0000000
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2017 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 <utility>
-#include <type_traits>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/MachineArm64.h>
-#include <unwindstack/MachineMips.h>
-#include <unwindstack/MachineMips64.h>
-#include <unwindstack/MachineX86.h>
-#include <unwindstack/MachineX86_64.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsMips.h>
-#include <unwindstack/RegsMips64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-
-namespace unwindstack {
-
-struct Register {
- std::string expected_name;
- uint64_t offset;
-
- bool operator==(const Register& rhs) const {
- return std::tie(expected_name, offset) == std::tie(rhs.expected_name, rhs.offset);
- }
-};
-
-template<typename T>
-class RegsIterateTest : public ::testing::Test {
-};
-
-template<typename RegsType>
-std::vector<Register> ExpectedRegisters();
-
-template<>
-std::vector<Register> ExpectedRegisters<RegsArm>() {
- std::vector<Register> result;
- result.push_back({"r0", ARM_REG_R0});
- result.push_back({"r1", ARM_REG_R1});
- result.push_back({"r2", ARM_REG_R2});
- result.push_back({"r3", ARM_REG_R3});
- result.push_back({"r4", ARM_REG_R4});
- result.push_back({"r5", ARM_REG_R5});
- result.push_back({"r6", ARM_REG_R6});
- result.push_back({"r7", ARM_REG_R7});
- result.push_back({"r8", ARM_REG_R8});
- result.push_back({"r9", ARM_REG_R9});
- result.push_back({"r10", ARM_REG_R10});
- result.push_back({"r11", ARM_REG_R11});
- result.push_back({"ip", ARM_REG_R12});
- result.push_back({"sp", ARM_REG_SP});
- result.push_back({"lr", ARM_REG_LR});
- result.push_back({"pc", ARM_REG_PC});
- return result;
-}
-
-template<>
-std::vector<Register> ExpectedRegisters<RegsArm64>() {
- std::vector<Register> result;
- result.push_back({"x0", ARM64_REG_R0});
- result.push_back({"x1", ARM64_REG_R1});
- result.push_back({"x2", ARM64_REG_R2});
- result.push_back({"x3", ARM64_REG_R3});
- result.push_back({"x4", ARM64_REG_R4});
- result.push_back({"x5", ARM64_REG_R5});
- result.push_back({"x6", ARM64_REG_R6});
- result.push_back({"x7", ARM64_REG_R7});
- result.push_back({"x8", ARM64_REG_R8});
- result.push_back({"x9", ARM64_REG_R9});
- result.push_back({"x10", ARM64_REG_R10});
- result.push_back({"x11", ARM64_REG_R11});
- result.push_back({"x12", ARM64_REG_R12});
- result.push_back({"x13", ARM64_REG_R13});
- result.push_back({"x14", ARM64_REG_R14});
- result.push_back({"x15", ARM64_REG_R15});
- result.push_back({"x16", ARM64_REG_R16});
- result.push_back({"x17", ARM64_REG_R17});
- result.push_back({"x18", ARM64_REG_R18});
- result.push_back({"x19", ARM64_REG_R19});
- result.push_back({"x20", ARM64_REG_R20});
- result.push_back({"x21", ARM64_REG_R21});
- result.push_back({"x22", ARM64_REG_R22});
- result.push_back({"x23", ARM64_REG_R23});
- result.push_back({"x24", ARM64_REG_R24});
- result.push_back({"x25", ARM64_REG_R25});
- result.push_back({"x26", ARM64_REG_R26});
- result.push_back({"x27", ARM64_REG_R27});
- result.push_back({"x28", ARM64_REG_R28});
- result.push_back({"x29", ARM64_REG_R29});
- result.push_back({"lr", ARM64_REG_LR});
- result.push_back({"sp", ARM64_REG_SP});
- result.push_back({"pc", ARM64_REG_PC});
- result.push_back({"pst", ARM64_REG_PSTATE});
- return result;
-}
-
-template<>
-std::vector<Register> ExpectedRegisters<RegsX86>() {
- std::vector<Register> result;
- result.push_back({"eax", X86_REG_EAX});
- result.push_back({"ebx", X86_REG_EBX});
- result.push_back({"ecx", X86_REG_ECX});
- result.push_back({"edx", X86_REG_EDX});
- result.push_back({"ebp", X86_REG_EBP});
- result.push_back({"edi", X86_REG_EDI});
- result.push_back({"esi", X86_REG_ESI});
- result.push_back({"esp", X86_REG_ESP});
- result.push_back({"eip", X86_REG_EIP});
- return result;
-}
-
-template<>
-std::vector<Register> ExpectedRegisters<RegsX86_64>() {
- std::vector<Register> result;
- result.push_back({"rax", X86_64_REG_RAX});
- result.push_back({"rbx", X86_64_REG_RBX});
- result.push_back({"rcx", X86_64_REG_RCX});
- result.push_back({"rdx", X86_64_REG_RDX});
- result.push_back({"r8", X86_64_REG_R8});
- result.push_back({"r9", X86_64_REG_R9});
- result.push_back({"r10", X86_64_REG_R10});
- result.push_back({"r11", X86_64_REG_R11});
- result.push_back({"r12", X86_64_REG_R12});
- result.push_back({"r13", X86_64_REG_R13});
- result.push_back({"r14", X86_64_REG_R14});
- result.push_back({"r15", X86_64_REG_R15});
- result.push_back({"rdi", X86_64_REG_RDI});
- result.push_back({"rsi", X86_64_REG_RSI});
- result.push_back({"rbp", X86_64_REG_RBP});
- result.push_back({"rsp", X86_64_REG_RSP});
- result.push_back({"rip", X86_64_REG_RIP});
- return result;
-}
-
-template<>
-std::vector<Register> ExpectedRegisters<RegsMips>() {
- std::vector<Register> result;
- result.push_back({"r0", MIPS_REG_R0});
- result.push_back({"r1", MIPS_REG_R1});
- result.push_back({"r2", MIPS_REG_R2});
- result.push_back({"r3", MIPS_REG_R3});
- result.push_back({"r4", MIPS_REG_R4});
- result.push_back({"r5", MIPS_REG_R5});
- result.push_back({"r6", MIPS_REG_R6});
- result.push_back({"r7", MIPS_REG_R7});
- result.push_back({"r8", MIPS_REG_R8});
- result.push_back({"r9", MIPS_REG_R9});
- result.push_back({"r10", MIPS_REG_R10});
- result.push_back({"r11", MIPS_REG_R11});
- result.push_back({"r12", MIPS_REG_R12});
- result.push_back({"r13", MIPS_REG_R13});
- result.push_back({"r14", MIPS_REG_R14});
- result.push_back({"r15", MIPS_REG_R15});
- result.push_back({"r16", MIPS_REG_R16});
- result.push_back({"r17", MIPS_REG_R17});
- result.push_back({"r18", MIPS_REG_R18});
- result.push_back({"r19", MIPS_REG_R19});
- result.push_back({"r20", MIPS_REG_R20});
- result.push_back({"r21", MIPS_REG_R21});
- result.push_back({"r22", MIPS_REG_R22});
- result.push_back({"r23", MIPS_REG_R23});
- result.push_back({"r24", MIPS_REG_R24});
- result.push_back({"r25", MIPS_REG_R25});
- result.push_back({"r26", MIPS_REG_R26});
- result.push_back({"r27", MIPS_REG_R27});
- result.push_back({"r28", MIPS_REG_R28});
- result.push_back({"sp", MIPS_REG_SP});
- result.push_back({"r30", MIPS_REG_R30});
- result.push_back({"ra", MIPS_REG_RA});
- result.push_back({"pc", MIPS_REG_PC});
-
- return result;
-}
-
-template<>
-std::vector<Register> ExpectedRegisters<RegsMips64>() {
- std::vector<Register> result;
- result.push_back({"r0", MIPS64_REG_R0});
- result.push_back({"r1", MIPS64_REG_R1});
- result.push_back({"r2", MIPS64_REG_R2});
- result.push_back({"r3", MIPS64_REG_R3});
- result.push_back({"r4", MIPS64_REG_R4});
- result.push_back({"r5", MIPS64_REG_R5});
- result.push_back({"r6", MIPS64_REG_R6});
- result.push_back({"r7", MIPS64_REG_R7});
- result.push_back({"r8", MIPS64_REG_R8});
- result.push_back({"r9", MIPS64_REG_R9});
- result.push_back({"r10", MIPS64_REG_R10});
- result.push_back({"r11", MIPS64_REG_R11});
- result.push_back({"r12", MIPS64_REG_R12});
- result.push_back({"r13", MIPS64_REG_R13});
- result.push_back({"r14", MIPS64_REG_R14});
- result.push_back({"r15", MIPS64_REG_R15});
- result.push_back({"r16", MIPS64_REG_R16});
- result.push_back({"r17", MIPS64_REG_R17});
- result.push_back({"r18", MIPS64_REG_R18});
- result.push_back({"r19", MIPS64_REG_R19});
- result.push_back({"r20", MIPS64_REG_R20});
- result.push_back({"r21", MIPS64_REG_R21});
- result.push_back({"r22", MIPS64_REG_R22});
- result.push_back({"r23", MIPS64_REG_R23});
- result.push_back({"r24", MIPS64_REG_R24});
- result.push_back({"r25", MIPS64_REG_R25});
- result.push_back({"r26", MIPS64_REG_R26});
- result.push_back({"r27", MIPS64_REG_R27});
- result.push_back({"r28", MIPS64_REG_R28});
- result.push_back({"sp", MIPS64_REG_SP});
- result.push_back({"r30", MIPS64_REG_R30});
- result.push_back({"ra", MIPS64_REG_RA});
- result.push_back({"pc", MIPS64_REG_PC});
-
- return result;
-}
-
-using RegTypes = ::testing::Types<RegsArm, RegsArm64, RegsX86, RegsX86_64, RegsMips, RegsMips64>;
-TYPED_TEST_SUITE(RegsIterateTest, RegTypes);
-
-TYPED_TEST(RegsIterateTest, iterate) {
- std::vector<Register> expected = ExpectedRegisters<TypeParam>();
- TypeParam regs;
- for (const auto& reg : expected) {
- regs[reg.offset] = reg.offset;
- }
-
- std::vector<Register> actual;
- regs.IterateRegisters([&actual](const char* name, uint64_t value) {
- actual.push_back({name, value});
- });
-
- ASSERT_EQ(expected, actual);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
deleted file mode 100644
index eac12ca..0000000
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright (C) 2017 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 <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/MachineArm64.h>
-#include <unwindstack/MachineMips.h>
-#include <unwindstack/MachineMips64.h>
-#include <unwindstack/MachineX86.h>
-#include <unwindstack/MachineX86_64.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsMips.h>
-#include <unwindstack/RegsMips64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-
-#include "MemoryFake.h"
-
-namespace unwindstack {
-
-class RegsStepIfSignalHandlerTest : public ::testing::Test {
- protected:
- void SetUp() override {
- elf_memory_ = new MemoryFake;
- elf_.reset(new Elf(elf_memory_));
- }
-
- void ArmStepIfSignalHandlerNonRt(uint32_t pc_data);
- void ArmStepIfSignalHandlerRt(uint32_t pc_data);
-
- MemoryFake* elf_memory_;
- MemoryFake process_memory_;
- std::unique_ptr<Elf> elf_;
-};
-
-void RegsStepIfSignalHandlerTest::ArmStepIfSignalHandlerNonRt(uint32_t pc_data) {
- uint64_t addr = 0x1000;
- RegsArm regs;
- regs[ARM_REG_PC] = 0x5000;
- regs[ARM_REG_SP] = addr;
-
- elf_memory_->SetData32(0x5000, pc_data);
-
- for (uint64_t index = 0; index <= 30; index++) {
- process_memory_.SetData32(addr + index * 4, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x5000, elf_.get(), &process_memory_));
- EXPECT_EQ(0x100U, regs[ARM_REG_SP]);
- EXPECT_EQ(0x120U, regs[ARM_REG_PC]);
- EXPECT_EQ(0x100U, regs.sp());
- EXPECT_EQ(0x120U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, arm_step_if_signal_handler_non_rt) {
- // Form 1
- ArmStepIfSignalHandlerNonRt(0xe3a07077);
-
- // Form 2
- ArmStepIfSignalHandlerNonRt(0xef900077);
-
- // Form 3
- ArmStepIfSignalHandlerNonRt(0xdf002777);
-}
-
-void RegsStepIfSignalHandlerTest::ArmStepIfSignalHandlerRt(uint32_t pc_data) {
- uint64_t addr = 0x1000;
- RegsArm regs;
- regs[ARM_REG_PC] = 0x5000;
- regs[ARM_REG_SP] = addr;
-
- elf_memory_->SetData32(0x5000, pc_data);
-
- for (uint64_t index = 0; index <= 100; index++) {
- process_memory_.SetData32(addr + index * 4, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x5000, elf_.get(), &process_memory_));
- EXPECT_EQ(0x350U, regs[ARM_REG_SP]);
- EXPECT_EQ(0x370U, regs[ARM_REG_PC]);
- EXPECT_EQ(0x350U, regs.sp());
- EXPECT_EQ(0x370U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, arm_step_if_signal_handler_rt) {
- // Form 1
- ArmStepIfSignalHandlerRt(0xe3a070ad);
-
- // Form 2
- ArmStepIfSignalHandlerRt(0xef9000ad);
-
- // Form 3
- ArmStepIfSignalHandlerRt(0xdf0027ad);
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, arm64_step_if_signal_handler) {
- uint64_t addr = 0x1000;
- RegsArm64 regs;
- regs[ARM64_REG_PC] = 0x8000;
- regs[ARM64_REG_SP] = addr;
-
- elf_memory_->SetData64(0x8000, 0xd4000001d2801168ULL);
-
- for (uint64_t index = 0; index <= 100; index++) {
- process_memory_.SetData64(addr + index * 8, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
- EXPECT_EQ(0x460U, regs[ARM64_REG_SP]);
- EXPECT_EQ(0x470U, regs[ARM64_REG_PC]);
- EXPECT_EQ(0x460U, regs.sp());
- EXPECT_EQ(0x470U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, x86_step_if_signal_handler_no_siginfo) {
- uint64_t addr = 0xa00;
- RegsX86 regs;
- regs[X86_REG_EIP] = 0x4100;
- regs[X86_REG_ESP] = addr;
-
- elf_memory_->SetData64(0x4100, 0x80cd00000077b858ULL);
- for (uint64_t index = 0; index <= 25; index++) {
- process_memory_.SetData32(addr + index * 4, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x4100, elf_.get(), &process_memory_));
- EXPECT_EQ(0x70U, regs[X86_REG_EBP]);
- EXPECT_EQ(0x80U, regs[X86_REG_ESP]);
- EXPECT_EQ(0x90U, regs[X86_REG_EBX]);
- EXPECT_EQ(0xa0U, regs[X86_REG_EDX]);
- EXPECT_EQ(0xb0U, regs[X86_REG_ECX]);
- EXPECT_EQ(0xc0U, regs[X86_REG_EAX]);
- EXPECT_EQ(0xf0U, regs[X86_REG_EIP]);
- EXPECT_EQ(0x80U, regs.sp());
- EXPECT_EQ(0xf0U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, x86_step_if_signal_handler_siginfo) {
- uint64_t addr = 0xa00;
- RegsX86 regs;
- regs[X86_REG_EIP] = 0x4100;
- regs[X86_REG_ESP] = addr;
-
- elf_memory_->SetData64(0x4100, 0x0080cd000000adb8ULL);
- addr += 8;
- // Pointer to ucontext data.
- process_memory_.SetData32(addr, 0x8100);
-
- addr = 0x8100;
- for (uint64_t index = 0; index <= 30; index++) {
- process_memory_.SetData32(addr + index * 4, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x4100, elf_.get(), &process_memory_));
- EXPECT_EQ(0xb0U, regs[X86_REG_EBP]);
- EXPECT_EQ(0xc0U, regs[X86_REG_ESP]);
- EXPECT_EQ(0xd0U, regs[X86_REG_EBX]);
- EXPECT_EQ(0xe0U, regs[X86_REG_EDX]);
- EXPECT_EQ(0xf0U, regs[X86_REG_ECX]);
- EXPECT_EQ(0x100U, regs[X86_REG_EAX]);
- EXPECT_EQ(0x130U, regs[X86_REG_EIP]);
- EXPECT_EQ(0xc0U, regs.sp());
- EXPECT_EQ(0x130U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, x86_64_step_if_signal_handler) {
- uint64_t addr = 0x500;
- RegsX86_64 regs;
- regs[X86_64_REG_RIP] = 0x7000;
- regs[X86_64_REG_RSP] = addr;
-
- elf_memory_->SetData64(0x7000, 0x0f0000000fc0c748);
- elf_memory_->SetData16(0x7008, 0x0f05);
-
- for (uint64_t index = 0; index <= 30; index++) {
- process_memory_.SetData64(addr + index * 8, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x7000, elf_.get(), &process_memory_));
- EXPECT_EQ(0x140U, regs[X86_64_REG_RSP]);
- EXPECT_EQ(0x150U, regs[X86_64_REG_RIP]);
- EXPECT_EQ(0x140U, regs.sp());
- EXPECT_EQ(0x150U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_non_rt) {
- uint64_t addr = 0x1000;
- RegsMips regs;
- regs[MIPS_REG_PC] = 0x8000;
- regs[MIPS_REG_SP] = addr;
-
- elf_memory_->SetData64(0x8000, 0x0000000c24021017ULL);
-
- for (uint64_t index = 0; index <= 50; index++) {
- process_memory_.SetData64(addr + index * 8, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
- EXPECT_EQ(0x220U, regs[MIPS_REG_SP]);
- EXPECT_EQ(0x040U, regs[MIPS_REG_PC]);
- EXPECT_EQ(0x220U, regs.sp());
- EXPECT_EQ(0x040U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, mips_step_if_signal_handler_rt) {
- uint64_t addr = 0x1000;
- RegsMips regs;
- regs[MIPS_REG_PC] = 0x8000;
- regs[MIPS_REG_SP] = addr;
-
- elf_memory_->SetData64(0x8000, 0x0000000c24021061ULL);
-
- for (uint64_t index = 0; index <= 100; index++) {
- process_memory_.SetData64(addr + index * 8, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
- EXPECT_EQ(0x350U, regs[MIPS_REG_SP]);
- EXPECT_EQ(0x170U, regs[MIPS_REG_PC]);
- EXPECT_EQ(0x350U, regs.sp());
- EXPECT_EQ(0x170U, regs.pc());
-}
-
-TEST_F(RegsStepIfSignalHandlerTest, mips64_step_if_signal_handler) {
- uint64_t addr = 0x1000;
- RegsMips64 regs;
- regs[MIPS64_REG_PC] = 0x8000;
- regs[MIPS64_REG_SP] = addr;
-
- elf_memory_->SetData64(0x8000, 0x0000000c2402145bULL);
-
- for (uint64_t index = 0; index <= 100; index++) {
- process_memory_.SetData64(addr + index * 8, index * 0x10);
- }
-
- ASSERT_TRUE(regs.StepIfSignalHandler(0x8000, elf_.get(), &process_memory_));
- EXPECT_EQ(0x350U, regs[MIPS64_REG_SP]);
- EXPECT_EQ(0x600U, regs[MIPS64_REG_PC]);
- EXPECT_EQ(0x350U, regs.sp());
- EXPECT_EQ(0x600U, regs.pc());
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp
deleted file mode 100644
index acf72de..0000000
--- a/libunwindstack/tests/RegsTest.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2017 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 <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/MapInfo.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-#include <unwindstack/RegsMips.h>
-#include <unwindstack/RegsMips64.h>
-
-#include "ElfFake.h"
-#include "MemoryFake.h"
-#include "RegsFake.h"
-
-namespace unwindstack {
-
-class RegsTest : public ::testing::Test {
- protected:
- void SetUp() override {
- memory_ = new MemoryFake;
- elf_.reset(new ElfFake(memory_));
- elf_interface_ = new ElfInterfaceFake(elf_->memory());
- elf_->FakeSetInterface(elf_interface_);
- }
-
- ElfInterfaceFake* elf_interface_;
- MemoryFake* memory_;
- std::unique_ptr<ElfFake> elf_;
-};
-
-TEST_F(RegsTest, regs32) {
- RegsImplFake<uint32_t> regs32(50);
- ASSERT_EQ(50U, regs32.total_regs());
-
- uint32_t* raw = reinterpret_cast<uint32_t*>(regs32.RawData());
- for (size_t i = 0; i < 50; i++) {
- raw[i] = 0xf0000000 + i;
- }
- regs32.set_pc(0xf0120340);
- regs32.set_sp(0xa0ab0cd0);
-
- for (size_t i = 0; i < 50; i++) {
- ASSERT_EQ(0xf0000000U + i, regs32[i]) << "Failed comparing register " << i;
- }
-
- ASSERT_EQ(0xf0120340U, regs32.pc());
- ASSERT_EQ(0xa0ab0cd0U, regs32.sp());
-
- regs32[32] = 10;
- ASSERT_EQ(10U, regs32[32]);
-}
-
-TEST_F(RegsTest, regs64) {
- RegsImplFake<uint64_t> regs64(30);
- ASSERT_EQ(30U, regs64.total_regs());
-
- uint64_t* raw = reinterpret_cast<uint64_t*>(regs64.RawData());
- for (size_t i = 0; i < 30; i++) {
- raw[i] = 0xf123456780000000UL + i;
- }
- regs64.set_pc(0xf123456780102030UL);
- regs64.set_sp(0xa123456780a0b0c0UL);
-
- for (size_t i = 0; i < 30; i++) {
- ASSERT_EQ(0xf123456780000000U + i, regs64[i]) << "Failed reading register " << i;
- }
-
- ASSERT_EQ(0xf123456780102030UL, regs64.pc());
- ASSERT_EQ(0xa123456780a0b0c0UL, regs64.sp());
-
- regs64[8] = 10;
- ASSERT_EQ(10U, regs64[8]);
-}
-
-TEST_F(RegsTest, rel_pc) {
- EXPECT_EQ(4U, GetPcAdjustment(0x10, elf_.get(), ARCH_ARM64));
- EXPECT_EQ(4U, GetPcAdjustment(0x4, elf_.get(), ARCH_ARM64));
- EXPECT_EQ(0U, GetPcAdjustment(0x3, elf_.get(), ARCH_ARM64));
- EXPECT_EQ(0U, GetPcAdjustment(0x2, elf_.get(), ARCH_ARM64));
- EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_ARM64));
- EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_ARM64));
-
- EXPECT_EQ(1U, GetPcAdjustment(0x100, elf_.get(), ARCH_X86));
- EXPECT_EQ(1U, GetPcAdjustment(0x2, elf_.get(), ARCH_X86));
- EXPECT_EQ(1U, GetPcAdjustment(0x1, elf_.get(), ARCH_X86));
- EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_X86));
-
- EXPECT_EQ(1U, GetPcAdjustment(0x100, elf_.get(), ARCH_X86_64));
- EXPECT_EQ(1U, GetPcAdjustment(0x2, elf_.get(), ARCH_X86_64));
- EXPECT_EQ(1U, GetPcAdjustment(0x1, elf_.get(), ARCH_X86_64));
- EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_X86_64));
-
- EXPECT_EQ(8U, GetPcAdjustment(0x10, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(8U, GetPcAdjustment(0x8, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x7, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x6, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x5, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x4, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x3, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x2, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_MIPS));
- EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_MIPS));
-
- EXPECT_EQ(8U, GetPcAdjustment(0x10, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(8U, GetPcAdjustment(0x8, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x7, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x6, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x5, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x4, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x3, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x2, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_MIPS64));
- EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_MIPS64));
-}
-
-TEST_F(RegsTest, rel_pc_arm) {
- // Check fence posts.
- elf_->FakeSetLoadBias(0);
- EXPECT_EQ(2U, GetPcAdjustment(0x5, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x4, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x3, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x2, elf_.get(), ARCH_ARM));
- EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_ARM));
- EXPECT_EQ(0U, GetPcAdjustment(0x0, elf_.get(), ARCH_ARM));
-
- elf_->FakeSetLoadBias(0x100);
- EXPECT_EQ(0U, GetPcAdjustment(0x1, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x2, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0xff, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x105, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x104, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x103, elf_.get(), ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x102, elf_.get(), ARCH_ARM));
- EXPECT_EQ(0U, GetPcAdjustment(0x101, elf_.get(), ARCH_ARM));
- EXPECT_EQ(0U, GetPcAdjustment(0x100, elf_.get(), ARCH_ARM));
-
- // Check thumb instructions handling.
- elf_->FakeSetLoadBias(0);
- memory_->SetData32(0x2000, 0);
- EXPECT_EQ(2U, GetPcAdjustment(0x2005, elf_.get(), ARCH_ARM));
- memory_->SetData32(0x2000, 0xe000f000);
- EXPECT_EQ(4U, GetPcAdjustment(0x2005, elf_.get(), ARCH_ARM));
-
- elf_->FakeSetLoadBias(0x400);
- memory_->SetData32(0x2100, 0);
- EXPECT_EQ(2U, GetPcAdjustment(0x2505, elf_.get(), ARCH_ARM));
- memory_->SetData32(0x2100, 0xf111f111);
- EXPECT_EQ(4U, GetPcAdjustment(0x2505, elf_.get(), ARCH_ARM));
-}
-
-TEST_F(RegsTest, elf_invalid) {
- MapInfo map_info(nullptr, nullptr, 0x1000, 0x2000, 0, 0, "");
- Elf* invalid_elf = new Elf(nullptr);
- map_info.elf.reset(invalid_elf);
-
- EXPECT_EQ(0x500U, invalid_elf->GetRelPc(0x1500, &map_info));
- EXPECT_EQ(2U, GetPcAdjustment(0x500U, invalid_elf, ARCH_ARM));
- EXPECT_EQ(2U, GetPcAdjustment(0x511U, invalid_elf, ARCH_ARM));
-
- EXPECT_EQ(0x600U, invalid_elf->GetRelPc(0x1600, &map_info));
- EXPECT_EQ(4U, GetPcAdjustment(0x600U, invalid_elf, ARCH_ARM64));
-
- EXPECT_EQ(0x700U, invalid_elf->GetRelPc(0x1700, &map_info));
- EXPECT_EQ(1U, GetPcAdjustment(0x700U, invalid_elf, ARCH_X86));
-
- EXPECT_EQ(0x800U, invalid_elf->GetRelPc(0x1800, &map_info));
- EXPECT_EQ(1U, GetPcAdjustment(0x800U, invalid_elf, ARCH_X86_64));
-
- EXPECT_EQ(0x900U, invalid_elf->GetRelPc(0x1900, &map_info));
- EXPECT_EQ(8U, GetPcAdjustment(0x900U, invalid_elf, ARCH_MIPS));
-
- EXPECT_EQ(0xa00U, invalid_elf->GetRelPc(0x1a00, &map_info));
- EXPECT_EQ(8U, GetPcAdjustment(0xa00U, invalid_elf, ARCH_MIPS64));
-}
-
-TEST_F(RegsTest, arm_verify_sp_pc) {
- RegsArm arm;
- uint32_t* regs = reinterpret_cast<uint32_t*>(arm.RawData());
- regs[13] = 0x100;
- regs[15] = 0x200;
- EXPECT_EQ(0x100U, arm.sp());
- EXPECT_EQ(0x200U, arm.pc());
-}
-
-TEST_F(RegsTest, arm64_verify_sp_pc) {
- RegsArm64 arm64;
- uint64_t* regs = reinterpret_cast<uint64_t*>(arm64.RawData());
- regs[31] = 0xb100000000ULL;
- regs[32] = 0xc200000000ULL;
- EXPECT_EQ(0xb100000000U, arm64.sp());
- EXPECT_EQ(0xc200000000U, arm64.pc());
-}
-
-TEST_F(RegsTest, x86_verify_sp_pc) {
- RegsX86 x86;
- uint32_t* regs = reinterpret_cast<uint32_t*>(x86.RawData());
- regs[4] = 0x23450000;
- regs[8] = 0xabcd0000;
- EXPECT_EQ(0x23450000U, x86.sp());
- EXPECT_EQ(0xabcd0000U, x86.pc());
-}
-
-TEST_F(RegsTest, x86_64_verify_sp_pc) {
- RegsX86_64 x86_64;
- uint64_t* regs = reinterpret_cast<uint64_t*>(x86_64.RawData());
- regs[7] = 0x1200000000ULL;
- regs[16] = 0x4900000000ULL;
- EXPECT_EQ(0x1200000000U, x86_64.sp());
- EXPECT_EQ(0x4900000000U, x86_64.pc());
-}
-
-TEST_F(RegsTest, mips_verify_sp_pc) {
- RegsMips mips;
- uint32_t* regs = reinterpret_cast<uint32_t*>(mips.RawData());
- regs[29] = 0x100;
- regs[32] = 0x200;
- EXPECT_EQ(0x100U, mips.sp());
- EXPECT_EQ(0x200U, mips.pc());
-}
-
-TEST_F(RegsTest, mips64_verify_sp_pc) {
- RegsMips64 mips64;
- uint64_t* regs = reinterpret_cast<uint64_t*>(mips64.RawData());
- regs[29] = 0xb100000000ULL;
- regs[32] = 0xc200000000ULL;
- EXPECT_EQ(0xb100000000U, mips64.sp());
- EXPECT_EQ(0xc200000000U, mips64.pc());
-}
-
-TEST_F(RegsTest, arm64_strip_pac_mask) {
- RegsArm64 arm64;
- arm64.SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 1);
- arm64.SetPACMask(0x007fff8000000000ULL);
- arm64.set_pc(0x0020007214bb3a04ULL);
- EXPECT_EQ(0x0000007214bb3a04ULL, arm64.pc());
-}
-
-TEST_F(RegsTest, machine_type) {
- RegsArm arm_regs;
- EXPECT_EQ(ARCH_ARM, arm_regs.Arch());
-
- RegsArm64 arm64_regs;
- EXPECT_EQ(ARCH_ARM64, arm64_regs.Arch());
-
- RegsX86 x86_regs;
- EXPECT_EQ(ARCH_X86, x86_regs.Arch());
-
- RegsX86_64 x86_64_regs;
- EXPECT_EQ(ARCH_X86_64, x86_64_regs.Arch());
-
- RegsMips mips_regs;
- EXPECT_EQ(ARCH_MIPS, mips_regs.Arch());
-
- RegsMips64 mips64_regs;
- EXPECT_EQ(ARCH_MIPS64, mips64_regs.Arch());
-}
-
-template <typename RegisterType>
-void clone_test(Regs* regs) {
- RegisterType* register_values = reinterpret_cast<RegisterType*>(regs->RawData());
- int num_regs = regs->total_regs();
- for (int i = 0; i < num_regs; ++i) {
- register_values[i] = i;
- }
-
- std::unique_ptr<Regs> clone(regs->Clone());
- ASSERT_EQ(regs->total_regs(), clone->total_regs());
- RegisterType* clone_values = reinterpret_cast<RegisterType*>(clone->RawData());
- for (int i = 0; i < num_regs; ++i) {
- EXPECT_EQ(register_values[i], clone_values[i]);
- EXPECT_NE(®ister_values[i], &clone_values[i]);
- }
-}
-
-TEST_F(RegsTest, clone) {
- std::vector<std::unique_ptr<Regs>> regs;
- regs.emplace_back(new RegsArm());
- regs.emplace_back(new RegsArm64());
- regs.emplace_back(new RegsX86());
- regs.emplace_back(new RegsX86_64());
- regs.emplace_back(new RegsMips());
- regs.emplace_back(new RegsMips64());
-
- for (auto& r : regs) {
- if (r->Is32Bit()) {
- clone_test<uint32_t>(r.get());
- } else {
- clone_test<uint64_t>(r.get());
- }
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/SymbolsTest.cpp b/libunwindstack/tests/SymbolsTest.cpp
deleted file mode 100644
index 9afbeec..0000000
--- a/libunwindstack/tests/SymbolsTest.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/test_utils.h>
-#include <gtest/gtest.h>
-
-#include <unwindstack/Memory.h>
-
-#include "MemoryFake.h"
-#include "Symbols.h"
-
-namespace unwindstack {
-
-template <typename TypeParam>
-class SymbolsTest : public ::testing::Test {
- protected:
- void SetUp() override { memory_.Clear(); }
-
- void InitSym(TypeParam* sym, uint32_t st_value, uint32_t st_size, uint32_t st_name) {
- memset(sym, 0, sizeof(*sym));
- sym->st_info = STT_FUNC;
- sym->st_value = st_value;
- sym->st_size = st_size;
- sym->st_name = st_name;
- sym->st_shndx = SHN_COMMON;
- }
-
- MemoryFake memory_;
-};
-TYPED_TEST_SUITE_P(SymbolsTest);
-
-TYPED_TEST_P(SymbolsTest, function_bounds_check) {
- Symbols symbols(0x1000, sizeof(TypeParam), sizeof(TypeParam), 0x2000, 0x100);
-
- TypeParam sym;
- this->InitSym(&sym, 0x5000, 0x10, 0x40);
- uint64_t offset = 0x1000;
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
-
- std::string fake_name("fake_function");
- this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1);
-
- std::string name;
- uint64_t func_offset;
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
- ASSERT_EQ("fake_function", name);
- ASSERT_EQ(0U, func_offset);
-
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x500f, &this->memory_, &name, &func_offset));
- ASSERT_EQ("fake_function", name);
- ASSERT_EQ(0xfU, func_offset);
-
- // Check one before and one after the function.
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x4fff, &this->memory_, &name, &func_offset));
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x5010, &this->memory_, &name, &func_offset));
-}
-
-TYPED_TEST_P(SymbolsTest, no_symbol) {
- Symbols symbols(0x1000, sizeof(TypeParam), sizeof(TypeParam), 0x2000, 0x100);
-
- TypeParam sym;
- this->InitSym(&sym, 0x5000, 0x10, 0x40);
- uint64_t offset = 0x1000;
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
-
- std::string fake_name("fake_function");
- this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1);
-
- // First verify that we can get the name.
- std::string name;
- uint64_t func_offset;
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
- ASSERT_EQ("fake_function", name);
- ASSERT_EQ(0U, func_offset);
-
- // Now modify the info field so it's no longer a function.
- sym.st_info = 0;
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- // Clear the cache to force the symbol data to be re-read.
- symbols.ClearCache();
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
-
- // Set the function back, and set the shndx to UNDEF.
- sym.st_info = STT_FUNC;
- sym.st_shndx = SHN_UNDEF;
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- // Clear the cache to force the symbol data to be re-read.
- symbols.ClearCache();
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
-}
-
-TYPED_TEST_P(SymbolsTest, multiple_entries) {
- Symbols symbols(0x1000, sizeof(TypeParam) * 3, sizeof(TypeParam), 0x2000, 0x500);
-
- TypeParam sym;
- uint64_t offset = 0x1000;
- std::string fake_name;
-
- this->InitSym(&sym, 0x5000, 0x10, 0x40);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- fake_name = "function_one";
- this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1);
- offset += sizeof(sym);
-
- this->InitSym(&sym, 0x3004, 0x200, 0x100);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- fake_name = "function_two";
- this->memory_.SetMemory(0x2100, fake_name.c_str(), fake_name.size() + 1);
- offset += sizeof(sym);
-
- this->InitSym(&sym, 0xa010, 0x20, 0x230);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- fake_name = "function_three";
- this->memory_.SetMemory(0x2230, fake_name.c_str(), fake_name.size() + 1);
-
- std::string name;
- uint64_t func_offset;
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_two", name);
- ASSERT_EQ(1U, func_offset);
-
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_one", name);
- ASSERT_EQ(4U, func_offset);
-
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_three", name);
- ASSERT_EQ(1U, func_offset);
-
- // Reget some of the others to verify getting one function name doesn't
- // affect any of the next calls.
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x5008, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_one", name);
- ASSERT_EQ(8U, func_offset);
-
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x3008, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_two", name);
- ASSERT_EQ(4U, func_offset);
-
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0xa01a, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_three", name);
- ASSERT_EQ(0xaU, func_offset);
-}
-
-TYPED_TEST_P(SymbolsTest, multiple_entries_nonstandard_size) {
- uint64_t entry_size = sizeof(TypeParam) + 5;
- Symbols symbols(0x1000, entry_size * 3, entry_size, 0x2000, 0x500);
-
- TypeParam sym;
- uint64_t offset = 0x1000;
- std::string fake_name;
-
- this->InitSym(&sym, 0x5000, 0x10, 0x40);
- this->memory_.SetMemoryBlock(offset, entry_size, 0);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- fake_name = "function_one";
- this->memory_.SetMemory(0x2040, fake_name.c_str(), fake_name.size() + 1);
- offset += entry_size;
-
- this->InitSym(&sym, 0x3004, 0x200, 0x100);
- this->memory_.SetMemoryBlock(offset, entry_size, 0);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- fake_name = "function_two";
- this->memory_.SetMemory(0x2100, fake_name.c_str(), fake_name.size() + 1);
- offset += entry_size;
-
- this->InitSym(&sym, 0xa010, 0x20, 0x230);
- this->memory_.SetMemoryBlock(offset, entry_size, 0);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- fake_name = "function_three";
- this->memory_.SetMemory(0x2230, fake_name.c_str(), fake_name.size() + 1);
-
- std::string name;
- uint64_t func_offset;
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x3005, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_two", name);
- ASSERT_EQ(1U, func_offset);
-
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x5004, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_one", name);
- ASSERT_EQ(4U, func_offset);
-
- name.clear();
- ASSERT_TRUE(symbols.GetName<TypeParam>(0xa011, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function_three", name);
- ASSERT_EQ(1U, func_offset);
-}
-
-TYPED_TEST_P(SymbolsTest, symtab_value_out_of_bounds) {
- Symbols symbols_end_at_100(0x1000, sizeof(TypeParam) * 2, sizeof(TypeParam), 0x2000, 0x100);
- Symbols symbols_end_at_200(0x1000, sizeof(TypeParam) * 2, sizeof(TypeParam), 0x2000, 0x200);
-
- TypeParam sym;
- uint64_t offset = 0x1000;
-
- this->InitSym(&sym, 0x5000, 0x10, 0xfb);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- offset += sizeof(sym);
-
- this->InitSym(&sym, 0x3000, 0x10, 0x100);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
-
- // Put the name across the end of the tab.
- std::string fake_name("fake_function");
- this->memory_.SetMemory(0x20fb, fake_name.c_str(), fake_name.size() + 1);
-
- std::string name;
- uint64_t func_offset;
- // Verify that we can get the function name properly for both entries.
- ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
- ASSERT_EQ("fake_function", name);
- ASSERT_EQ(0U, func_offset);
- ASSERT_TRUE(symbols_end_at_200.GetName<TypeParam>(0x3000, &this->memory_, &name, &func_offset));
- ASSERT_EQ("function", name);
- ASSERT_EQ(0U, func_offset);
-
- // Now use the symbol table that ends at 0x100.
- ASSERT_FALSE(symbols_end_at_100.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
- ASSERT_FALSE(symbols_end_at_100.GetName<TypeParam>(0x3000, &this->memory_, &name, &func_offset));
-}
-
-// Verify the entire func table is cached.
-TYPED_TEST_P(SymbolsTest, symtab_read_cached) {
- Symbols symbols(0x1000, 3 * sizeof(TypeParam), sizeof(TypeParam), 0xa000, 0x1000);
-
- TypeParam sym;
- uint64_t offset = 0x1000;
-
- // Make sure that these entries are not in ascending order.
- this->InitSym(&sym, 0x5000, 0x10, 0x100);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- offset += sizeof(sym);
-
- this->InitSym(&sym, 0x2000, 0x300, 0x200);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- offset += sizeof(sym);
-
- this->InitSym(&sym, 0x1000, 0x100, 0x300);
- this->memory_.SetMemory(offset, &sym, sizeof(sym));
- offset += sizeof(sym);
-
- // Do call that should cache all of the entries (except the string data).
- std::string name;
- uint64_t func_offset;
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x5000, &this->memory_, &name, &func_offset));
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x2000, &this->memory_, &name, &func_offset));
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x1000, &this->memory_, &name, &func_offset));
- this->memory_.Clear();
- ASSERT_FALSE(symbols.GetName<TypeParam>(0x6000, &this->memory_, &name, &func_offset));
-
- // Clear the memory and only put the symbol data string data in memory.
- this->memory_.Clear();
-
- std::string fake_name;
- fake_name = "first_entry";
- this->memory_.SetMemory(0xa100, fake_name.c_str(), fake_name.size() + 1);
- fake_name = "second_entry";
- this->memory_.SetMemory(0xa200, fake_name.c_str(), fake_name.size() + 1);
- fake_name = "third_entry";
- this->memory_.SetMemory(0xa300, fake_name.c_str(), fake_name.size() + 1);
-
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x5001, &this->memory_, &name, &func_offset));
- ASSERT_EQ("first_entry", name);
- ASSERT_EQ(1U, func_offset);
-
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x2002, &this->memory_, &name, &func_offset));
- ASSERT_EQ("second_entry", name);
- ASSERT_EQ(2U, func_offset);
-
- ASSERT_TRUE(symbols.GetName<TypeParam>(0x1003, &this->memory_, &name, &func_offset));
- ASSERT_EQ("third_entry", name);
- ASSERT_EQ(3U, func_offset);
-}
-
-TYPED_TEST_P(SymbolsTest, get_global) {
- uint64_t start_offset = 0x1000;
- uint64_t str_offset = 0xa000;
- Symbols symbols(start_offset, 4 * sizeof(TypeParam), sizeof(TypeParam), str_offset, 0x1000);
-
- TypeParam sym;
- memset(&sym, 0, sizeof(sym));
- sym.st_shndx = SHN_COMMON;
- sym.st_info = STT_OBJECT | (STB_GLOBAL << 4);
- sym.st_name = 0x100;
- this->memory_.SetMemory(start_offset, &sym, sizeof(sym));
- this->memory_.SetMemory(str_offset + 0x100, "global_0");
-
- start_offset += sizeof(sym);
- memset(&sym, 0, sizeof(sym));
- sym.st_shndx = SHN_COMMON;
- sym.st_info = STT_FUNC;
- sym.st_name = 0x200;
- sym.st_value = 0x10000;
- sym.st_size = 0x100;
- this->memory_.SetMemory(start_offset, &sym, sizeof(sym));
- this->memory_.SetMemory(str_offset + 0x200, "function_0");
-
- start_offset += sizeof(sym);
- memset(&sym, 0, sizeof(sym));
- sym.st_shndx = SHN_COMMON;
- sym.st_info = STT_OBJECT | (STB_GLOBAL << 4);
- sym.st_name = 0x300;
- this->memory_.SetMemory(start_offset, &sym, sizeof(sym));
- this->memory_.SetMemory(str_offset + 0x300, "global_1");
-
- start_offset += sizeof(sym);
- memset(&sym, 0, sizeof(sym));
- sym.st_shndx = SHN_COMMON;
- sym.st_info = STT_FUNC;
- sym.st_name = 0x400;
- sym.st_value = 0x12000;
- sym.st_size = 0x100;
- this->memory_.SetMemory(start_offset, &sym, sizeof(sym));
- this->memory_.SetMemory(str_offset + 0x400, "function_1");
-
- uint64_t offset;
- EXPECT_TRUE(symbols.GetGlobal<TypeParam>(&this->memory_, "global_0", &offset));
- EXPECT_TRUE(symbols.GetGlobal<TypeParam>(&this->memory_, "global_1", &offset));
- EXPECT_TRUE(symbols.GetGlobal<TypeParam>(&this->memory_, "global_0", &offset));
- EXPECT_TRUE(symbols.GetGlobal<TypeParam>(&this->memory_, "global_1", &offset));
-
- EXPECT_FALSE(symbols.GetGlobal<TypeParam>(&this->memory_, "function_0", &offset));
- EXPECT_FALSE(symbols.GetGlobal<TypeParam>(&this->memory_, "function_1", &offset));
-
- std::string name;
- EXPECT_TRUE(symbols.GetName<TypeParam>(0x10002, &this->memory_, &name, &offset));
- EXPECT_EQ("function_0", name);
- EXPECT_EQ(2U, offset);
-
- EXPECT_TRUE(symbols.GetName<TypeParam>(0x12004, &this->memory_, &name, &offset));
- EXPECT_EQ("function_1", name);
- EXPECT_EQ(4U, offset);
-}
-
-REGISTER_TYPED_TEST_SUITE_P(SymbolsTest, function_bounds_check, no_symbol, multiple_entries,
- multiple_entries_nonstandard_size, symtab_value_out_of_bounds,
- symtab_read_cached, get_global);
-
-typedef ::testing::Types<Elf32_Sym, Elf64_Sym> SymbolsTestTypes;
-INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, SymbolsTest, SymbolsTestTypes);
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/TestLocal.cpp b/libunwindstack/tests/TestLocal.cpp
deleted file mode 100644
index fa0baff..0000000
--- a/libunwindstack/tests/TestLocal.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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 <unwindstack/LocalUnwinder.h>
-
-#include <vector>
-
-extern "C" void TestlibLevel4(void* unwinder_data, void* frame_data) {
- unwindstack::LocalUnwinder* unwinder =
- reinterpret_cast<unwindstack::LocalUnwinder*>(unwinder_data);
- std::vector<unwindstack::LocalFrameData>* frame_info =
- reinterpret_cast<std::vector<unwindstack::LocalFrameData>*>(frame_data);
- unwinder->Unwind(frame_info, 256);
-}
-
-extern "C" void TestlibLevel3(void* unwinder_data, void* frame_data) {
- TestlibLevel4(unwinder_data, frame_data);
-}
-
-extern "C" void TestlibLevel2(void* unwinder_data, void* frame_data) {
- TestlibLevel3(unwinder_data, frame_data);
-}
-
-extern "C" void TestlibLevel1(void* unwinder_data, void* frame_data) {
- TestlibLevel2(unwinder_data, frame_data);
-}
diff --git a/libunwindstack/tests/TestUtils.cpp b/libunwindstack/tests/TestUtils.cpp
deleted file mode 100644
index e76f5f8..0000000
--- a/libunwindstack/tests/TestUtils.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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 <malloc.h>
-#include <stdint.h>
-
-#include <gtest/gtest.h>
-
-namespace unwindstack {
-
-void TestCheckForLeaks(void (*unwind_func)(void*), void* data) {
- static constexpr size_t kNumLeakLoops = 200;
- static constexpr size_t kMaxAllowedLeakBytes = 32 * 1024;
-
- size_t first_allocated_bytes = 0;
- size_t last_allocated_bytes = 0;
- for (size_t i = 0; i < kNumLeakLoops; i++) {
- unwind_func(data);
-
- size_t allocated_bytes = mallinfo().uordblks;
- if (first_allocated_bytes == 0) {
- first_allocated_bytes = allocated_bytes;
- } else if (last_allocated_bytes > first_allocated_bytes) {
- // Check that the memory did not increase too much over the first loop.
- ASSERT_LE(last_allocated_bytes - first_allocated_bytes, kMaxAllowedLeakBytes);
- }
- last_allocated_bytes = allocated_bytes;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
deleted file mode 100644
index 0685006..0000000
--- a/libunwindstack/tests/TestUtils.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2017 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_TESTS_TEST_UTILS_H
-#define _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
-
-#include <signal.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-namespace unwindstack {
-
-class TestScopedPidReaper {
- public:
- TestScopedPidReaper(pid_t pid) : pid_(pid) {}
- ~TestScopedPidReaper() {
- kill(pid_, SIGKILL);
- waitpid(pid_, nullptr, 0);
- }
-
- private:
- pid_t pid_;
-};
-
-inline bool TestQuiescePid(pid_t pid) {
- siginfo_t si;
- bool ready = false;
- // Wait for up to 5 seconds.
- for (size_t i = 0; i < 5000; i++) {
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- ready = true;
- break;
- }
- usleep(1000);
- }
- return ready;
-}
-
-inline bool TestAttach(pid_t pid) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == -1) {
- return false;
- }
-
- return TestQuiescePid(pid);
-}
-
-inline bool TestDetach(pid_t pid) {
- return ptrace(PTRACE_DETACH, pid, 0, 0) == 0;
-}
-
-void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
-
-} // namespace unwindstack
-
-#endif // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
deleted file mode 100644
index c2bd836..0000000
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ /dev/null
@@ -1,1739 +0,0 @@
-/*
- * Copyright (C) 2017 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 <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/file.h>
-
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/MachineArm.h>
-#include <unwindstack/MachineArm64.h>
-#include <unwindstack/MachineX86.h>
-#include <unwindstack/MachineX86_64.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-#include <unwindstack/Unwinder.h>
-
-#include "ElfTestUtils.h"
-#include "MemoryOffline.h"
-#include "TestUtils.h"
-
-namespace unwindstack {
-
-static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
- MemoryOffline* memory = new MemoryOffline;
- ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
- parts->Add(memory);
-}
-
-class UnwindOfflineTest : public ::testing::Test {
- protected:
- void TearDown() override {
- if (cwd_ != nullptr) {
- ASSERT_EQ(0, chdir(cwd_));
- }
- free(cwd_);
- }
-
- void Init(const char* file_dir, ArchEnum arch, bool add_stack = true) {
- dir_ = TestGetFileDirectory() + "offline/" + file_dir;
-
- std::string data;
- ASSERT_TRUE(android::base::ReadFileToString((dir_ + "maps.txt"), &data));
-
- maps_.reset(new BufferMaps(data.c_str()));
- ASSERT_TRUE(maps_->Parse());
-
- if (add_stack) {
- std::string stack_name(dir_ + "stack.data");
- struct stat st;
- if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
- std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
- ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
- process_memory_.reset(stack_memory.release());
- } else {
- std::unique_ptr<MemoryOfflineParts> stack_memory(new MemoryOfflineParts);
- for (size_t i = 0;; i++) {
- stack_name = dir_ + "stack" + std::to_string(i) + ".data";
- if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) {
- ASSERT_TRUE(i != 0) << "No stack data files found.";
- break;
- }
- AddMemory(stack_name, stack_memory.get());
- }
- process_memory_.reset(stack_memory.release());
- }
- }
-
- switch (arch) {
- case ARCH_ARM: {
- RegsArm* regs = new RegsArm;
- regs_.reset(regs);
- ReadRegs<uint32_t>(regs, arm_regs_);
- break;
- }
- case ARCH_ARM64: {
- RegsArm64* regs = new RegsArm64;
- regs_.reset(regs);
- ReadRegs<uint64_t>(regs, arm64_regs_);
- break;
- }
- case ARCH_X86: {
- RegsX86* regs = new RegsX86;
- regs_.reset(regs);
- ReadRegs<uint32_t>(regs, x86_regs_);
- break;
- }
- case ARCH_X86_64: {
- RegsX86_64* regs = new RegsX86_64;
- regs_.reset(regs);
- ReadRegs<uint64_t>(regs, x86_64_regs_);
- break;
- }
- default:
- ASSERT_TRUE(false) << "Unknown arch " << std::to_string(arch);
- }
- cwd_ = getcwd(nullptr, 0);
- // Make dir_ an absolute directory.
- if (dir_.empty() || dir_[0] != '/') {
- dir_ = std::string(cwd_) + '/' + dir_;
- }
- ASSERT_EQ(0, chdir(dir_.c_str()));
- }
-
- template <typename AddressType>
- void ReadRegs(RegsImpl<AddressType>* regs,
- const std::unordered_map<std::string, uint32_t>& name_to_reg) {
- FILE* fp = fopen((dir_ + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- while (!feof(fp)) {
- uint64_t value;
- char reg_name[100];
- ASSERT_EQ(2, fscanf(fp, "%s %" SCNx64 "\n", reg_name, &value));
- std::string name(reg_name);
- if (!name.empty()) {
- // Remove the : from the end.
- name.resize(name.size() - 1);
- }
- auto entry = name_to_reg.find(name);
- ASSERT_TRUE(entry != name_to_reg.end()) << "Unknown register named " << name;
- (*regs)[entry->second] = value;
- }
- fclose(fp);
- }
-
- static std::unordered_map<std::string, uint32_t> arm_regs_;
- static std::unordered_map<std::string, uint32_t> arm64_regs_;
- static std::unordered_map<std::string, uint32_t> x86_regs_;
- static std::unordered_map<std::string, uint32_t> x86_64_regs_;
-
- char* cwd_ = nullptr;
- std::string dir_;
- std::unique_ptr<Regs> regs_;
- std::unique_ptr<Maps> maps_;
- std::shared_ptr<Memory> process_memory_;
-};
-
-std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm_regs_ = {
- {"r0", ARM_REG_R0}, {"r1", ARM_REG_R1}, {"r2", ARM_REG_R2}, {"r3", ARM_REG_R3},
- {"r4", ARM_REG_R4}, {"r5", ARM_REG_R5}, {"r6", ARM_REG_R6}, {"r7", ARM_REG_R7},
- {"r8", ARM_REG_R8}, {"r9", ARM_REG_R9}, {"r10", ARM_REG_R10}, {"r11", ARM_REG_R11},
- {"ip", ARM_REG_R12}, {"sp", ARM_REG_SP}, {"lr", ARM_REG_LR}, {"pc", ARM_REG_PC},
-};
-
-std::unordered_map<std::string, uint32_t> UnwindOfflineTest::arm64_regs_ = {
- {"x0", ARM64_REG_R0}, {"x1", ARM64_REG_R1}, {"x2", ARM64_REG_R2},
- {"x3", ARM64_REG_R3}, {"x4", ARM64_REG_R4}, {"x5", ARM64_REG_R5},
- {"x6", ARM64_REG_R6}, {"x7", ARM64_REG_R7}, {"x8", ARM64_REG_R8},
- {"x9", ARM64_REG_R9}, {"x10", ARM64_REG_R10}, {"x11", ARM64_REG_R11},
- {"x12", ARM64_REG_R12}, {"x13", ARM64_REG_R13}, {"x14", ARM64_REG_R14},
- {"x15", ARM64_REG_R15}, {"x16", ARM64_REG_R16}, {"x17", ARM64_REG_R17},
- {"x18", ARM64_REG_R18}, {"x19", ARM64_REG_R19}, {"x20", ARM64_REG_R20},
- {"x21", ARM64_REG_R21}, {"x22", ARM64_REG_R22}, {"x23", ARM64_REG_R23},
- {"x24", ARM64_REG_R24}, {"x25", ARM64_REG_R25}, {"x26", ARM64_REG_R26},
- {"x27", ARM64_REG_R27}, {"x28", ARM64_REG_R28}, {"x29", ARM64_REG_R29},
- {"sp", ARM64_REG_SP}, {"lr", ARM64_REG_LR}, {"pc", ARM64_REG_PC},
- {"pst", ARM64_REG_PSTATE},
-};
-
-std::unordered_map<std::string, uint32_t> UnwindOfflineTest::x86_regs_ = {
- {"eax", X86_REG_EAX}, {"ebx", X86_REG_EBX}, {"ecx", X86_REG_ECX},
- {"edx", X86_REG_EDX}, {"ebp", X86_REG_EBP}, {"edi", X86_REG_EDI},
- {"esi", X86_REG_ESI}, {"esp", X86_REG_ESP}, {"eip", X86_REG_EIP},
-};
-
-std::unordered_map<std::string, uint32_t> UnwindOfflineTest::x86_64_regs_ = {
- {"rax", X86_64_REG_RAX}, {"rbx", X86_64_REG_RBX}, {"rcx", X86_64_REG_RCX},
- {"rdx", X86_64_REG_RDX}, {"r8", X86_64_REG_R8}, {"r9", X86_64_REG_R9},
- {"r10", X86_64_REG_R10}, {"r11", X86_64_REG_R11}, {"r12", X86_64_REG_R12},
- {"r13", X86_64_REG_R13}, {"r14", X86_64_REG_R14}, {"r15", X86_64_REG_R15},
- {"rdi", X86_64_REG_RDI}, {"rsi", X86_64_REG_RSI}, {"rbp", X86_64_REG_RBP},
- {"rsp", X86_64_REG_RSP}, {"rip", X86_64_REG_RIP},
-};
-
-static std::string DumpFrames(Unwinder& unwinder) {
- std::string str;
- for (size_t i = 0; i < unwinder.NumFrames(); i++) {
- str += unwinder.FormatFrame(i) + "\n";
- }
- return str;
-}
-
-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();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0001a9f8 libc.so (abort+64)\n"
- " #01 pc 00006a1b libbase.so (android::base::DefaultAborter(char const*)+6)\n"
- " #02 pc 00007441 libbase.so (android::base::LogMessage::~LogMessage()+748)\n"
- " #03 pc 00015147 /does/not/exist/libhidlbase.so\n",
- frame_info);
- EXPECT_EQ(0xf31ea9f8U, unwinder.frames()[0].pc);
- EXPECT_EQ(0xe9c866f8U, unwinder.frames()[0].sp);
- EXPECT_EQ(0xf2da0a1bU, unwinder.frames()[1].pc);
- EXPECT_EQ(0xe9c86728U, unwinder.frames()[1].sp);
- EXPECT_EQ(0xf2da1441U, unwinder.frames()[2].pc);
- 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) {
- ASSERT_NO_FATAL_FAILURE(Init("gnu_debugdata_arm/", ARCH_ARM));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(2U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0006dc49 libandroid_runtime.so "
- "(android::AndroidRuntime::javaThreadShell(void*)+80)\n"
- " #01 pc 0006dce5 libandroid_runtime.so "
- "(android::AndroidRuntime::javaCreateThreadEtc(int (*)(void*), void*, char const*, int, "
- "unsigned int, void**))\n",
- frame_info);
- EXPECT_EQ(0xf1f6dc49U, unwinder.frames()[0].pc);
- EXPECT_EQ(0xd8fe6930U, unwinder.frames()[0].sp);
- EXPECT_EQ(0xf1f6dce5U, unwinder.frames()[1].pc);
- EXPECT_EQ(0xd8fe6958U, unwinder.frames()[1].sp);
-}
-
-TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
- ASSERT_NO_FATAL_FAILURE(Init("straddle_arm64/", ARCH_ARM64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0000000000429fd8 libunwindstack_test (SignalInnerFunction+24)\n"
- " #01 pc 000000000042a078 libunwindstack_test (SignalMiddleFunction+8)\n"
- " #02 pc 000000000042a08c libunwindstack_test (SignalOuterFunction+8)\n"
- " #03 pc 000000000042d8fc libunwindstack_test "
- "(unwindstack::RemoteThroughSignal(int, unsigned int)+20)\n"
- " #04 pc 000000000042d8d8 libunwindstack_test "
- "(unwindstack::UnwindTest_remote_through_signal_Test::TestBody()+32)\n"
- " #05 pc 0000000000455d70 libunwindstack_test (testing::Test::Run()+392)\n",
- frame_info);
- EXPECT_EQ(0x64d09d4fd8U, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7fe0d84040U, unwinder.frames()[0].sp);
- EXPECT_EQ(0x64d09d5078U, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7fe0d84070U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x64d09d508cU, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7fe0d84080U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x64d09d88fcU, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7fe0d84090U, unwinder.frames()[3].sp);
- EXPECT_EQ(0x64d09d88d8U, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7fe0d840f0U, unwinder.frames()[4].sp);
- EXPECT_EQ(0x64d0a00d70U, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7fe0d84110U, unwinder.frames()[5].sp);
-}
-
-TEST_F(UnwindOfflineTest, jit_debug_x86) {
- ASSERT_NO_FATAL_FAILURE(Init("jit_debug_x86/", ARCH_X86));
-
- MemoryOfflineParts* memory = new MemoryOfflineParts;
- AddMemory(dir_ + "descriptor.data", memory);
- AddMemory(dir_ + "stack.data", memory);
- for (size_t i = 0; i < 7; i++) {
- AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
- AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
- }
- 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));
- ASSERT_EQ(69U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00068fb8 libarttestd.so (art::CauseSegfault()+72)\n"
- " #01 pc 00067f00 libarttestd.so (Java_Main_unwindInProcess+10032)\n"
- " #02 pc 000021a8 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
- "boolean)+136)\n"
- " #03 pc 0000fe80 anonymous:ee74c000 (boolean Main.bar(boolean)+64)\n"
- " #04 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
- " #05 pc 00146ab5 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+885)\n"
- " #06 pc 0039cf0d libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
- " #07 pc 00392552 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+354)\n"
- " #08 pc 0039399a libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+234)\n"
- " #09 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
- " #10 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
- " #11 pc 0000fe03 anonymous:ee74c000 (int Main.compare(Main, Main)+51)\n"
- " #12 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
- " #13 pc 00146ab5 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+885)\n"
- " #14 pc 0039cf0d libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
- " #15 pc 00392552 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+354)\n"
- " #16 pc 0039399a libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+234)\n"
- " #17 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
- " #18 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
- " #19 pc 0000fd3b anonymous:ee74c000 (int Main.compare(java.lang.Object, "
- "java.lang.Object)+107)\n"
- " #20 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
- " #21 pc 00146ab5 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+885)\n"
- " #22 pc 0039cf0d libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
- " #23 pc 00392552 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+354)\n"
- " #24 pc 0039399a libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+234)\n"
- " #25 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
- " #26 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
- " #27 pc 0000fbdb anonymous:ee74c000 (int "
- "java.util.Arrays.binarySearch0(java.lang.Object[], int, int, java.lang.Object, "
- "java.util.Comparator)+331)\n"
- " #28 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)\n"
- " #29 pc 00146acb libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+907)\n"
- " #30 pc 0039cf0d libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
- " #31 pc 00392552 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+354)\n"
- " #32 pc 0039399a libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+234)\n"
- " #33 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
- " #34 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
- " #35 pc 0000f624 anonymous:ee74c000 (boolean Main.foo()+164)\n"
- " #36 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
- " #37 pc 00146ab5 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+885)\n"
- " #38 pc 0039cf0d libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
- " #39 pc 00392552 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+354)\n"
- " #40 pc 0039399a libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+234)\n"
- " #41 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
- " #42 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
- " #43 pc 0000eedb anonymous:ee74c000 (void Main.runPrimary()+59)\n"
- " #44 pc 006ad4d2 libartd.so (art_quick_invoke_stub+338)\n"
- " #45 pc 00146ab5 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+885)\n"
- " #46 pc 0039cf0d libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
- " #47 pc 00392552 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+354)\n"
- " #48 pc 0039399a libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+234)\n"
- " #49 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
- " #50 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
- " #51 pc 0000ac21 anonymous:ee74c000 (void Main.main(java.lang.String[])+97)\n"
- " #52 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)\n"
- " #53 pc 00146acb libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+907)\n"
- " #54 pc 0039cf0d libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+653)\n"
- " #55 pc 00392552 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+354)\n"
- " #56 pc 0039399a libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+234)\n"
- " #57 pc 00684362 libartd.so (artQuickToInterpreterBridge+1058)\n"
- " #58 pc 006b35bd libartd.so (art_quick_to_interpreter_bridge+77)\n"
- " #59 pc 006ad6a2 libartd.so (art_quick_invoke_static_stub+418)\n"
- " #60 pc 00146acb libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+907)\n"
- " #61 pc 005aac95 libartd.so "
- "(art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, "
- "art::ArgArray*, art::JValue*, char const*)+85)\n"
- " #62 pc 005aab5a libartd.so "
- "(art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, "
- "_jmethodID*, char*)+362)\n"
- " #63 pc 0048a3dd libartd.so "
- "(art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, char*)+125)\n"
- " #64 pc 0018448c libartd.so "
- "(art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, char*, "
- "art::Primitive::Type, art::InvokeType)+1964)\n"
- " #65 pc 0017cf06 libartd.so "
- "(art::CheckJNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, char*)+70)\n"
- " #66 pc 00001d8c dalvikvm32 "
- "(_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+60)\n"
- " #67 pc 00001a80 dalvikvm32 (main+1312)\n"
- " #68 pc 00018275 libc.so\n",
- frame_info);
- EXPECT_EQ(0xeb89bfb8U, unwinder.frames()[0].pc);
- EXPECT_EQ(0xffeb5280U, unwinder.frames()[0].sp);
- EXPECT_EQ(0xeb89af00U, unwinder.frames()[1].pc);
- EXPECT_EQ(0xffeb52a0U, unwinder.frames()[1].sp);
- EXPECT_EQ(0xec6061a8U, unwinder.frames()[2].pc);
- EXPECT_EQ(0xffeb5ce0U, unwinder.frames()[2].sp);
- EXPECT_EQ(0xee75be80U, unwinder.frames()[3].pc);
- EXPECT_EQ(0xffeb5d30U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xf728e4d2U, unwinder.frames()[4].pc);
- EXPECT_EQ(0xffeb5d60U, unwinder.frames()[4].sp);
- EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[5].pc);
- EXPECT_EQ(0xffeb5d80U, unwinder.frames()[5].sp);
- EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[6].pc);
- EXPECT_EQ(0xffeb5e20U, unwinder.frames()[6].sp);
- EXPECT_EQ(0xf6f73552U, unwinder.frames()[7].pc);
- EXPECT_EQ(0xffeb5ec0U, unwinder.frames()[7].sp);
- EXPECT_EQ(0xf6f7499aU, unwinder.frames()[8].pc);
- EXPECT_EQ(0xffeb5f40U, unwinder.frames()[8].sp);
- EXPECT_EQ(0xf7265362U, unwinder.frames()[9].pc);
- EXPECT_EQ(0xffeb5fb0U, unwinder.frames()[9].sp);
- EXPECT_EQ(0xf72945bdU, unwinder.frames()[10].pc);
- EXPECT_EQ(0xffeb6110U, unwinder.frames()[10].sp);
- EXPECT_EQ(0xee75be03U, unwinder.frames()[11].pc);
- EXPECT_EQ(0xffeb6160U, unwinder.frames()[11].sp);
- EXPECT_EQ(0xf728e4d2U, unwinder.frames()[12].pc);
- EXPECT_EQ(0xffeb6180U, unwinder.frames()[12].sp);
- EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[13].pc);
- EXPECT_EQ(0xffeb61b0U, unwinder.frames()[13].sp);
- EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[14].pc);
- EXPECT_EQ(0xffeb6250U, unwinder.frames()[14].sp);
- EXPECT_EQ(0xf6f73552U, unwinder.frames()[15].pc);
- EXPECT_EQ(0xffeb62f0U, unwinder.frames()[15].sp);
- EXPECT_EQ(0xf6f7499aU, unwinder.frames()[16].pc);
- EXPECT_EQ(0xffeb6370U, unwinder.frames()[16].sp);
- EXPECT_EQ(0xf7265362U, unwinder.frames()[17].pc);
- EXPECT_EQ(0xffeb63e0U, unwinder.frames()[17].sp);
- EXPECT_EQ(0xf72945bdU, unwinder.frames()[18].pc);
- EXPECT_EQ(0xffeb6530U, unwinder.frames()[18].sp);
- EXPECT_EQ(0xee75bd3bU, unwinder.frames()[19].pc);
- EXPECT_EQ(0xffeb6580U, unwinder.frames()[19].sp);
- EXPECT_EQ(0xf728e4d2U, unwinder.frames()[20].pc);
- EXPECT_EQ(0xffeb65b0U, unwinder.frames()[20].sp);
- EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[21].pc);
- EXPECT_EQ(0xffeb65e0U, unwinder.frames()[21].sp);
- EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[22].pc);
- EXPECT_EQ(0xffeb6680U, unwinder.frames()[22].sp);
- EXPECT_EQ(0xf6f73552U, unwinder.frames()[23].pc);
- EXPECT_EQ(0xffeb6720U, unwinder.frames()[23].sp);
- EXPECT_EQ(0xf6f7499aU, unwinder.frames()[24].pc);
- EXPECT_EQ(0xffeb67a0U, unwinder.frames()[24].sp);
- EXPECT_EQ(0xf7265362U, unwinder.frames()[25].pc);
- EXPECT_EQ(0xffeb6810U, unwinder.frames()[25].sp);
- EXPECT_EQ(0xf72945bdU, unwinder.frames()[26].pc);
- EXPECT_EQ(0xffeb6960U, unwinder.frames()[26].sp);
- EXPECT_EQ(0xee75bbdbU, unwinder.frames()[27].pc);
- EXPECT_EQ(0xffeb69b0U, unwinder.frames()[27].sp);
- EXPECT_EQ(0xf728e6a2U, unwinder.frames()[28].pc);
- EXPECT_EQ(0xffeb69f0U, unwinder.frames()[28].sp);
- EXPECT_EQ(0xf6d27acbU, unwinder.frames()[29].pc);
- EXPECT_EQ(0xffeb6a20U, unwinder.frames()[29].sp);
- EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[30].pc);
- EXPECT_EQ(0xffeb6ac0U, unwinder.frames()[30].sp);
- EXPECT_EQ(0xf6f73552U, unwinder.frames()[31].pc);
- EXPECT_EQ(0xffeb6b60U, unwinder.frames()[31].sp);
- EXPECT_EQ(0xf6f7499aU, unwinder.frames()[32].pc);
- EXPECT_EQ(0xffeb6be0U, unwinder.frames()[32].sp);
- EXPECT_EQ(0xf7265362U, unwinder.frames()[33].pc);
- EXPECT_EQ(0xffeb6c50U, unwinder.frames()[33].sp);
- EXPECT_EQ(0xf72945bdU, unwinder.frames()[34].pc);
- EXPECT_EQ(0xffeb6dd0U, unwinder.frames()[34].sp);
- EXPECT_EQ(0xee75b624U, unwinder.frames()[35].pc);
- EXPECT_EQ(0xffeb6e20U, unwinder.frames()[35].sp);
- EXPECT_EQ(0xf728e4d2U, unwinder.frames()[36].pc);
- EXPECT_EQ(0xffeb6e50U, unwinder.frames()[36].sp);
- EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[37].pc);
- EXPECT_EQ(0xffeb6e70U, unwinder.frames()[37].sp);
- EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[38].pc);
- EXPECT_EQ(0xffeb6f10U, unwinder.frames()[38].sp);
- EXPECT_EQ(0xf6f73552U, unwinder.frames()[39].pc);
- EXPECT_EQ(0xffeb6fb0U, unwinder.frames()[39].sp);
- EXPECT_EQ(0xf6f7499aU, unwinder.frames()[40].pc);
- EXPECT_EQ(0xffeb7030U, unwinder.frames()[40].sp);
- EXPECT_EQ(0xf7265362U, unwinder.frames()[41].pc);
- EXPECT_EQ(0xffeb70a0U, unwinder.frames()[41].sp);
- EXPECT_EQ(0xf72945bdU, unwinder.frames()[42].pc);
- EXPECT_EQ(0xffeb71f0U, unwinder.frames()[42].sp);
- EXPECT_EQ(0xee75aedbU, unwinder.frames()[43].pc);
- EXPECT_EQ(0xffeb7240U, unwinder.frames()[43].sp);
- EXPECT_EQ(0xf728e4d2U, unwinder.frames()[44].pc);
- EXPECT_EQ(0xffeb72a0U, unwinder.frames()[44].sp);
- EXPECT_EQ(0xf6d27ab5U, unwinder.frames()[45].pc);
- EXPECT_EQ(0xffeb72c0U, unwinder.frames()[45].sp);
- EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[46].pc);
- EXPECT_EQ(0xffeb7360U, unwinder.frames()[46].sp);
- EXPECT_EQ(0xf6f73552U, unwinder.frames()[47].pc);
- EXPECT_EQ(0xffeb7400U, unwinder.frames()[47].sp);
- EXPECT_EQ(0xf6f7499aU, unwinder.frames()[48].pc);
- EXPECT_EQ(0xffeb7480U, unwinder.frames()[48].sp);
- EXPECT_EQ(0xf7265362U, unwinder.frames()[49].pc);
- EXPECT_EQ(0xffeb74f0U, unwinder.frames()[49].sp);
- EXPECT_EQ(0xf72945bdU, unwinder.frames()[50].pc);
- EXPECT_EQ(0xffeb7680U, unwinder.frames()[50].sp);
- EXPECT_EQ(0xee756c21U, unwinder.frames()[51].pc);
- EXPECT_EQ(0xffeb76d0U, unwinder.frames()[51].sp);
- EXPECT_EQ(0xf728e6a2U, unwinder.frames()[52].pc);
- EXPECT_EQ(0xffeb76f0U, unwinder.frames()[52].sp);
- EXPECT_EQ(0xf6d27acbU, unwinder.frames()[53].pc);
- EXPECT_EQ(0xffeb7710U, unwinder.frames()[53].sp);
- EXPECT_EQ(0xf6f7df0dU, unwinder.frames()[54].pc);
- EXPECT_EQ(0xffeb77b0U, unwinder.frames()[54].sp);
- EXPECT_EQ(0xf6f73552U, unwinder.frames()[55].pc);
- EXPECT_EQ(0xffeb7850U, unwinder.frames()[55].sp);
- EXPECT_EQ(0xf6f7499aU, unwinder.frames()[56].pc);
- EXPECT_EQ(0xffeb78d0U, unwinder.frames()[56].sp);
- EXPECT_EQ(0xf7265362U, unwinder.frames()[57].pc);
- EXPECT_EQ(0xffeb7940U, unwinder.frames()[57].sp);
- EXPECT_EQ(0xf72945bdU, unwinder.frames()[58].pc);
- EXPECT_EQ(0xffeb7a80U, unwinder.frames()[58].sp);
- EXPECT_EQ(0xf728e6a2U, unwinder.frames()[59].pc);
- EXPECT_EQ(0xffeb7ad0U, unwinder.frames()[59].sp);
- EXPECT_EQ(0xf6d27acbU, unwinder.frames()[60].pc);
- EXPECT_EQ(0xffeb7af0U, unwinder.frames()[60].sp);
- EXPECT_EQ(0xf718bc95U, unwinder.frames()[61].pc);
- EXPECT_EQ(0xffeb7b90U, unwinder.frames()[61].sp);
- EXPECT_EQ(0xf718bb5aU, unwinder.frames()[62].pc);
- EXPECT_EQ(0xffeb7c50U, unwinder.frames()[62].sp);
- EXPECT_EQ(0xf706b3ddU, unwinder.frames()[63].pc);
- EXPECT_EQ(0xffeb7d10U, unwinder.frames()[63].sp);
- EXPECT_EQ(0xf6d6548cU, unwinder.frames()[64].pc);
- EXPECT_EQ(0xffeb7d70U, unwinder.frames()[64].sp);
- EXPECT_EQ(0xf6d5df06U, unwinder.frames()[65].pc);
- EXPECT_EQ(0xffeb7df0U, unwinder.frames()[65].sp);
- EXPECT_EQ(0x56574d8cU, unwinder.frames()[66].pc);
- EXPECT_EQ(0xffeb7e40U, unwinder.frames()[66].sp);
- EXPECT_EQ(0x56574a80U, unwinder.frames()[67].pc);
- EXPECT_EQ(0xffeb7e70U, unwinder.frames()[67].sp);
- EXPECT_EQ(0xf7363275U, unwinder.frames()[68].pc);
- EXPECT_EQ(0xffeb7ef0U, unwinder.frames()[68].sp);
-}
-
-TEST_F(UnwindOfflineTest, jit_debug_arm) {
- ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
-
- MemoryOfflineParts* memory = new MemoryOfflineParts;
- AddMemory(dir_ + "descriptor.data", memory);
- AddMemory(dir_ + "descriptor1.data", memory);
- AddMemory(dir_ + "stack.data", memory);
- for (size_t i = 0; i < 7; i++) {
- AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
- AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
- }
- 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));
- ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00018a5e libarttestd.so (Java_Main_unwindInProcess+866)\n"
- " #01 pc 0000212d 137-cfi.odex (boolean Main.unwindInProcess(boolean, int, "
- "boolean)+92)\n"
- " #02 pc 00011cb1 anonymous:e2796000 (boolean Main.bar(boolean)+72)\n"
- " #03 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #04 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
- " #05 pc 000bf7a9 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+864)\n"
- " #06 pc 00247833 libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
- " #07 pc 0022e935 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+244)\n"
- " #08 pc 0022f71d libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+128)\n"
- " #09 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
- " #10 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
- " #11 pc 00011c31 anonymous:e2796000 (int Main.compare(Main, Main)+64)\n"
- " #12 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #13 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
- " #14 pc 000bf7a9 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+864)\n"
- " #15 pc 00247833 libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
- " #16 pc 0022e935 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+244)\n"
- " #17 pc 0022f71d libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+128)\n"
- " #18 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
- " #19 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
- " #20 pc 00011b77 anonymous:e2796000 (int Main.compare(java.lang.Object, "
- "java.lang.Object)+118)\n"
- " #21 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #22 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
- " #23 pc 000bf7a9 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+864)\n"
- " #24 pc 00247833 libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
- " #25 pc 0022e935 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+244)\n"
- " #26 pc 0022f71d libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+128)\n"
- " #27 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
- " #28 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
- " #29 pc 00011a29 anonymous:e2796000 (int "
- "java.util.Arrays.binarySearch0(java.lang.Object[], int, int, java.lang.Object, "
- "java.util.Comparator)+304)\n"
- " #30 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #31 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
- " #32 pc 000bf7bb libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+882)\n"
- " #33 pc 00247833 libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
- " #34 pc 0022e935 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+244)\n"
- " #35 pc 0022f71d libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+128)\n"
- " #36 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
- " #37 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
- " #38 pc 0001139b anonymous:e2796000 (boolean Main.foo()+178)\n"
- " #39 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #40 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
- " #41 pc 000bf7a9 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+864)\n"
- " #42 pc 00247833 libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
- " #43 pc 0022e935 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+244)\n"
- " #44 pc 0022f71d libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+128)\n"
- " #45 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
- " #46 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
- " #47 pc 00010aa7 anonymous:e2796000 (void Main.runPrimary()+70)\n"
- " #48 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #49 pc 00467129 libartd.so (art_quick_invoke_stub+228)\n"
- " #50 pc 000bf7a9 libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+864)\n"
- " #51 pc 00247833 libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
- " #52 pc 0022e935 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+244)\n"
- " #53 pc 0022f71d libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+128)\n"
- " #54 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
- " #55 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
- " #56 pc 0000ba99 anonymous:e2796000 (void Main.main(java.lang.String[])+144)\n"
- " #57 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #58 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
- " #59 pc 000bf7bb libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+882)\n"
- " #60 pc 00247833 libartd.so "
- "(art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, "
- "art::ShadowFrame*, unsigned short, art::JValue*)+382)\n"
- " #61 pc 0022e935 libartd.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+244)\n"
- " #62 pc 0022f71d libartd.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+128)\n"
- " #63 pc 00442865 libartd.so (artQuickToInterpreterBridge+796)\n"
- " #64 pc 004666ff libartd.so (art_quick_to_interpreter_bridge+30)\n"
- " #65 pc 00462175 libartd.so (art_quick_invoke_stub_internal+68)\n"
- " #66 pc 0046722f libartd.so (art_quick_invoke_static_stub+226)\n"
- " #67 pc 000bf7bb libartd.so "
- "(art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char "
- "const*)+882)\n"
- " #68 pc 003b292d libartd.so "
- "(art::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable const&, art::ArtMethod*, "
- "art::ArgArray*, art::JValue*, char const*)+52)\n"
- " #69 pc 003b26c3 libartd.so "
- "(art::InvokeWithVarArgs(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, "
- "_jmethodID*, std::__va_list)+210)\n"
- " #70 pc 00308411 libartd.so "
- "(art::JNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+76)\n"
- " #71 pc 000e6a9f libartd.so "
- "(art::CheckJNI::CallMethodV(char const*, _JNIEnv*, _jobject*, _jclass*, _jmethodID*, "
- "std::__va_list, art::Primitive::Type, art::InvokeType)+1486)\n"
- " #72 pc 000e19b9 libartd.so "
- "(art::CheckJNI::CallStaticVoidMethodV(_JNIEnv*, _jclass*, _jmethodID*, std::__va_list)+40)\n"
- " #73 pc 0000159f dalvikvm32 "
- "(_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)+30)\n"
- " #74 pc 00001349 dalvikvm32 (main+896)\n"
- " #75 pc 000850c9 libc.so\n",
- frame_info);
- EXPECT_EQ(0xdfe66a5eU, unwinder.frames()[0].pc);
- EXPECT_EQ(0xff85d180U, unwinder.frames()[0].sp);
- EXPECT_EQ(0xe044712dU, unwinder.frames()[1].pc);
- EXPECT_EQ(0xff85d200U, unwinder.frames()[1].sp);
- EXPECT_EQ(0xe27a7cb1U, unwinder.frames()[2].pc);
- EXPECT_EQ(0xff85d290U, unwinder.frames()[2].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[3].pc);
- EXPECT_EQ(0xff85d2b0U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xed761129U, unwinder.frames()[4].pc);
- EXPECT_EQ(0xff85d2e8U, unwinder.frames()[4].sp);
- EXPECT_EQ(0xed3b97a9U, unwinder.frames()[5].pc);
- EXPECT_EQ(0xff85d370U, unwinder.frames()[5].sp);
- EXPECT_EQ(0xed541833U, unwinder.frames()[6].pc);
- EXPECT_EQ(0xff85d3d8U, unwinder.frames()[6].sp);
- EXPECT_EQ(0xed528935U, unwinder.frames()[7].pc);
- EXPECT_EQ(0xff85d428U, unwinder.frames()[7].sp);
- EXPECT_EQ(0xed52971dU, unwinder.frames()[8].pc);
- EXPECT_EQ(0xff85d470U, unwinder.frames()[8].sp);
- EXPECT_EQ(0xed73c865U, unwinder.frames()[9].pc);
- EXPECT_EQ(0xff85d4b0U, unwinder.frames()[9].sp);
- EXPECT_EQ(0xed7606ffU, unwinder.frames()[10].pc);
- EXPECT_EQ(0xff85d5d0U, unwinder.frames()[10].sp);
- EXPECT_EQ(0xe27a7c31U, unwinder.frames()[11].pc);
- EXPECT_EQ(0xff85d640U, unwinder.frames()[11].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[12].pc);
- EXPECT_EQ(0xff85d660U, unwinder.frames()[12].sp);
- EXPECT_EQ(0xed761129U, unwinder.frames()[13].pc);
- EXPECT_EQ(0xff85d698U, unwinder.frames()[13].sp);
- EXPECT_EQ(0xed3b97a9U, unwinder.frames()[14].pc);
- EXPECT_EQ(0xff85d720U, unwinder.frames()[14].sp);
- EXPECT_EQ(0xed541833U, unwinder.frames()[15].pc);
- EXPECT_EQ(0xff85d788U, unwinder.frames()[15].sp);
- EXPECT_EQ(0xed528935U, unwinder.frames()[16].pc);
- EXPECT_EQ(0xff85d7d8U, unwinder.frames()[16].sp);
- EXPECT_EQ(0xed52971dU, unwinder.frames()[17].pc);
- EXPECT_EQ(0xff85d820U, unwinder.frames()[17].sp);
- EXPECT_EQ(0xed73c865U, unwinder.frames()[18].pc);
- EXPECT_EQ(0xff85d860U, unwinder.frames()[18].sp);
- EXPECT_EQ(0xed7606ffU, unwinder.frames()[19].pc);
- EXPECT_EQ(0xff85d970U, unwinder.frames()[19].sp);
- EXPECT_EQ(0xe27a7b77U, unwinder.frames()[20].pc);
- EXPECT_EQ(0xff85d9e0U, unwinder.frames()[20].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[21].pc);
- EXPECT_EQ(0xff85da10U, unwinder.frames()[21].sp);
- EXPECT_EQ(0xed761129U, unwinder.frames()[22].pc);
- EXPECT_EQ(0xff85da48U, unwinder.frames()[22].sp);
- EXPECT_EQ(0xed3b97a9U, unwinder.frames()[23].pc);
- EXPECT_EQ(0xff85dad0U, unwinder.frames()[23].sp);
- EXPECT_EQ(0xed541833U, unwinder.frames()[24].pc);
- EXPECT_EQ(0xff85db38U, unwinder.frames()[24].sp);
- EXPECT_EQ(0xed528935U, unwinder.frames()[25].pc);
- EXPECT_EQ(0xff85db88U, unwinder.frames()[25].sp);
- EXPECT_EQ(0xed52971dU, unwinder.frames()[26].pc);
- EXPECT_EQ(0xff85dbd0U, unwinder.frames()[26].sp);
- EXPECT_EQ(0xed73c865U, unwinder.frames()[27].pc);
- EXPECT_EQ(0xff85dc10U, unwinder.frames()[27].sp);
- EXPECT_EQ(0xed7606ffU, unwinder.frames()[28].pc);
- EXPECT_EQ(0xff85dd20U, unwinder.frames()[28].sp);
- EXPECT_EQ(0xe27a7a29U, unwinder.frames()[29].pc);
- EXPECT_EQ(0xff85dd90U, unwinder.frames()[29].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[30].pc);
- EXPECT_EQ(0xff85ddc0U, unwinder.frames()[30].sp);
- EXPECT_EQ(0xed76122fU, unwinder.frames()[31].pc);
- EXPECT_EQ(0xff85de08U, unwinder.frames()[31].sp);
- EXPECT_EQ(0xed3b97bbU, unwinder.frames()[32].pc);
- EXPECT_EQ(0xff85de90U, unwinder.frames()[32].sp);
- EXPECT_EQ(0xed541833U, unwinder.frames()[33].pc);
- EXPECT_EQ(0xff85def8U, unwinder.frames()[33].sp);
- EXPECT_EQ(0xed528935U, unwinder.frames()[34].pc);
- EXPECT_EQ(0xff85df48U, unwinder.frames()[34].sp);
- EXPECT_EQ(0xed52971dU, unwinder.frames()[35].pc);
- EXPECT_EQ(0xff85df90U, unwinder.frames()[35].sp);
- EXPECT_EQ(0xed73c865U, unwinder.frames()[36].pc);
- EXPECT_EQ(0xff85dfd0U, unwinder.frames()[36].sp);
- EXPECT_EQ(0xed7606ffU, unwinder.frames()[37].pc);
- EXPECT_EQ(0xff85e110U, unwinder.frames()[37].sp);
- EXPECT_EQ(0xe27a739bU, unwinder.frames()[38].pc);
- EXPECT_EQ(0xff85e180U, unwinder.frames()[38].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[39].pc);
- EXPECT_EQ(0xff85e1b0U, unwinder.frames()[39].sp);
- EXPECT_EQ(0xed761129U, unwinder.frames()[40].pc);
- EXPECT_EQ(0xff85e1e0U, unwinder.frames()[40].sp);
- EXPECT_EQ(0xed3b97a9U, unwinder.frames()[41].pc);
- EXPECT_EQ(0xff85e268U, unwinder.frames()[41].sp);
- EXPECT_EQ(0xed541833U, unwinder.frames()[42].pc);
- EXPECT_EQ(0xff85e2d0U, unwinder.frames()[42].sp);
- EXPECT_EQ(0xed528935U, unwinder.frames()[43].pc);
- EXPECT_EQ(0xff85e320U, unwinder.frames()[43].sp);
- EXPECT_EQ(0xed52971dU, unwinder.frames()[44].pc);
- EXPECT_EQ(0xff85e368U, unwinder.frames()[44].sp);
- EXPECT_EQ(0xed73c865U, unwinder.frames()[45].pc);
- EXPECT_EQ(0xff85e3a8U, unwinder.frames()[45].sp);
- EXPECT_EQ(0xed7606ffU, unwinder.frames()[46].pc);
- EXPECT_EQ(0xff85e4c0U, unwinder.frames()[46].sp);
- EXPECT_EQ(0xe27a6aa7U, unwinder.frames()[47].pc);
- EXPECT_EQ(0xff85e530U, unwinder.frames()[47].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[48].pc);
- EXPECT_EQ(0xff85e5a0U, unwinder.frames()[48].sp);
- EXPECT_EQ(0xed761129U, unwinder.frames()[49].pc);
- EXPECT_EQ(0xff85e5d8U, unwinder.frames()[49].sp);
- EXPECT_EQ(0xed3b97a9U, unwinder.frames()[50].pc);
- EXPECT_EQ(0xff85e660U, unwinder.frames()[50].sp);
- EXPECT_EQ(0xed541833U, unwinder.frames()[51].pc);
- EXPECT_EQ(0xff85e6c8U, unwinder.frames()[51].sp);
- EXPECT_EQ(0xed528935U, unwinder.frames()[52].pc);
- EXPECT_EQ(0xff85e718U, unwinder.frames()[52].sp);
- EXPECT_EQ(0xed52971dU, unwinder.frames()[53].pc);
- EXPECT_EQ(0xff85e760U, unwinder.frames()[53].sp);
- EXPECT_EQ(0xed73c865U, unwinder.frames()[54].pc);
- EXPECT_EQ(0xff85e7a0U, unwinder.frames()[54].sp);
- EXPECT_EQ(0xed7606ffU, unwinder.frames()[55].pc);
- EXPECT_EQ(0xff85e8f0U, unwinder.frames()[55].sp);
- EXPECT_EQ(0xe27a1a99U, unwinder.frames()[56].pc);
- EXPECT_EQ(0xff85e960U, unwinder.frames()[56].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[57].pc);
- EXPECT_EQ(0xff85e990U, unwinder.frames()[57].sp);
- EXPECT_EQ(0xed76122fU, unwinder.frames()[58].pc);
- EXPECT_EQ(0xff85e9c8U, unwinder.frames()[58].sp);
- EXPECT_EQ(0xed3b97bbU, unwinder.frames()[59].pc);
- EXPECT_EQ(0xff85ea50U, unwinder.frames()[59].sp);
- EXPECT_EQ(0xed541833U, unwinder.frames()[60].pc);
- EXPECT_EQ(0xff85eab8U, unwinder.frames()[60].sp);
- EXPECT_EQ(0xed528935U, unwinder.frames()[61].pc);
- EXPECT_EQ(0xff85eb08U, unwinder.frames()[61].sp);
- EXPECT_EQ(0xed52971dU, unwinder.frames()[62].pc);
- EXPECT_EQ(0xff85eb50U, unwinder.frames()[62].sp);
- EXPECT_EQ(0xed73c865U, unwinder.frames()[63].pc);
- EXPECT_EQ(0xff85eb90U, unwinder.frames()[63].sp);
- EXPECT_EQ(0xed7606ffU, unwinder.frames()[64].pc);
- EXPECT_EQ(0xff85ec90U, unwinder.frames()[64].sp);
- EXPECT_EQ(0xed75c175U, unwinder.frames()[65].pc);
- EXPECT_EQ(0xff85ed00U, unwinder.frames()[65].sp);
- EXPECT_EQ(0xed76122fU, unwinder.frames()[66].pc);
- EXPECT_EQ(0xff85ed38U, unwinder.frames()[66].sp);
- EXPECT_EQ(0xed3b97bbU, unwinder.frames()[67].pc);
- EXPECT_EQ(0xff85edc0U, unwinder.frames()[67].sp);
- EXPECT_EQ(0xed6ac92dU, unwinder.frames()[68].pc);
- EXPECT_EQ(0xff85ee28U, unwinder.frames()[68].sp);
- EXPECT_EQ(0xed6ac6c3U, unwinder.frames()[69].pc);
- EXPECT_EQ(0xff85eeb8U, unwinder.frames()[69].sp);
- EXPECT_EQ(0xed602411U, unwinder.frames()[70].pc);
- EXPECT_EQ(0xff85ef48U, unwinder.frames()[70].sp);
- EXPECT_EQ(0xed3e0a9fU, unwinder.frames()[71].pc);
- EXPECT_EQ(0xff85ef90U, unwinder.frames()[71].sp);
- EXPECT_EQ(0xed3db9b9U, unwinder.frames()[72].pc);
- EXPECT_EQ(0xff85f008U, unwinder.frames()[72].sp);
- EXPECT_EQ(0xab0d459fU, unwinder.frames()[73].pc);
- EXPECT_EQ(0xff85f038U, unwinder.frames()[73].sp);
- EXPECT_EQ(0xab0d4349U, unwinder.frames()[74].pc);
- EXPECT_EQ(0xff85f050U, unwinder.frames()[74].sp);
- EXPECT_EQ(0xedb0d0c9U, unwinder.frames()[75].pc);
- EXPECT_EQ(0xff85f0c0U, unwinder.frames()[75].sp);
-}
-
-struct LeakType {
- LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory)
- : maps(maps), regs(regs), process_memory(process_memory) {}
-
- Maps* maps;
- Regs* regs;
- std::shared_ptr<Memory>& process_memory;
-};
-
-static void OfflineUnwind(void* data) {
- 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());
-}
-
-TEST_F(UnwindOfflineTest, unwind_offline_check_for_leaks) {
- ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
-
- MemoryOfflineParts* memory = new MemoryOfflineParts;
- AddMemory(dir_ + "descriptor.data", memory);
- AddMemory(dir_ + "descriptor1.data", memory);
- AddMemory(dir_ + "stack.data", memory);
- for (size_t i = 0; i < 7; i++) {
- AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
- AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
- }
- process_memory_.reset(memory);
-
- LeakType data(maps_.get(), regs_.get(), process_memory_);
- TestCheckForLeaks(OfflineUnwind, &data);
-}
-
-// The eh_frame_hdr data is present but set to zero fdes. This should
-// fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
-// No .gnu_debugdata section in the elf file, so no symbols.
-TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
- ASSERT_NO_FATAL_FAILURE(Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0000000000000550 waiter64\n"
- " #01 pc 0000000000000568 waiter64\n"
- " #02 pc 000000000000057c waiter64\n"
- " #03 pc 0000000000000590 waiter64\n"
- " #04 pc 00000000000a8e98 libc.so (__libc_init+88)\n",
- frame_info);
- EXPECT_EQ(0x60a9fdf550U, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7fdd141990U, unwinder.frames()[0].sp);
- EXPECT_EQ(0x60a9fdf568U, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7fdd1419a0U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x60a9fdf57cU, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7fdd1419b0U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x60a9fdf590U, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7fdd1419c0U, unwinder.frames()[3].sp);
- EXPECT_EQ(0x7542d68e98U, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7fdd1419d0U, unwinder.frames()[4].sp);
-}
-
-// The elf has bad eh_frame unwind information for the pcs. If eh_frame
-// is used first, the unwind will not match the expected output.
-TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
- ASSERT_NO_FATAL_FAILURE(Init("debug_frame_first_x86/", ARCH_X86));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00000685 waiter (call_level3+53)\n"
- " #01 pc 000006b7 waiter (call_level2+23)\n"
- " #02 pc 000006d7 waiter (call_level1+23)\n"
- " #03 pc 000006f7 waiter (main+23)\n"
- " #04 pc 00018275 libc.so\n",
- frame_info);
- EXPECT_EQ(0x56598685U, unwinder.frames()[0].pc);
- EXPECT_EQ(0xffcf9e38U, unwinder.frames()[0].sp);
- EXPECT_EQ(0x565986b7U, unwinder.frames()[1].pc);
- EXPECT_EQ(0xffcf9e50U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x565986d7U, unwinder.frames()[2].pc);
- EXPECT_EQ(0xffcf9e60U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x565986f7U, unwinder.frames()[3].pc);
- EXPECT_EQ(0xffcf9e70U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xf744a275U, unwinder.frames()[4].pc);
- EXPECT_EQ(0xffcf9e80U, unwinder.frames()[4].sp);
-}
-
-// Make sure that a pc that is at the beginning of an fde unwinds correctly.
-TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
- ASSERT_NO_FATAL_FAILURE(Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0000000000000a80 unwind_test64 (calling3)\n"
- " #01 pc 0000000000000dd9 unwind_test64 (calling2+633)\n"
- " #02 pc 000000000000121e unwind_test64 (calling1+638)\n"
- " #03 pc 00000000000013ed unwind_test64 (main+13)\n"
- " #04 pc 00000000000202b0 libc.so\n",
- frame_info);
- EXPECT_EQ(0x561550b17a80U, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7ffcc8596ce8U, unwinder.frames()[0].sp);
- EXPECT_EQ(0x561550b17dd9U, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7ffcc8596cf0U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x561550b1821eU, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7ffcc8596f40U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x561550b183edU, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7ffcc8597190U, unwinder.frames()[3].sp);
- EXPECT_EQ(0x7f4de62162b0U, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7ffcc85971a0U, unwinder.frames()[4].sp);
-}
-
-TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
- ASSERT_NO_FATAL_FAILURE(Init("art_quick_osr_stub_arm/", ARCH_ARM));
-
- MemoryOfflineParts* memory = new MemoryOfflineParts;
- AddMemory(dir_ + "descriptor.data", memory);
- AddMemory(dir_ + "stack.data", memory);
- for (size_t i = 0; i < 2; i++) {
- AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
- AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
- }
- 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));
- ASSERT_EQ(25U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0000c788 <anonymous:d0250000> "
- "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n"
- " #01 pc 0000cdd5 <anonymous:d0250000> "
- "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n"
- " #02 pc 004135bb libart.so (art_quick_osr_stub+42)\n"
- " #03 pc 002657a5 libart.so "
- "(art::jit::Jit::MaybeDoOnStackReplacement(art::Thread*, art::ArtMethod*, unsigned int, int, "
- "art::JValue*)+876)\n"
- " #04 pc 004021a7 libart.so (MterpMaybeDoOnStackReplacement+86)\n"
- " #05 pc 00412474 libart.so (ExecuteMterpImpl+66164)\n"
- " #06 pc cd8365b0 <unknown>\n" // symbol in dex file
- " #07 pc 001d7f1b libart.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+374)\n"
- " #08 pc 001dc593 libart.so "
- "(art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, "
- "art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*)+154)\n"
- " #09 pc 001f4d01 libart.so "
- "(bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, "
- "art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*)+732)\n"
- " #10 pc 003fe427 libart.so (MterpInvokeInterface+1354)\n"
- " #11 pc 00405b94 libart.so (ExecuteMterpImpl+14740)\n"
- " #12 pc 7004873e <unknown>\n" // symbol in dex file
- " #13 pc 001d7f1b libart.so "
- "(art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, "
- "art::ShadowFrame&, art::JValue, bool)+374)\n"
- " #14 pc 001dc4d5 libart.so "
- "(art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor "
- "const&, art::ShadowFrame*)+92)\n"
- " #15 pc 003f25ab libart.so (artQuickToInterpreterBridge+970)\n"
- " #16 pc 00417aff libart.so (art_quick_to_interpreter_bridge+30)\n"
- " #17 pc 00413575 libart.so (art_quick_invoke_stub_internal+68)\n"
- " #18 pc 00418531 libart.so (art_quick_invoke_stub+236)\n"
- " #19 pc 000b468d libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned "
- "int, art::JValue*, char const*)+136)\n"
- " #20 pc 00362f49 libart.so "
- "(art::(anonymous namespace)::InvokeWithArgArray(art::ScopedObjectAccessAlreadyRunnable "
- "const&, art::ArtMethod*, art::(anonymous namespace)::ArgArray*, art::JValue*, char "
- "const*)+52)\n"
- " #21 pc 00363cd9 libart.so "
- "(art::InvokeVirtualOrInterfaceWithJValues(art::ScopedObjectAccessAlreadyRunnable const&, "
- "_jobject*, _jmethodID*, jvalue*)+332)\n"
- " #22 pc 003851dd libart.so (art::Thread::CreateCallback(void*)+868)\n"
- " #23 pc 00062925 libc.so (__pthread_start(void*)+22)\n"
- " #24 pc 0001de39 libc.so (__start_thread+24)\n",
- frame_info);
- EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc);
- EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp);
- EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc);
- EXPECT_EQ(0xcd4ff140U, unwinder.frames()[1].sp);
- EXPECT_EQ(0xe4a755bbU, unwinder.frames()[2].pc);
- EXPECT_EQ(0xcd4ff160U, unwinder.frames()[2].sp);
- EXPECT_EQ(0xe48c77a5U, unwinder.frames()[3].pc);
- EXPECT_EQ(0xcd4ff190U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xe4a641a7U, unwinder.frames()[4].pc);
- EXPECT_EQ(0xcd4ff298U, unwinder.frames()[4].sp);
- EXPECT_EQ(0xe4a74474U, unwinder.frames()[5].pc);
- EXPECT_EQ(0xcd4ff2b8U, unwinder.frames()[5].sp);
- EXPECT_EQ(0xcd8365b0U, unwinder.frames()[6].pc);
- EXPECT_EQ(0xcd4ff2e0U, unwinder.frames()[6].sp);
- EXPECT_EQ(0xe4839f1bU, unwinder.frames()[7].pc);
- EXPECT_EQ(0xcd4ff2e0U, unwinder.frames()[7].sp);
- EXPECT_EQ(0xe483e593U, unwinder.frames()[8].pc);
- EXPECT_EQ(0xcd4ff330U, unwinder.frames()[8].sp);
- EXPECT_EQ(0xe4856d01U, unwinder.frames()[9].pc);
- EXPECT_EQ(0xcd4ff380U, unwinder.frames()[9].sp);
- EXPECT_EQ(0xe4a60427U, unwinder.frames()[10].pc);
- EXPECT_EQ(0xcd4ff430U, unwinder.frames()[10].sp);
- EXPECT_EQ(0xe4a67b94U, unwinder.frames()[11].pc);
- EXPECT_EQ(0xcd4ff498U, unwinder.frames()[11].sp);
- EXPECT_EQ(0x7004873eU, unwinder.frames()[12].pc);
- EXPECT_EQ(0xcd4ff4c0U, unwinder.frames()[12].sp);
- EXPECT_EQ(0xe4839f1bU, unwinder.frames()[13].pc);
- EXPECT_EQ(0xcd4ff4c0U, unwinder.frames()[13].sp);
- EXPECT_EQ(0xe483e4d5U, unwinder.frames()[14].pc);
- EXPECT_EQ(0xcd4ff510U, unwinder.frames()[14].sp);
- EXPECT_EQ(0xe4a545abU, unwinder.frames()[15].pc);
- EXPECT_EQ(0xcd4ff538U, unwinder.frames()[15].sp);
- EXPECT_EQ(0xe4a79affU, unwinder.frames()[16].pc);
- EXPECT_EQ(0xcd4ff640U, unwinder.frames()[16].sp);
- EXPECT_EQ(0xe4a75575U, unwinder.frames()[17].pc);
- EXPECT_EQ(0xcd4ff6b0U, unwinder.frames()[17].sp);
- EXPECT_EQ(0xe4a7a531U, unwinder.frames()[18].pc);
- EXPECT_EQ(0xcd4ff6e8U, unwinder.frames()[18].sp);
- EXPECT_EQ(0xe471668dU, unwinder.frames()[19].pc);
- EXPECT_EQ(0xcd4ff770U, unwinder.frames()[19].sp);
- EXPECT_EQ(0xe49c4f49U, unwinder.frames()[20].pc);
- EXPECT_EQ(0xcd4ff7c8U, unwinder.frames()[20].sp);
- EXPECT_EQ(0xe49c5cd9U, unwinder.frames()[21].pc);
- EXPECT_EQ(0xcd4ff850U, unwinder.frames()[21].sp);
- EXPECT_EQ(0xe49e71ddU, unwinder.frames()[22].pc);
- EXPECT_EQ(0xcd4ff8e8U, unwinder.frames()[22].sp);
- EXPECT_EQ(0xe7df3925U, unwinder.frames()[23].pc);
- EXPECT_EQ(0xcd4ff958U, unwinder.frames()[23].sp);
- EXPECT_EQ(0xe7daee39U, unwinder.frames()[24].pc);
- EXPECT_EQ(0xcd4ff960U, unwinder.frames()[24].sp);
-}
-
-TEST_F(UnwindOfflineTest, jit_map_arm) {
- ASSERT_NO_FATAL_FAILURE(Init("jit_map_arm/", ARCH_ARM));
-
- maps_->Add(0xd025c788, 0xd025c9f0, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
- "jit_map0.so", 0);
- maps_->Add(0xd025cd98, 0xd025cff4, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
- "jit_map1.so", 0);
- maps_->Sort();
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00000000 jit_map0.so "
- "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity.access$000)\n"
- " #01 pc 0000003d jit_map1.so "
- "(com.example.simpleperf.simpleperfexamplewithnative.MixActivity$1.run+60)\n"
- " #02 pc 004135bb libart.so (art_quick_osr_stub+42)\n"
-
- " #03 pc 003851dd libart.so (art::Thread::CreateCallback(void*)+868)\n"
- " #04 pc 00062925 libc.so (__pthread_start(void*)+22)\n"
- " #05 pc 0001de39 libc.so (__start_thread+24)\n",
- frame_info);
-
- EXPECT_EQ(0xd025c788U, unwinder.frames()[0].pc);
- EXPECT_EQ(0xcd4ff140U, unwinder.frames()[0].sp);
- EXPECT_EQ(0xd025cdd5U, unwinder.frames()[1].pc);
- EXPECT_EQ(0xcd4ff140U, unwinder.frames()[1].sp);
- EXPECT_EQ(0xe4a755bbU, unwinder.frames()[2].pc);
- EXPECT_EQ(0xcd4ff160U, unwinder.frames()[2].sp);
- EXPECT_EQ(0xe49e71ddU, unwinder.frames()[3].pc);
- EXPECT_EQ(0xcd4ff8e8U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xe7df3925U, unwinder.frames()[4].pc);
- EXPECT_EQ(0xcd4ff958U, unwinder.frames()[4].sp);
- EXPECT_EQ(0xe7daee39U, unwinder.frames()[5].pc);
- EXPECT_EQ(0xcd4ff960U, unwinder.frames()[5].sp);
-}
-
-TEST_F(UnwindOfflineTest, offset_arm) {
- ASSERT_NO_FATAL_FAILURE(Init("offset_arm/", ARCH_ARM));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0032bfa0 libunwindstack_test (SignalInnerFunction+40)\n"
- " #01 pc 0032bfeb libunwindstack_test (SignalMiddleFunction+2)\n"
- " #02 pc 0032bff3 libunwindstack_test (SignalOuterFunction+2)\n"
- " #03 pc 0032fed3 libunwindstack_test "
- "(unwindstack::SignalCallerHandler(int, siginfo*, void*)+26)\n"
- " #04 pc 0002652c libc.so (__restore)\n"
- " #05 pc 00000000 <unknown>\n"
- " #06 pc 0032c2d9 libunwindstack_test (InnerFunction+736)\n"
- " #07 pc 0032cc4f libunwindstack_test (MiddleFunction+42)\n"
- " #08 pc 0032cc81 libunwindstack_test (OuterFunction+42)\n"
- " #09 pc 0032e547 libunwindstack_test "
- "(unwindstack::RemoteThroughSignal(int, unsigned int)+270)\n"
- " #10 pc 0032ed99 libunwindstack_test "
- "(unwindstack::UnwindTest_remote_through_signal_with_invalid_func_Test::TestBody()+16)\n"
- " #11 pc 00354453 libunwindstack_test (testing::Test::Run()+154)\n"
- " #12 pc 00354de7 libunwindstack_test (testing::TestInfo::Run()+194)\n"
- " #13 pc 00355105 libunwindstack_test (testing::TestCase::Run()+180)\n"
- " #14 pc 0035a215 libunwindstack_test "
- "(testing::internal::UnitTestImpl::RunAllTests()+664)\n"
- " #15 pc 00359f4f libunwindstack_test (testing::UnitTest::Run()+110)\n"
- " #16 pc 0034d3db libunwindstack_test (main+38)\n"
- " #17 pc 00092c0d libc.so (__libc_init+48)\n"
- " #18 pc 0004202f libunwindstack_test (_start_main+38)\n",
- frame_info);
-
- EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc);
- EXPECT_EQ(0xf43d2cccU, unwinder.frames()[0].sp);
- EXPECT_EQ(0x2e55febU, unwinder.frames()[1].pc);
- EXPECT_EQ(0xf43d2ce0U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x2e55ff3U, unwinder.frames()[2].pc);
- EXPECT_EQ(0xf43d2ce8U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x2e59ed3U, unwinder.frames()[3].pc);
- EXPECT_EQ(0xf43d2cf0U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xf413652cU, unwinder.frames()[4].pc);
- EXPECT_EQ(0xf43d2d10U, unwinder.frames()[4].sp);
- EXPECT_EQ(0U, unwinder.frames()[5].pc);
- EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[5].sp);
- EXPECT_EQ(0x2e562d9U, unwinder.frames()[6].pc);
- EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[6].sp);
- EXPECT_EQ(0x2e56c4fU, unwinder.frames()[7].pc);
- EXPECT_EQ(0xffcc1060U, unwinder.frames()[7].sp);
- EXPECT_EQ(0x2e56c81U, unwinder.frames()[8].pc);
- EXPECT_EQ(0xffcc1078U, unwinder.frames()[8].sp);
- EXPECT_EQ(0x2e58547U, unwinder.frames()[9].pc);
- EXPECT_EQ(0xffcc1090U, unwinder.frames()[9].sp);
- EXPECT_EQ(0x2e58d99U, unwinder.frames()[10].pc);
- EXPECT_EQ(0xffcc1438U, unwinder.frames()[10].sp);
- EXPECT_EQ(0x2e7e453U, unwinder.frames()[11].pc);
- EXPECT_EQ(0xffcc1448U, unwinder.frames()[11].sp);
- EXPECT_EQ(0x2e7ede7U, unwinder.frames()[12].pc);
- EXPECT_EQ(0xffcc1458U, unwinder.frames()[12].sp);
- EXPECT_EQ(0x2e7f105U, unwinder.frames()[13].pc);
- EXPECT_EQ(0xffcc1490U, unwinder.frames()[13].sp);
- EXPECT_EQ(0x2e84215U, unwinder.frames()[14].pc);
- EXPECT_EQ(0xffcc14c0U, unwinder.frames()[14].sp);
- EXPECT_EQ(0x2e83f4fU, unwinder.frames()[15].pc);
- EXPECT_EQ(0xffcc1510U, unwinder.frames()[15].sp);
- EXPECT_EQ(0x2e773dbU, unwinder.frames()[16].pc);
- EXPECT_EQ(0xffcc1528U, unwinder.frames()[16].sp);
- EXPECT_EQ(0xf41a2c0dU, unwinder.frames()[17].pc);
- EXPECT_EQ(0xffcc1540U, unwinder.frames()[17].sp);
- EXPECT_EQ(0x2b6c02fU, unwinder.frames()[18].pc);
- EXPECT_EQ(0xffcc1558U, unwinder.frames()[18].sp);
-}
-
-// Test using a non-zero load bias library that has the fde entries
-// encoded as 0xb, which is not set as pc relative.
-TEST_F(UnwindOfflineTest, debug_frame_load_bias_arm) {
- ASSERT_NO_FATAL_FAILURE(Init("debug_frame_load_bias_arm/", ARCH_ARM));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(8U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0005138c libc.so (__ioctl+8)\n"
- " #01 pc 0002140f libc.so (ioctl+30)\n"
- " #02 pc 00039535 libbinder.so (android::IPCThreadState::talkWithDriver(bool)+204)\n"
- " #03 pc 00039633 libbinder.so (android::IPCThreadState::getAndExecuteCommand()+10)\n"
- " #04 pc 00039b57 libbinder.so (android::IPCThreadState::joinThreadPool(bool)+38)\n"
- " #05 pc 00000c21 mediaserver (main+104)\n"
- " #06 pc 00084b89 libc.so (__libc_init+48)\n"
- " #07 pc 00000b77 mediaserver (_start_main+38)\n",
- frame_info);
-
- EXPECT_EQ(0xf0be238cU, unwinder.frames()[0].pc);
- EXPECT_EQ(0xffd4a638U, unwinder.frames()[0].sp);
- EXPECT_EQ(0xf0bb240fU, unwinder.frames()[1].pc);
- EXPECT_EQ(0xffd4a638U, unwinder.frames()[1].sp);
- EXPECT_EQ(0xf1a75535U, unwinder.frames()[2].pc);
- EXPECT_EQ(0xffd4a650U, unwinder.frames()[2].sp);
- EXPECT_EQ(0xf1a75633U, unwinder.frames()[3].pc);
- EXPECT_EQ(0xffd4a6b0U, unwinder.frames()[3].sp);
- EXPECT_EQ(0xf1a75b57U, unwinder.frames()[4].pc);
- EXPECT_EQ(0xffd4a6d0U, unwinder.frames()[4].sp);
- EXPECT_EQ(0x8d1cc21U, unwinder.frames()[5].pc);
- EXPECT_EQ(0xffd4a6e8U, unwinder.frames()[5].sp);
- EXPECT_EQ(0xf0c15b89U, unwinder.frames()[6].pc);
- EXPECT_EQ(0xffd4a700U, unwinder.frames()[6].sp);
- EXPECT_EQ(0x8d1cb77U, unwinder.frames()[7].pc);
- EXPECT_EQ(0xffd4a718U, unwinder.frames()[7].sp);
-}
-
-TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) {
- ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_arm64/", ARCH_ARM64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
- " #01 pc 000000000005426c linker64 "
- "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
- " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n"
- " #03 pc 00000000000846f4 libc.so (abort+172)\n"
- " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
- " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk!libfeature_support_angle.so (offset 0x4000) "
- "(ANGLEGetUtilityAPI+56)\n"
- " #06 pc 000000000007fe68 libc.so (__libc_init)\n",
- frame_info);
-
- EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
- EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
- EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
- EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp);
- EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp);
- EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc);
- EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp);
- // Ignore top frame since the test code was modified to end in __libc_init.
-}
-
-TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) {
- ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_memory_only_arm64/", ARCH_ARM64));
- // Add the memory that represents the shared library.
- MemoryOfflineParts* memory = reinterpret_cast<MemoryOfflineParts*>(process_memory_.get());
- AddMemory(dir_ + "lib_mem.data", memory);
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n"
- " #01 pc 000000000005426c linker64 "
- "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n"
- " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n"
- " #03 pc 00000000000846f4 libc.so (abort+172)\n"
- " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n"
- " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x21d5000)\n"
- " #06 pc 000000000007fe68 libc.so (__libc_init)\n",
- frame_info);
-
- EXPECT_EQ(0x7e82c4fcbcULL, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp);
- EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp);
- EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp);
- EXPECT_EQ(0x7e7eeccad4ULL, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7dabf3dc40ULL, unwinder.frames()[4].sp);
- EXPECT_EQ(0x7dabc405b4ULL, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7dabf3dc50ULL, unwinder.frames()[5].sp);
- EXPECT_EQ(0x7e7eec7e68ULL, unwinder.frames()[6].pc);
- EXPECT_EQ(0x7dabf3dc70ULL, unwinder.frames()[6].sp);
- // Ignore top frame since the test code was modified to end in __libc_init.
-}
-
-TEST_F(UnwindOfflineTest, shared_lib_in_apk_single_map_arm64) {
- ASSERT_NO_FATAL_FAILURE(Init("shared_lib_in_apk_single_map_arm64/", ARCH_ARM64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(13U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00000000000814bc libc.so (syscall+28)\n"
- " #01 pc 00000000008cdf5c test.apk (offset 0x5000)\n"
- " #02 pc 00000000008cde9c test.apk (offset 0x5000)\n"
- " #03 pc 00000000008cdd70 test.apk (offset 0x5000)\n"
- " #04 pc 00000000008ce408 test.apk (offset 0x5000)\n"
- " #05 pc 00000000008ce8d8 test.apk (offset 0x5000)\n"
- " #06 pc 00000000008ce814 test.apk (offset 0x5000)\n"
- " #07 pc 00000000008bcf60 test.apk (offset 0x5000)\n"
- " #08 pc 0000000000133024 test.apk (offset 0x5000)\n"
- " #09 pc 0000000000134ad0 test.apk (offset 0x5000)\n"
- " #10 pc 0000000000134b64 test.apk (offset 0x5000)\n"
- " #11 pc 00000000000e406c libc.so (__pthread_start(void*)+36)\n"
- " #12 pc 0000000000085e18 libc.so (__start_thread+64)\n",
- frame_info);
-
- EXPECT_EQ(0x7cbe0b14bcULL, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7be4f077d0ULL, unwinder.frames()[0].sp);
- EXPECT_EQ(0x7be6715f5cULL, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7be4f077d0ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7be6715e9cULL, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7be4f07800ULL, unwinder.frames()[2].sp);
- EXPECT_EQ(0x7be6715d70ULL, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7be4f07840ULL, unwinder.frames()[3].sp);
- EXPECT_EQ(0x7be6716408ULL, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7be4f07860ULL, unwinder.frames()[4].sp);
- EXPECT_EQ(0x7be67168d8ULL, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7be4f07880ULL, unwinder.frames()[5].sp);
- EXPECT_EQ(0x7be6716814ULL, unwinder.frames()[6].pc);
- EXPECT_EQ(0x7be4f078f0ULL, unwinder.frames()[6].sp);
- EXPECT_EQ(0x7be6704f60ULL, unwinder.frames()[7].pc);
- EXPECT_EQ(0x7be4f07910ULL, unwinder.frames()[7].sp);
- EXPECT_EQ(0x7be5f7b024ULL, unwinder.frames()[8].pc);
- EXPECT_EQ(0x7be4f07950ULL, unwinder.frames()[8].sp);
- EXPECT_EQ(0x7be5f7cad0ULL, unwinder.frames()[9].pc);
- EXPECT_EQ(0x7be4f07aa0ULL, unwinder.frames()[9].sp);
- EXPECT_EQ(0x7be5f7cb64ULL, unwinder.frames()[10].pc);
- EXPECT_EQ(0x7be4f07ce0ULL, unwinder.frames()[10].sp);
- EXPECT_EQ(0x7cbe11406cULL, unwinder.frames()[11].pc);
- EXPECT_EQ(0x7be4f07d00ULL, unwinder.frames()[11].sp);
- EXPECT_EQ(0x7cbe0b5e18ULL, unwinder.frames()[12].pc);
- EXPECT_EQ(0x7be4f07d20ULL, unwinder.frames()[12].sp);
-}
-
-TEST_F(UnwindOfflineTest, invalid_elf_offset_arm) {
- ASSERT_NO_FATAL_FAILURE(Init("invalid_elf_offset_arm/", ARCH_ARM, false));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(1U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(" #00 pc 00aa7508 invalid.apk (offset 0x12e4000)\n", frame_info);
- EXPECT_EQ(0xc898f508, unwinder.frames()[0].pc);
- EXPECT_EQ(0xc2044218, unwinder.frames()[0].sp);
-}
-
-TEST_F(UnwindOfflineTest, load_bias_ro_rx_x86_64) {
- ASSERT_NO_FATAL_FAILURE(Init("load_bias_ro_rx_x86_64/", ARCH_X86_64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(17U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00000000000e9dd4 libc.so (__write+20)\n"
- " #01 pc 000000000007ab9c libc.so (_IO_file_write+44)\n"
- " #02 pc 0000000000079f3e libc.so\n"
- " #03 pc 000000000007bce8 libc.so (_IO_do_write+24)\n"
- " #04 pc 000000000007b26e libc.so (_IO_file_xsputn+270)\n"
- " #05 pc 000000000004f7f9 libc.so (_IO_vfprintf+1945)\n"
- " #06 pc 0000000000057cb5 libc.so (_IO_printf+165)\n"
- " #07 pc 0000000000ed1796 perfetto_unittests "
- "(testing::internal::PrettyUnitTestResultPrinter::OnTestIterationStart(testing::UnitTest "
- "const&, int)+374)\n"
- " #08 pc 0000000000ed30fd perfetto_unittests "
- "(testing::internal::TestEventRepeater::OnTestIterationStart(testing::UnitTest const&, "
- "int)+125)\n"
- " #09 pc 0000000000ed5e25 perfetto_unittests "
- "(testing::internal::UnitTestImpl::RunAllTests()+581)\n"
- " #10 pc 0000000000ef63f3 perfetto_unittests "
- "(bool "
- "testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, "
- "bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char "
- "const*)+131)\n"
- " #11 pc 0000000000ee2a21 perfetto_unittests "
- "(bool "
- "testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, "
- "bool>(testing::internal::UnitTestImpl*, bool (testing::internal::UnitTestImpl::*)(), char "
- "const*)+113)\n"
- " #12 pc 0000000000ed5bb9 perfetto_unittests (testing::UnitTest::Run()+185)\n"
- " #13 pc 0000000000e900f0 perfetto_unittests (RUN_ALL_TESTS()+16)\n"
- " #14 pc 0000000000e900d8 perfetto_unittests (main+56)\n"
- " #15 pc 000000000002352a libc.so (__libc_start_main+234)\n"
- " #16 pc 0000000000919029 perfetto_unittests (_start+41)\n",
- frame_info);
-
- EXPECT_EQ(0x7f9326a57dd4ULL, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7ffd224153c8ULL, unwinder.frames()[0].sp);
- EXPECT_EQ(0x7f93269e8b9cULL, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7ffd224153d0ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7f93269e7f3eULL, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7ffd22415400ULL, unwinder.frames()[2].sp);
- EXPECT_EQ(0x7f93269e9ce8ULL, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7ffd22415440ULL, unwinder.frames()[3].sp);
- EXPECT_EQ(0x7f93269e926eULL, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7ffd22415450ULL, unwinder.frames()[4].sp);
- EXPECT_EQ(0x7f93269bd7f9ULL, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7ffd22415490ULL, unwinder.frames()[5].sp);
- EXPECT_EQ(0x7f93269c5cb5ULL, unwinder.frames()[6].pc);
- EXPECT_EQ(0x7ffd22415a10ULL, unwinder.frames()[6].sp);
- EXPECT_EQ(0xed1796ULL, unwinder.frames()[7].pc);
- EXPECT_EQ(0x7ffd22415af0ULL, unwinder.frames()[7].sp);
- EXPECT_EQ(0xed30fdULL, unwinder.frames()[8].pc);
- EXPECT_EQ(0x7ffd22415b70ULL, unwinder.frames()[8].sp);
- EXPECT_EQ(0xed5e25ULL, unwinder.frames()[9].pc);
- EXPECT_EQ(0x7ffd22415bb0ULL, unwinder.frames()[9].sp);
- EXPECT_EQ(0xef63f3ULL, unwinder.frames()[10].pc);
- EXPECT_EQ(0x7ffd22415c60ULL, unwinder.frames()[10].sp);
- EXPECT_EQ(0xee2a21ULL, unwinder.frames()[11].pc);
- EXPECT_EQ(0x7ffd22415cc0ULL, unwinder.frames()[11].sp);
- EXPECT_EQ(0xed5bb9ULL, unwinder.frames()[12].pc);
- EXPECT_EQ(0x7ffd22415d40ULL, unwinder.frames()[12].sp);
- EXPECT_EQ(0xe900f0ULL, unwinder.frames()[13].pc);
- EXPECT_EQ(0x7ffd22415d90ULL, unwinder.frames()[13].sp);
- EXPECT_EQ(0xe900d8ULL, unwinder.frames()[14].pc);
- EXPECT_EQ(0x7ffd22415da0ULL, unwinder.frames()[14].sp);
- EXPECT_EQ(0x7f932699152aULL, unwinder.frames()[15].pc);
- EXPECT_EQ(0x7ffd22415dd0ULL, unwinder.frames()[15].sp);
- EXPECT_EQ(0x919029ULL, unwinder.frames()[16].pc);
- EXPECT_EQ(0x7ffd22415e90ULL, unwinder.frames()[16].sp);
-}
-
-TEST_F(UnwindOfflineTest, load_bias_different_section_bias_arm64) {
- ASSERT_NO_FATAL_FAILURE(Init("load_bias_different_section_bias_arm64/", ARCH_ARM64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(12U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00000000000d59bc linker64 (__dl_syscall+28)\n"
- " #01 pc 00000000000554e8 linker64 (__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1148)\n"
- " #02 pc 00000000000008c0 vdso (__kernel_rt_sigreturn)\n"
- " #03 pc 000000000007f3e8 libc.so (abort+168)\n"
- " #04 pc 00000000000459fc test (std::__ndk1::__throw_bad_cast()+4)\n"
- " #05 pc 0000000000056d80 test (testing::Test::Run()+88)\n"
- " #06 pc 000000000005724c test (testing::TestInfo::Run()+112)\n"
- " #07 pc 0000000000057558 test (testing::TestSuite::Run()+116)\n"
- " #08 pc 000000000005bffc test (testing::internal::UnitTestImpl::RunAllTests()+464)\n"
- " #09 pc 000000000005bd9c test (testing::UnitTest::Run()+116)\n"
- " #10 pc 00000000000464e4 test (main+144)\n"
- " #11 pc 000000000007aa34 libc.so (__libc_init+108)\n",
- frame_info);
-
- EXPECT_EQ(0x7112cb99bcULL, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7112bdbbf0ULL, unwinder.frames()[0].sp);
- EXPECT_EQ(0x7112c394e8ULL, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7112bdbbf0ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0x7112be28c0ULL, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7112bdbda0ULL, unwinder.frames()[2].sp);
- EXPECT_EQ(0x71115ab3e8ULL, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7fdd4a3f00ULL, unwinder.frames()[3].sp);
- EXPECT_EQ(0x5f739dc9fcULL, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7fdd4a3fe0ULL, unwinder.frames()[4].sp);
- EXPECT_EQ(0x5f739edd80ULL, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7fdd4a3ff0ULL, unwinder.frames()[5].sp);
- EXPECT_EQ(0x5f739ee24cULL, unwinder.frames()[6].pc);
- EXPECT_EQ(0x7fdd4a4010ULL, unwinder.frames()[6].sp);
- EXPECT_EQ(0x5f739ee558ULL, unwinder.frames()[7].pc);
- EXPECT_EQ(0x7fdd4a4040ULL, unwinder.frames()[7].sp);
- EXPECT_EQ(0x5f739f2ffcULL, unwinder.frames()[8].pc);
- EXPECT_EQ(0x7fdd4a4070ULL, unwinder.frames()[8].sp);
- EXPECT_EQ(0x5f739f2d9cULL, unwinder.frames()[9].pc);
- EXPECT_EQ(0x7fdd4a4100ULL, unwinder.frames()[9].sp);
- EXPECT_EQ(0x5f739dd4e4ULL, unwinder.frames()[10].pc);
- EXPECT_EQ(0x7fdd4a4130ULL, unwinder.frames()[10].sp);
- EXPECT_EQ(0x71115a6a34ULL, unwinder.frames()[11].pc);
- EXPECT_EQ(0x7fdd4a4170ULL, unwinder.frames()[11].sp);
-}
-
-TEST_F(UnwindOfflineTest, eh_frame_bias_x86) {
- ASSERT_NO_FATAL_FAILURE(Init("eh_frame_bias_x86/", ARCH_X86));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(11U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc ffffe430 vdso.so (__kernel_vsyscall+16)\n"
- " #01 pc 00082a4b libc.so (__epoll_pwait+43)\n"
- " #02 pc 000303a3 libc.so (epoll_pwait+115)\n"
- " #03 pc 000303ed libc.so (epoll_wait+45)\n"
- " #04 pc 00010ea2 tombstoned (epoll_dispatch+226)\n"
- " #05 pc 0000c5e7 tombstoned (event_base_loop+1095)\n"
- " #06 pc 0000c193 tombstoned (event_base_dispatch+35)\n"
- " #07 pc 00005c77 tombstoned (main+884)\n"
- " #08 pc 00015f66 libc.so (__libc_init+102)\n"
- " #09 pc 0000360e tombstoned (_start+98)\n"
- " #10 pc 00000001 <unknown>\n",
- frame_info);
-
- EXPECT_EQ(0xffffe430ULL, unwinder.frames()[0].pc);
- EXPECT_EQ(0xfffe1a30ULL, unwinder.frames()[0].sp);
- EXPECT_EQ(0xeb585a4bULL, unwinder.frames()[1].pc);
- EXPECT_EQ(0xfffe1a40ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0xeb5333a3ULL, unwinder.frames()[2].pc);
- EXPECT_EQ(0xfffe1a60ULL, unwinder.frames()[2].sp);
- EXPECT_EQ(0xeb5333edULL, unwinder.frames()[3].pc);
- EXPECT_EQ(0xfffe1ab0ULL, unwinder.frames()[3].sp);
- EXPECT_EQ(0xeb841ea2ULL, unwinder.frames()[4].pc);
- EXPECT_EQ(0xfffe1ae0ULL, unwinder.frames()[4].sp);
- EXPECT_EQ(0xeb83d5e7ULL, unwinder.frames()[5].pc);
- EXPECT_EQ(0xfffe1b30ULL, unwinder.frames()[5].sp);
- EXPECT_EQ(0xeb83d193ULL, unwinder.frames()[6].pc);
- EXPECT_EQ(0xfffe1bd0ULL, unwinder.frames()[6].sp);
- EXPECT_EQ(0xeb836c77ULL, unwinder.frames()[7].pc);
- EXPECT_EQ(0xfffe1c00ULL, unwinder.frames()[7].sp);
- EXPECT_EQ(0xeb518f66ULL, unwinder.frames()[8].pc);
- EXPECT_EQ(0xfffe1d00ULL, unwinder.frames()[8].sp);
- EXPECT_EQ(0xeb83460eULL, unwinder.frames()[9].pc);
- EXPECT_EQ(0xfffe1d40ULL, unwinder.frames()[9].sp);
- EXPECT_EQ(0x00000001ULL, unwinder.frames()[10].pc);
- EXPECT_EQ(0xfffe1d74ULL, unwinder.frames()[10].sp);
-}
-
-TEST_F(UnwindOfflineTest, signal_load_bias_arm) {
- ASSERT_NO_FATAL_FAILURE(Init("signal_load_bias_arm/", ARCH_ARM));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(17U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 0029ef9e libunwindstack_unit_test (SignalInnerFunction+10)\n"
- " #01 pc 0029efa7 libunwindstack_unit_test (SignalMiddleFunction+2)\n"
- " #02 pc 0029efaf libunwindstack_unit_test (SignalOuterFunction+2)\n"
- " #03 pc 002a280b libunwindstack_unit_test (unwindstack::SignalCallerHandler(int, "
- "siginfo*, void*)+10)\n"
- " #04 pc 00058bd4 libc.so (__restore)\n"
- " #05 pc 0029f01e libunwindstack_unit_test (InnerFunction+106)\n"
- " #06 pc 0029f633 libunwindstack_unit_test (MiddleFunction+16)\n"
- " #07 pc 0029f64b libunwindstack_unit_test (OuterFunction+16)\n"
- " #08 pc 002a1711 libunwindstack_unit_test (unwindstack::RemoteThroughSignal(int, unsigned "
- "int)+260)\n"
- " #09 pc 002a1603 libunwindstack_unit_test "
- "(unwindstack::UnwindTest_remote_through_signal_Test::TestBody()+10)\n"
- " #10 pc 002c8fe3 libunwindstack_unit_test (testing::Test::Run()+130)\n"
- " #11 pc 002c9b25 libunwindstack_unit_test (testing::TestInfo::Run()+184)\n"
- " #12 pc 002c9e27 libunwindstack_unit_test (testing::TestSuite::Run()+202)\n"
- " #13 pc 002d193d libunwindstack_unit_test "
- "(testing::internal::UnitTestImpl::RunAllTests()+660)\n"
- " #14 pc 002d160b libunwindstack_unit_test (testing::UnitTest::Run()+134)\n"
- " #15 pc 002de035 libunwindstack_unit_test (IsolateMain+680)\n"
- " #16 pc 00058155 libc.so (__libc_init+68)\n",
- frame_info);
-
- EXPECT_EQ(0xb6955f9eULL, unwinder.frames()[0].pc);
- EXPECT_EQ(0xf2790ce8ULL, unwinder.frames()[0].sp);
- EXPECT_EQ(0xb6955fa7ULL, unwinder.frames()[1].pc);
- EXPECT_EQ(0xf2790ce8ULL, unwinder.frames()[1].sp);
- EXPECT_EQ(0xb6955fafULL, unwinder.frames()[2].pc);
- EXPECT_EQ(0xf2790cf0ULL, unwinder.frames()[2].sp);
- EXPECT_EQ(0xb695980bULL, unwinder.frames()[3].pc);
- EXPECT_EQ(0xf2790cf8ULL, unwinder.frames()[3].sp);
- EXPECT_EQ(0xf23febd4ULL, unwinder.frames()[4].pc);
- EXPECT_EQ(0xf2790d10ULL, unwinder.frames()[4].sp);
- EXPECT_EQ(0xb695601eULL, unwinder.frames()[5].pc);
- EXPECT_EQ(0xffe67798ULL, unwinder.frames()[5].sp);
- EXPECT_EQ(0xb6956633ULL, unwinder.frames()[6].pc);
- EXPECT_EQ(0xffe67890ULL, unwinder.frames()[6].sp);
- EXPECT_EQ(0xb695664bULL, unwinder.frames()[7].pc);
- EXPECT_EQ(0xffe678a0ULL, unwinder.frames()[7].sp);
- EXPECT_EQ(0xb6958711ULL, unwinder.frames()[8].pc);
- EXPECT_EQ(0xffe678b0ULL, unwinder.frames()[8].sp);
- EXPECT_EQ(0xb6958603ULL, unwinder.frames()[9].pc);
- EXPECT_EQ(0xffe67ac8ULL, unwinder.frames()[9].sp);
- EXPECT_EQ(0xb697ffe3ULL, unwinder.frames()[10].pc);
- EXPECT_EQ(0xffe67ad8ULL, unwinder.frames()[10].sp);
- EXPECT_EQ(0xb6980b25ULL, unwinder.frames()[11].pc);
- EXPECT_EQ(0xffe67ae8ULL, unwinder.frames()[11].sp);
- EXPECT_EQ(0xb6980e27ULL, unwinder.frames()[12].pc);
- EXPECT_EQ(0xffe67b18ULL, unwinder.frames()[12].sp);
- EXPECT_EQ(0xb698893dULL, unwinder.frames()[13].pc);
- EXPECT_EQ(0xffe67b48ULL, unwinder.frames()[13].sp);
- EXPECT_EQ(0xb698860bULL, unwinder.frames()[14].pc);
- EXPECT_EQ(0xffe67bb0ULL, unwinder.frames()[14].sp);
- EXPECT_EQ(0xb6995035ULL, unwinder.frames()[15].pc);
- EXPECT_EQ(0xffe67bd0ULL, unwinder.frames()[15].sp);
- EXPECT_EQ(0xf23fe155ULL, unwinder.frames()[16].pc);
- EXPECT_EQ(0xffe67d10ULL, unwinder.frames()[16].sp);
-}
-
-TEST_F(UnwindOfflineTest, empty_arm64) {
- ASSERT_NO_FATAL_FAILURE(Init("empty_arm64/", ARCH_ARM64));
-
- Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
- unwinder.Unwind();
-
- std::string frame_info(DumpFrames(unwinder));
- ASSERT_EQ(7U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
- EXPECT_EQ(
- " #00 pc 00000000000963a4 libc.so (__ioctl+4)\n"
- " #01 pc 000000000005344c libc.so (ioctl+140)\n"
- " #02 pc 0000000000050ce4 libbinder.so "
- "(android::IPCThreadState::talkWithDriver(bool)+308)\n"
- " #03 pc 0000000000050e98 libbinder.so "
- "(android::IPCThreadState::getAndExecuteCommand()+24)\n"
- " #04 pc 00000000000516ac libbinder.so (android::IPCThreadState::joinThreadPool(bool)+60)\n"
- " #05 pc 00000000000443b0 netd (main+1056)\n"
- " #06 pc 0000000000045594 libc.so (__libc_init+108)\n",
- frame_info);
-
- EXPECT_EQ(0x72a02203a4U, unwinder.frames()[0].pc);
- EXPECT_EQ(0x7ffb6c0b50U, unwinder.frames()[0].sp);
- EXPECT_EQ(0x72a01dd44cU, unwinder.frames()[1].pc);
- EXPECT_EQ(0x7ffb6c0b50U, unwinder.frames()[1].sp);
- EXPECT_EQ(0x729f759ce4U, unwinder.frames()[2].pc);
- EXPECT_EQ(0x7ffb6c0c50U, unwinder.frames()[2].sp);
- EXPECT_EQ(0x729f759e98U, unwinder.frames()[3].pc);
- EXPECT_EQ(0x7ffb6c0ce0U, unwinder.frames()[3].sp);
- EXPECT_EQ(0x729f75a6acU, unwinder.frames()[4].pc);
- EXPECT_EQ(0x7ffb6c0d10U, unwinder.frames()[4].sp);
- EXPECT_EQ(0x5d478af3b0U, unwinder.frames()[5].pc);
- EXPECT_EQ(0x7ffb6c0d40U, unwinder.frames()[5].sp);
- EXPECT_EQ(0x72a01cf594U, unwinder.frames()[6].pc);
- EXPECT_EQ(0x7ffb6c0f30U, unwinder.frames()[6].sp);
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
deleted file mode 100644
index f76a101..0000000
--- a/libunwindstack/tests/UnwindTest.cpp
+++ /dev/null
@@ -1,479 +0,0 @@
-/*
- * Copyright (C) 2017 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 <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/syscall.h>
-#include <unistd.h>
-
-#include <gtest/gtest.h>
-
-#include <atomic>
-#include <memory>
-#include <sstream>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-#include <android-base/threads.h>
-
-#include <unwindstack/Maps.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsGetLocal.h>
-#include <unwindstack/Unwinder.h>
-
-#include "MemoryRemote.h"
-#include "TestUtils.h"
-
-namespace unwindstack {
-
-enum TestTypeEnum : uint8_t {
- TEST_TYPE_LOCAL_UNWINDER = 0,
- TEST_TYPE_LOCAL_UNWINDER_FROM_PID,
- TEST_TYPE_LOCAL_WAIT_FOR_FINISH,
- TEST_TYPE_REMOTE,
- TEST_TYPE_REMOTE_WITH_INVALID_CALL,
-};
-
-static std::atomic_bool g_ready;
-static volatile bool g_ready_for_remote;
-static volatile bool g_signal_ready_for_remote;
-static std::atomic_bool g_finish;
-static std::atomic_uintptr_t g_ucontext;
-
-static void ResetGlobals() {
- g_ready = false;
- g_ready_for_remote = false;
- g_signal_ready_for_remote = false;
- g_finish = false;
- g_ucontext = 0;
-}
-
-static std::vector<const char*> kFunctionOrder{"OuterFunction", "MiddleFunction", "InnerFunction"};
-
-static std::vector<const char*> kFunctionSignalOrder{"OuterFunction", "MiddleFunction",
- "InnerFunction", "SignalOuterFunction",
- "SignalMiddleFunction", "SignalInnerFunction"};
-
-static void SignalHandler(int, siginfo_t*, void* sigcontext) {
- g_ucontext = reinterpret_cast<uintptr_t>(sigcontext);
- while (!g_finish.load()) {
- }
-}
-
-extern "C" void SignalInnerFunction() {
- g_signal_ready_for_remote = true;
- // Avoid any function calls because not every instruction will be
- // unwindable.
- // This method of looping is only used when testing a remote unwind.
- while (true) {
- }
-}
-
-extern "C" void SignalMiddleFunction() {
- SignalInnerFunction();
-}
-
-extern "C" void SignalOuterFunction() {
- SignalMiddleFunction();
-}
-
-static void SignalCallerHandler(int, siginfo_t*, void*) {
- SignalOuterFunction();
-}
-
-static std::string ErrorMsg(const std::vector<const char*>& function_names, Unwinder* unwinder) {
- std::string unwind;
- for (size_t i = 0; i < unwinder->NumFrames(); i++) {
- unwind += unwinder->FormatFrame(i) + '\n';
- }
-
- return std::string(
- "Unwind completed without finding all frames\n"
- " Looking for function: ") +
- function_names.front() + "\n" + "Unwind data:\n" + unwind;
-}
-
-static void VerifyUnwind(Unwinder* unwinder, std::vector<const char*> expected_function_names) {
- unwinder->Unwind();
-
- for (auto& frame : unwinder->frames()) {
- if (frame.function_name == expected_function_names.back()) {
- expected_function_names.pop_back();
- if (expected_function_names.empty()) {
- break;
- }
- }
- }
-
- ASSERT_TRUE(expected_function_names.empty()) << ErrorMsg(expected_function_names, unwinder);
-}
-
-static void VerifyUnwind(pid_t pid, Maps* maps, Regs* regs,
- std::vector<const char*> expected_function_names) {
- auto process_memory(Memory::CreateProcessMemory(pid));
-
- Unwinder unwinder(512, maps, regs, process_memory);
- VerifyUnwind(&unwinder, expected_function_names);
-}
-
-// This test assumes that this code is compiled with optimizations turned
-// off. If this doesn't happen, then all of the calls will be optimized
-// away.
-extern "C" void InnerFunction(TestTypeEnum test_type) {
- if (test_type == TEST_TYPE_LOCAL_WAIT_FOR_FINISH) {
- while (!g_finish.load()) {
- }
- return;
- }
- if (test_type == TEST_TYPE_REMOTE || test_type == TEST_TYPE_REMOTE_WITH_INVALID_CALL) {
- g_ready_for_remote = true;
- g_ready = true;
- if (test_type == TEST_TYPE_REMOTE_WITH_INVALID_CALL) {
- void (*crash_func)() = nullptr;
- crash_func();
- }
- // Avoid any function calls because not every instruction will be
- // unwindable.
- // This method of looping is only used when testing a remote unwind.
- while (true) {
- }
- return;
- }
-
- std::unique_ptr<Unwinder> unwinder;
- std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
- RegsGetLocal(regs.get());
- std::unique_ptr<Maps> maps;
-
- if (test_type == TEST_TYPE_LOCAL_UNWINDER) {
- maps.reset(new LocalMaps());
- ASSERT_TRUE(maps->Parse());
- auto process_memory(Memory::CreateProcessMemory(getpid()));
- 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(regs->Arch()));
- unwinder_from_pid->SetRegs(regs.get());
- unwinder.reset(unwinder_from_pid);
- }
- VerifyUnwind(unwinder.get(), kFunctionOrder);
-}
-
-extern "C" void MiddleFunction(TestTypeEnum test_type) {
- InnerFunction(test_type);
-}
-
-extern "C" void OuterFunction(TestTypeEnum test_type) {
- MiddleFunction(test_type);
-}
-
-class UnwindTest : public ::testing::Test {
- public:
- void SetUp() override { ResetGlobals(); }
-};
-
-TEST_F(UnwindTest, local) {
- OuterFunction(TEST_TYPE_LOCAL_UNWINDER);
-}
-
-TEST_F(UnwindTest, local_use_from_pid) {
- OuterFunction(TEST_TYPE_LOCAL_UNWINDER_FROM_PID);
-}
-
-static void LocalUnwind(void* data) {
- TestTypeEnum* test_type = reinterpret_cast<TestTypeEnum*>(data);
- OuterFunction(*test_type);
-}
-
-TEST_F(UnwindTest, local_check_for_leak) {
- TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER;
- TestCheckForLeaks(LocalUnwind, &test_type);
-}
-
-TEST_F(UnwindTest, local_use_from_pid_check_for_leak) {
- TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER_FROM_PID;
- TestCheckForLeaks(LocalUnwind, &test_type);
-}
-
-void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
- *completed = false;
- // Need to sleep before attempting first ptrace. Without this, on the
- // host it becomes impossible to attach and ptrace sets errno to EPERM.
- usleep(1000);
- for (size_t i = 0; i < 1000; i++) {
- if (ptrace(PTRACE_ATTACH, pid, 0, 0) == 0) {
- ASSERT_TRUE(TestQuiescePid(pid))
- << "Waiting for process to quiesce failed: " << strerror(errno);
-
- MemoryRemote memory(pid);
- // Read the remote value to see if we are ready.
- bool value;
- if (memory.ReadFully(addr, &value, sizeof(value)) && value) {
- *completed = true;
- }
- if (!*completed || !leave_attached) {
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0));
- }
- if (*completed) {
- break;
- }
- } else {
- ASSERT_EQ(ESRCH, errno) << "ptrace attach failed with unexpected error: " << strerror(errno);
- }
- usleep(5000);
- }
-}
-
-TEST_F(UnwindTest, remote) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- OuterFunction(TEST_TYPE_REMOTE);
- exit(0);
- }
- ASSERT_NE(-1, pid);
- TestScopedPidReaper reap(pid);
-
- bool completed;
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
-
- RemoteMaps maps(pid);
- ASSERT_TRUE(maps.Parse());
- std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
- ASSERT_TRUE(regs.get() != nullptr);
-
- VerifyUnwind(pid, &maps, regs.get(), kFunctionOrder);
-
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
- << "ptrace detach failed with unexpected error: " << strerror(errno);
-}
-
-TEST_F(UnwindTest, unwind_from_pid_remote) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- OuterFunction(TEST_TYPE_REMOTE);
- exit(0);
- }
- ASSERT_NE(-1, pid);
- TestScopedPidReaper reap(pid);
-
- bool completed;
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
-
- std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
- ASSERT_TRUE(regs.get() != nullptr);
-
- UnwinderFromPid unwinder(512, pid);
- ASSERT_TRUE(unwinder.Init(regs->Arch()));
- unwinder.SetRegs(regs.get());
-
- VerifyUnwind(&unwinder, kFunctionOrder);
-
- // Verify that calling the same object works again.
-
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
- << "ptrace detach failed with unexpected error: " << strerror(errno);
-}
-
-static void RemoteCheckForLeaks(void (*unwind_func)(void*)) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- OuterFunction(TEST_TYPE_REMOTE);
- exit(0);
- }
- ASSERT_NE(-1, pid);
- TestScopedPidReaper reap(pid);
-
- bool completed;
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
-
- TestCheckForLeaks(unwind_func, &pid);
-
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
- << "ptrace detach failed with unexpected error: " << strerror(errno);
-}
-
-static void RemoteUnwind(void* data) {
- pid_t* pid = reinterpret_cast<pid_t*>(data);
-
- RemoteMaps maps(*pid);
- ASSERT_TRUE(maps.Parse());
- std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
- ASSERT_TRUE(regs.get() != nullptr);
-
- VerifyUnwind(*pid, &maps, regs.get(), kFunctionOrder);
-}
-
-TEST_F(UnwindTest, remote_check_for_leaks) {
- RemoteCheckForLeaks(RemoteUnwind);
-}
-
-static void RemoteUnwindFromPid(void* data) {
- pid_t* pid = reinterpret_cast<pid_t*>(data);
-
- std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
- ASSERT_TRUE(regs.get() != nullptr);
-
- UnwinderFromPid unwinder(512, *pid);
- ASSERT_TRUE(unwinder.Init(regs->Arch()));
- unwinder.SetRegs(regs.get());
-
- VerifyUnwind(&unwinder, kFunctionOrder);
-}
-
-TEST_F(UnwindTest, remote_unwind_for_pid_check_for_leaks) {
- RemoteCheckForLeaks(RemoteUnwindFromPid);
-}
-
-TEST_F(UnwindTest, from_context) {
- std::atomic_int tid(0);
- std::thread thread([&]() {
- tid = syscall(__NR_gettid);
- OuterFunction(TEST_TYPE_LOCAL_WAIT_FOR_FINISH);
- });
-
- struct sigaction act, oldact;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = SignalHandler;
- act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
- ASSERT_EQ(0, sigaction(SIGUSR1, &act, &oldact));
- // Wait for the tid to get set.
- for (size_t i = 0; i < 100; i++) {
- if (tid.load() != 0) {
- break;
- }
- usleep(1000);
- }
- ASSERT_NE(0, tid.load());
- ASSERT_EQ(0, tgkill(getpid(), tid.load(), SIGUSR1)) << "Error: " << strerror(errno);
-
- // Wait for context data.
- void* ucontext;
- for (size_t i = 0; i < 2000; i++) {
- ucontext = reinterpret_cast<void*>(g_ucontext.load());
- if (ucontext != nullptr) {
- break;
- }
- usleep(1000);
- }
- ASSERT_TRUE(ucontext != nullptr) << "Timed out waiting for thread to respond to signal.";
-
- LocalMaps maps;
- ASSERT_TRUE(maps.Parse());
- std::unique_ptr<Regs> regs(Regs::CreateFromUcontext(Regs::CurrentArch(), ucontext));
-
- VerifyUnwind(getpid(), &maps, regs.get(), kFunctionOrder);
-
- ASSERT_EQ(0, sigaction(SIGUSR1, &oldact, nullptr));
-
- g_finish = true;
- thread.join();
-}
-
-static void RemoteThroughSignal(int signal, unsigned int sa_flags) {
- pid_t pid;
- if ((pid = fork()) == 0) {
- struct sigaction act, oldact;
- memset(&act, 0, sizeof(act));
- act.sa_sigaction = SignalCallerHandler;
- act.sa_flags = SA_RESTART | SA_ONSTACK | sa_flags;
- ASSERT_EQ(0, sigaction(signal, &act, &oldact));
-
- OuterFunction(signal != SIGSEGV ? TEST_TYPE_REMOTE : TEST_TYPE_REMOTE_WITH_INVALID_CALL);
- exit(0);
- }
- ASSERT_NE(-1, pid);
- TestScopedPidReaper reap(pid);
-
- bool completed;
- if (signal != SIGSEGV) {
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), false, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
- ASSERT_EQ(0, kill(pid, SIGUSR1));
- }
- WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_signal_ready_for_remote), true, &completed);
- ASSERT_TRUE(completed) << "Timed out waiting for remote process to be in signal handler.";
-
- RemoteMaps maps(pid);
- ASSERT_TRUE(maps.Parse());
- std::unique_ptr<Regs> regs(Regs::RemoteGet(pid));
- ASSERT_TRUE(regs.get() != nullptr);
-
- VerifyUnwind(pid, &maps, regs.get(), kFunctionSignalOrder);
-
- ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
- << "ptrace detach failed with unexpected error: " << strerror(errno);
-}
-
-TEST_F(UnwindTest, remote_through_signal) {
- RemoteThroughSignal(SIGUSR1, 0);
-}
-
-TEST_F(UnwindTest, remote_through_signal_sa_siginfo) {
- RemoteThroughSignal(SIGUSR1, SA_SIGINFO);
-}
-
-TEST_F(UnwindTest, remote_through_signal_with_invalid_func) {
- RemoteThroughSignal(SIGSEGV, 0);
-}
-
-TEST_F(UnwindTest, remote_through_signal_sa_siginfo_with_invalid_func) {
- RemoteThroughSignal(SIGSEGV, SA_SIGINFO);
-}
-
-// Verify that using the same map while unwinding multiple threads at the
-// same time doesn't cause problems.
-TEST_F(UnwindTest, multiple_threads_unwind_same_map) {
- static constexpr size_t kNumConcurrentThreads = 100;
-
- LocalMaps maps;
- ASSERT_TRUE(maps.Parse());
- auto process_memory(Memory::CreateProcessMemory(getpid()));
-
- std::vector<std::thread*> threads;
-
- std::atomic_bool wait;
- wait = true;
- size_t frames[kNumConcurrentThreads];
- for (size_t i = 0; i < kNumConcurrentThreads; i++) {
- std::thread* thread = new std::thread([i, &frames, &maps, &process_memory, &wait]() {
- while (wait)
- ;
- std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
- RegsGetLocal(regs.get());
-
- Unwinder unwinder(512, &maps, regs.get(), process_memory);
- unwinder.Unwind();
- frames[i] = unwinder.NumFrames();
- ASSERT_LE(3U, frames[i]) << "Failed for thread " << i;
- });
- threads.push_back(thread);
- }
- wait = false;
- for (auto thread : threads) {
- thread->join();
- delete thread;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
deleted file mode 100644
index d10af2f..0000000
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ /dev/null
@@ -1,1505 +0,0 @@
-/*
- * Copyright (C) 2017 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 <elf.h>
-#include <stdint.h>
-#include <sys/mman.h>
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-#include <unwindstack/RegsMips.h>
-#include <unwindstack/RegsMips64.h>
-#include <unwindstack/Unwinder.h>
-
-#include "ElfFake.h"
-#include "MemoryFake.h"
-#include "RegsFake.h"
-
-namespace unwindstack {
-
-class UnwinderTest : public ::testing::Test {
- protected:
- static void AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
- const char* name, Elf* elf = nullptr) {
- std::string str_name(name);
- maps_->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
- if (elf != nullptr) {
- const auto& map_info = *--maps_->end();
- map_info->elf.reset(elf);
- }
- }
-
- static void SetUpTestSuite() {
- maps_.reset(new Maps);
-
- ElfFake* elf = new ElfFake(new MemoryFake);
- ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
- interface_fake->FakeSetBuildID("FAKE");
- elf->FakeSetInterface(interface_fake);
- AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);
-
- AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");
-
- AddMapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
- "/dev/fake_device");
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so", elf);
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so", elf);
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);
-
- elf = new ElfFake(new MemoryFake);
- ElfInterfaceFake* interface = new ElfInterfaceFake(nullptr);
- interface->FakeSetSoname("lib_fake.so");
- elf->FakeSetInterface(interface);
- AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
- MapInfo* map_info = maps_->Find(0x43000);
- ASSERT_TRUE(map_info != nullptr);
- map_info->elf_start_offset = 0x1d000;
-
- AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
-
- AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
- const auto& info = *--maps_->end();
- info->load_bias = 0;
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- elf->FakeSetLoadBias(0x5000);
- AddMapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_load_bias.so",
- elf);
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_offset.oat",
- elf);
- const auto& info2 = *--maps_->end();
- info2->elf_offset = 0x8000;
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf);
- const auto& info3 = *--maps_->end();
- info3->memory_backed_elf = true;
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
- const auto& info4 = *--maps_->end();
- info4->memory_backed_elf = true;
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
- const auto& info5 = *--maps_->end();
- info5->memory_backed_elf = true;
-
- elf = new ElfFake(new MemoryFake);
- elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
- AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/memfd:/jit-cache", elf);
- const auto& info6 = *--maps_->end();
- info6->memory_backed_elf = true;
-
- AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
- const auto& info7 = *--maps_->end();
- info7->load_bias = 0;
-
- process_memory_.reset(new MemoryFake);
- }
-
- void SetUp() override {
- ElfInterfaceFake::FakeClear();
- regs_.FakeSetArch(ARCH_ARM);
- regs_.FakeSetReturnAddressValid(false);
- }
-
- static std::unique_ptr<Maps> maps_;
- static RegsFake regs_;
- static std::shared_ptr<Memory> process_memory_;
-};
-
-std::unique_ptr<Maps> UnwinderTest::maps_;
-RegsFake UnwinderTest::regs_(5);
-std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr);
-
-TEST_F(UnwinderTest, multiple_frames) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
-
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0x1104, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x1204, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(3U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x100U, frame->rel_pc);
- EXPECT_EQ(0x1100U, frame->pc);
- EXPECT_EQ(0x10010U, frame->sp);
- EXPECT_EQ("Frame1", frame->function_name);
- EXPECT_EQ(1U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[2];
- EXPECT_EQ(2U, frame->num);
- EXPECT_EQ(0x200U, frame->rel_pc);
- EXPECT_EQ(0x1200U, frame->pc);
- EXPECT_EQ(0x10020U, frame->sp);
- EXPECT_EQ("Frame2", frame->function_name);
- EXPECT_EQ(2U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
-
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0x1104, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x1204, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.SetResolveNames(false);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(3U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x100U, frame->rel_pc);
- EXPECT_EQ(0x1100U, frame->pc);
- EXPECT_EQ(0x10010U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[2];
- EXPECT_EQ(2U, frame->num);
- EXPECT_EQ(0x200U, frame->rel_pc);
- EXPECT_EQ(0x1200U, frame->pc);
- EXPECT_EQ(0x10020U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, non_zero_load_bias) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0xa5500);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x5500U, frame->rel_pc);
- EXPECT_EQ(0xa5500U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xa5000U, frame->map_start);
- EXPECT_EQ(0xa6000U, frame->map_end);
- EXPECT_EQ(0x5000U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, non_zero_elf_offset) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0xa7500);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x8500U, frame->rel_pc);
- EXPECT_EQ(0xa7500U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake_offset.oat", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xa7000U, frame->map_start);
- EXPECT_EQ(0xa8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, non_zero_map_offset) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0x43000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x43000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_name);
- EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
- EXPECT_EQ(0x1d000U, frame->map_exact_offset);
- EXPECT_EQ(0x43000U, frame->map_start);
- EXPECT_EQ(0x44000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, disable_embedded_soname) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0x43000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.SetEmbeddedSoname(false);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x43000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake.apk", frame->map_name);
- EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
- EXPECT_EQ(0x1d000U, frame->map_exact_offset);
- EXPECT_EQ(0x43000U, frame->map_start);
- EXPECT_EQ(0x44000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-// Verify that no attempt to continue after the step indicates it is done.
-TEST_F(UnwinderTest, no_frames_after_finished) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame4", 4));
-
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0x1000, 0x10000, true));
- ElfInterfaceFake::FakePushStepData(StepData(0x1102, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x1202, 0x10020, false));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-// Verify the maximum frames to save.
-TEST_F(UnwinderTest, max_frames) {
- for (size_t i = 0; i < 30; i++) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame" + std::to_string(i), i));
- ElfInterfaceFake::FakePushStepData(StepData(0x1104 + i * 0x100, 0x10010 + i * 0x10, false));
- }
-
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
-
- Unwinder unwinder(20, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(20U, unwinder.NumFrames());
-
- for (size_t i = 0; i < 20; i++) {
- auto* frame = &unwinder.frames()[i];
- EXPECT_EQ(i, frame->num);
- EXPECT_EQ(i * 0x100, frame->rel_pc) << "Failed at frame " << i;
- EXPECT_EQ(0x1000 + i * 0x100, frame->pc) << "Failed at frame " << i;
- EXPECT_EQ(0x10000 + 0x10 * i, frame->sp) << "Failed at frame " << i;
- EXPECT_EQ("Frame" + std::to_string(i), frame->function_name) << "Failed at frame " << i;
- EXPECT_EQ(i, frame->function_offset) << "Failed at frame " << i;
- EXPECT_EQ("/system/fake/libc.so", frame->map_name) << "Failed at frame " << i;
- EXPECT_EQ(0U, frame->map_elf_start_offset) << "Failed at frame " << i;
- EXPECT_EQ(0U, frame->map_exact_offset) << "Failed at frame " << i;
- EXPECT_EQ(0x1000U, frame->map_start) << "Failed at frame " << i;
- EXPECT_EQ(0x8000U, frame->map_end) << "Failed at frame " << i;
- EXPECT_EQ(0U, frame->map_load_bias) << "Failed at frame " << i;
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags) << "Failed at frame " << i;
- }
-}
-
-// Verify that initial map names frames are removed.
-TEST_F(UnwinderTest, verify_frames_skipped) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
-
- regs_.set_pc(0x20000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0x23004, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x23104, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x20004, 0x10030, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x21004, 0x10040, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x1002, 0x10050, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x21004, 0x10060, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10070, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- std::vector<std::string> skip_libs{"libunwind.so", "libanother.so"};
- unwinder.Unwind(&skip_libs);
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(3U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10050U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x1000U, frame->rel_pc);
- EXPECT_EQ(0x21000U, frame->pc);
- EXPECT_EQ(0x10060U, frame->sp);
- EXPECT_EQ("Frame1", frame->function_name);
- EXPECT_EQ(1U, frame->function_offset);
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x20000U, frame->map_start);
- EXPECT_EQ(0x22000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[2];
- EXPECT_EQ(2U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x23000U, frame->pc);
- EXPECT_EQ(0x10070U, frame->sp);
- EXPECT_EQ("Frame2", frame->function_name);
- EXPECT_EQ(2U, frame->function_offset);
- EXPECT_EQ("/fake/libanother.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x23000U, frame->map_start);
- EXPECT_EQ(0x24000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-// Verify SP in a non-existant map is okay.
-TEST_F(UnwinderTest, sp_not_in_map) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
-
- regs_.set_pc(0x1000);
- regs_.set_sp(0x63000);
- ElfInterfaceFake::FakePushStepData(StepData(0x21004, 0x50020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(2U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x63000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x1000U, frame->rel_pc);
- EXPECT_EQ(0x21000U, frame->pc);
- EXPECT_EQ(0x50020U, frame->sp);
- EXPECT_EQ("Frame1", frame->function_name);
- EXPECT_EQ(1U, frame->function_offset);
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x20000U, frame->map_start);
- EXPECT_EQ(0x22000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-// Verify PC in a device stops the unwind.
-TEST_F(UnwinderTest, pc_in_device_stops_unwind) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
-
- regs_.set_pc(0x13000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-}
-
-// Verify SP in a device stops the unwind.
-TEST_F(UnwinderTest, sp_in_device_stops_unwind) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
-
- regs_.set_pc(0x1000);
- regs_.set_sp(0x13000);
- ElfInterfaceFake::FakePushStepData(StepData(0x23002, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x23102, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-}
-
-// Verify a no map info frame gets a frame.
-TEST_F(UnwinderTest, pc_without_map) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0x41000);
- regs_.set_sp(0x13000);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x41000U, frame->rel_pc);
- EXPECT_EQ(0x41000U, frame->pc);
- EXPECT_EQ(0x13000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0U, frame->map_start);
- EXPECT_EQ(0U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(0, frame->map_flags);
-}
-
-// Verify that a speculative frame is added.
-TEST_F(UnwinderTest, speculative_frame) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
-
- // Fake as if code called a nullptr function.
- regs_.set_pc(0);
- regs_.set_sp(0x10000);
- regs_.FakeSetReturnAddress(0x1204);
- regs_.FakeSetReturnAddressValid(true);
-
- ElfInterfaceFake::FakePushStepData(StepData(0x23104, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(3U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0U, frame->map_start);
- EXPECT_EQ(0U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(0, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x200U, frame->rel_pc);
- EXPECT_EQ(0x1200U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[2];
- EXPECT_EQ(2U, frame->num);
- EXPECT_EQ(0x100U, frame->rel_pc);
- EXPECT_EQ(0x23100U, frame->pc);
- EXPECT_EQ(0x10020U, frame->sp);
- EXPECT_EQ("Frame1", frame->function_name);
- EXPECT_EQ(1U, frame->function_offset);
- EXPECT_EQ("/fake/libanother.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x23000U, frame->map_start);
- EXPECT_EQ(0x24000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-// Verify that a speculative frame is added then removed because no other
-// frames are added.
-TEST_F(UnwinderTest, speculative_frame_removed) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
-
- // Fake as if code called a nullptr function.
- regs_.set_pc(0x20000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0x10010, false));
- regs_.FakeSetReturnAddress(0x12);
- regs_.FakeSetReturnAddressValid(true);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(2U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x20000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libunwind.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x20000U, frame->map_start);
- EXPECT_EQ(0x22000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0U, frame->pc);
- EXPECT_EQ(0x10010U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0U, frame->map_start);
- EXPECT_EQ(0U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(0, frame->map_flags);
-}
-
-// Verify that a speculative frame is added and left if there are only
-// two frames and the pc is in the middle nowhere.
-TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
-
- // Fake as if code called a nullptr function.
- regs_.set_pc(0);
- regs_.set_sp(0x10000);
- regs_.FakeSetReturnAddress(0x1204);
- regs_.FakeSetReturnAddressValid(true);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(2U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0U, frame->map_start);
- EXPECT_EQ(0U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(0, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x200U, frame->rel_pc);
- EXPECT_EQ(0x1200U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-// Verify that a speculative frame does not cause a crash when it wasn't
-// really added due to a filter.
-TEST_F(UnwinderTest, speculative_frame_check_with_no_frames) {
- regs_.set_pc(0x23000);
- regs_.set_sp(0x10000);
- regs_.FakeSetReturnAddress(0x23100);
- regs_.FakeSetReturnAddressValid(true);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
-
- std::vector<std::string> skip_names{"libanother.so"};
- unwinder.Unwind(&skip_names);
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(0U, unwinder.NumFrames());
-}
-
-// Verify that an unwind stops when a frame is in given suffix.
-TEST_F(UnwinderTest, map_ignore_suffixes) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
-
- // Fake as if code called a nullptr function.
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0x43404, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x53504, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- std::vector<std::string> suffixes{"oat"};
- unwinder.Unwind(nullptr, &suffixes);
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(2U, unwinder.NumFrames());
- // Make sure the elf was not initialized.
- MapInfo* map_info = maps_->Find(0x53000);
- ASSERT_TRUE(map_info != nullptr);
- EXPECT_TRUE(map_info->elf == nullptr);
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x400U, frame->rel_pc);
- EXPECT_EQ(0x43400U, frame->pc);
- EXPECT_EQ(0x10010U, frame->sp);
- EXPECT_EQ("Frame1", frame->function_name);
- EXPECT_EQ(1U, frame->function_offset);
- EXPECT_EQ("/fake/fake.apk!lib_fake.so", frame->map_name);
- EXPECT_EQ(0x1d000U, frame->map_elf_start_offset);
- EXPECT_EQ(0x1d000U, frame->map_exact_offset);
- EXPECT_EQ(0x43000U, frame->map_start);
- EXPECT_EQ(0x44000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-// Verify that an unwind stops when the sp and pc don't change.
-TEST_F(UnwinderTest, sp_pc_do_not_change) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame3", 3));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame4", 4));
-
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0x33404, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0x33504, 0x10020, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(3U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0x400U, frame->rel_pc);
- EXPECT_EQ(0x33400U, frame->pc);
- EXPECT_EQ(0x10010U, frame->sp);
- EXPECT_EQ("Frame1", frame->function_name);
- EXPECT_EQ(1U, frame->function_offset);
- EXPECT_EQ("/fake/compressed.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x33000U, frame->map_start);
- EXPECT_EQ(0x34000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[2];
- EXPECT_EQ(2U, frame->num);
- EXPECT_EQ(0x500U, frame->rel_pc);
- EXPECT_EQ(0x33500U, frame->pc);
- EXPECT_EQ(0x10020U, frame->sp);
- EXPECT_EQ("Frame2", frame->function_name);
- EXPECT_EQ(2U, frame->function_offset);
- EXPECT_EQ("/fake/compressed.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x33000U, frame->map_start);
- EXPECT_EQ(0x34000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, dex_pc_in_map) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- regs_.FakeSetDexPc(0xa3400);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(2U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x400U, frame->rel_pc);
- EXPECT_EQ(0xa3400U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake.vdex", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xa3000U, frame->map_start);
- EXPECT_EQ(0xa4000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, dex_pc_in_map_non_zero_offset) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- regs_.FakeSetDexPc(0xd0400);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(2U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x400U, frame->rel_pc);
- EXPECT_EQ(0xd0400U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake.apk", frame->map_name);
- EXPECT_EQ(0x1000U, frame->map_elf_start_offset);
- EXPECT_EQ(0x1000U, frame->map_exact_offset);
- EXPECT_EQ(0xd0000U, frame->map_start);
- EXPECT_EQ(0xd1000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, dex_pc_not_in_map) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- regs_.FakeSetDexPc(0x50000);
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_DEX_PC_NOT_IN_MAP, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(2U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x50000U, frame->rel_pc);
- EXPECT_EQ(0x50000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0U, frame->map_start);
- EXPECT_EQ(0U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(0, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, dex_pc_multiple_frames) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- regs_.FakeSetDexPc(0xa3400);
- ElfInterfaceFake::FakePushStepData(StepData(0x33404, 0x10010, false));
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(3U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x400U, frame->rel_pc);
- EXPECT_EQ(0xa3400U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake.vdex", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xa3000U, frame->map_start);
- EXPECT_EQ(0xa4000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-
- frame = &unwinder.frames()[1];
- EXPECT_EQ(1U, frame->num);
- EXPECT_EQ(0U, frame->rel_pc);
- EXPECT_EQ(0x1000U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/system/fake/libc.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x1000U, frame->map_start);
- EXPECT_EQ(0x8000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-
- frame = &unwinder.frames()[2];
- EXPECT_EQ(2U, frame->num);
- EXPECT_EQ(0x400U, frame->rel_pc);
- EXPECT_EQ(0x33400U, frame->pc);
- EXPECT_EQ(0x10010U, frame->sp);
- EXPECT_EQ("Frame1", frame->function_name);
- EXPECT_EQ(1U, frame->function_offset);
- EXPECT_EQ("/fake/compressed.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0x33000U, frame->map_start);
- EXPECT_EQ(0x34000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, dex_pc_max_frames) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
- regs_.set_pc(0x1000);
- regs_.set_sp(0x10000);
- regs_.FakeSetDexPc(0xa3400);
-
- Unwinder unwinder(1, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x400U, frame->rel_pc);
- EXPECT_EQ(0xa3400U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/fake.vdex", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xa3000U, frame->map_start);
- EXPECT_EQ(0xa4000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, elf_from_memory_not_file) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0xc0050);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_TRUE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x50U, frame->rel_pc);
- EXPECT_EQ(0xc0050U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/fake/unreadable.so", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xc0000U, frame->map_start);
- EXPECT_EQ(0xc1000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0xc1050);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x50U, frame->rel_pc);
- EXPECT_EQ(0xc1050U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("[vdso]", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xc1000U, frame->map_start);
- EXPECT_EQ(0xc2000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0xc2050);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x50U, frame->rel_pc);
- EXPECT_EQ(0xc2050U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xc2000U, frame->map_start);
- EXPECT_EQ(0xc3000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-}
-
-TEST_F(UnwinderTest, elf_from_memory_but_from_memfd) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
-
- regs_.set_pc(0xc3050);
- regs_.set_sp(0x10000);
- ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
-
- Unwinder unwinder(64, maps_.get(), ®s_, process_memory_);
- unwinder.Unwind();
- EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
- EXPECT_EQ(WARNING_NONE, unwinder.warnings());
- EXPECT_FALSE(unwinder.elf_from_memory_not_file());
-
- ASSERT_EQ(1U, unwinder.NumFrames());
-
- auto* frame = &unwinder.frames()[0];
- EXPECT_EQ(0U, frame->num);
- EXPECT_EQ(0x50U, frame->rel_pc);
- EXPECT_EQ(0xc3050U, frame->pc);
- EXPECT_EQ(0x10000U, frame->sp);
- EXPECT_EQ("Frame0", frame->function_name);
- EXPECT_EQ(0U, frame->function_offset);
- EXPECT_EQ("/memfd:/jit-cache", frame->map_name);
- EXPECT_EQ(0U, frame->map_elf_start_offset);
- EXPECT_EQ(0U, frame->map_exact_offset);
- EXPECT_EQ(0xc3000U, frame->map_start);
- EXPECT_EQ(0xc4000U, frame->map_end);
- EXPECT_EQ(0U, frame->map_load_bias);
- EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags);
-}
-
-// Verify format frame code.
-TEST_F(UnwinderTest, format_frame) {
- RegsFake regs_arm(10);
- regs_arm.FakeSetArch(ARCH_ARM);
- Unwinder unwinder32(10, maps_.get(), ®s_arm, process_memory_);
-
- RegsFake regs_arm64(10);
- regs_arm64.FakeSetArch(ARCH_ARM64);
- Unwinder unwinder64(10, maps_.get(), ®s_arm64, process_memory_);
-
- FrameData frame;
- frame.num = 1;
- frame.rel_pc = 0x1000;
- frame.pc = 0x4000;
- frame.sp = 0x1000;
- frame.function_name = "function";
- frame.function_offset = 100;
- frame.map_name = "/fake/libfake.so";
- frame.map_elf_start_offset = 0x2000;
- frame.map_start = 0x3000;
- frame.map_end = 0x6000;
- frame.map_flags = PROT_READ;
-
- EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (offset 0x2000) (function+100)",
- unwinder64.FormatFrame(frame));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (offset 0x2000) (function+100)",
- unwinder32.FormatFrame(frame));
-
- frame.map_elf_start_offset = 0;
- EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function+100)",
- unwinder64.FormatFrame(frame));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder32.FormatFrame(frame));
-
- frame.function_offset = 0;
- EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (function)",
- unwinder64.FormatFrame(frame));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function)", unwinder32.FormatFrame(frame));
-
- // Verify the function name is demangled.
- frame.function_name = "_ZN4funcEv";
- EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so (func())", unwinder64.FormatFrame(frame));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (func())", unwinder32.FormatFrame(frame));
-
- frame.function_name = "";
- EXPECT_EQ(" #01 pc 0000000000001000 /fake/libfake.so", unwinder64.FormatFrame(frame));
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so", unwinder32.FormatFrame(frame));
-
- frame.map_name = "";
- EXPECT_EQ(" #01 pc 0000000000001000 <anonymous:3000>", unwinder64.FormatFrame(frame));
- EXPECT_EQ(" #01 pc 00001000 <anonymous:3000>", unwinder32.FormatFrame(frame));
-
- frame.map_start = 0;
- frame.map_end = 0;
- EXPECT_EQ(" #01 pc 0000000000001000 <unknown>", unwinder64.FormatFrame(frame));
- EXPECT_EQ(" #01 pc 00001000 <unknown>", unwinder32.FormatFrame(frame));
-}
-
-TEST_F(UnwinderTest, format_frame_build_id) {
- RegsFake regs(10);
- regs.FakeSetArch(ARCH_ARM);
- Unwinder unwinder(10, maps_.get(), ®s, process_memory_);
-
- FrameData frame;
- frame.num = 1;
- frame.rel_pc = 0x1000;
- frame.pc = 0x4000;
- frame.sp = 0x1000;
- frame.function_name = "function";
- frame.function_offset = 100;
- frame.map_name = "/fake/libfake.so";
- frame.map_elf_start_offset = 0;
- frame.map_start = 0x3000;
- frame.map_end = 0x6000;
- frame.map_flags = PROT_READ;
-
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100)", unwinder.FormatFrame(frame));
- unwinder.SetDisplayBuildID(true);
- EXPECT_EQ(" #01 pc 00001000 /fake/libfake.so (function+100) (BuildId: 46414b45)",
- unwinder.FormatFrame(frame));
-}
-
-static std::string ArchToString(ArchEnum arch) {
- if (arch == ARCH_ARM) {
- return "Arm";
- } else if (arch == ARCH_ARM64) {
- return "Arm64";
- } else if (arch == ARCH_X86) {
- return "X86";
- } else if (arch == ARCH_X86_64) {
- return "X86_64";
- } else {
- return "Unknown";
- }
-}
-
-// Verify format frame code.
-TEST_F(UnwinderTest, format_frame_by_arch) {
- std::vector<Regs*> reg_list;
- RegsArm* arm = new RegsArm;
- arm->set_pc(0x2300);
- arm->set_sp(0x10000);
- reg_list.push_back(arm);
-
- RegsArm64* arm64 = new RegsArm64;
- arm64->set_pc(0x2300);
- arm64->set_sp(0x10000);
- reg_list.push_back(arm64);
-
- RegsX86* x86 = new RegsX86;
- x86->set_pc(0x2300);
- x86->set_sp(0x10000);
- reg_list.push_back(x86);
-
- RegsX86_64* x86_64 = new RegsX86_64;
- x86_64->set_pc(0x2300);
- x86_64->set_sp(0x10000);
- reg_list.push_back(x86_64);
-
- RegsMips* mips = new RegsMips;
- mips->set_pc(0x2300);
- mips->set_sp(0x10000);
- reg_list.push_back(mips);
-
- RegsMips64* mips64 = new RegsMips64;
- mips64->set_pc(0x2300);
- mips64->set_sp(0x10000);
- reg_list.push_back(mips64);
-
- for (auto regs : reg_list) {
- ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 10));
-
- Unwinder unwinder(64, maps_.get(), regs, process_memory_);
- unwinder.Unwind();
-
- ASSERT_EQ(1U, unwinder.NumFrames());
- std::string expected;
- switch (regs->Arch()) {
- case ARCH_ARM:
- case ARCH_X86:
- case ARCH_MIPS:
- expected = " #00 pc 00001300 /system/fake/libc.so (Frame0+10)";
- break;
- case ARCH_ARM64:
- case ARCH_X86_64:
- case ARCH_MIPS64:
- expected = " #00 pc 0000000000001300 /system/fake/libc.so (Frame0+10)";
- break;
- default:
- expected = "";
- }
- EXPECT_EQ(expected, unwinder.FormatFrame(0))
- << "Mismatch of frame format for regs arch " << ArchToString(regs->Arch());
- delete regs;
- }
-}
-
-} // namespace unwindstack
diff --git a/libunwindstack/tests/VerifyBionicTerminationTest.cpp b/libunwindstack/tests/VerifyBionicTerminationTest.cpp
deleted file mode 100644
index eb2b01d..0000000
--- a/libunwindstack/tests/VerifyBionicTerminationTest.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.
- */
-
-#define _GNU_SOURCE 1
-#include <stdint.h>
-#include <string.h>
-
-#include <string>
-
-#if defined(__BIONIC__)
-
-#include <gtest/gtest.h>
-
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsGetLocal.h>
-#include <unwindstack/Unwinder.h>
-
-// This test is specific to bionic to verify that __libc_init is
-// properly setting the return address to undefined so that the
-// unwind properly terminates.
-
-namespace unwindstack {
-
-static std::string DumpFrames(const UnwinderFromPid& unwinder) {
- std::string unwind;
- for (size_t i = 0; i < unwinder.NumFrames(); i++) {
- unwind += unwinder.FormatFrame(i) + '\n';
- }
- return unwind;
-}
-
-static DwarfLocationEnum GetReturnAddressLocation(uint64_t rel_pc, DwarfSection* section) {
- if (section == nullptr) {
- return DWARF_LOCATION_INVALID;
- }
-
- const DwarfFde* fde = section->GetFdeFromPc(rel_pc);
- if (fde == nullptr || fde->cie == nullptr) {
- return DWARF_LOCATION_INVALID;
- }
- dwarf_loc_regs_t regs;
- if (!section->GetCfaLocationInfo(rel_pc, fde, ®s, ARCH_UNKNOWN)) {
- return DWARF_LOCATION_INVALID;
- }
-
- auto reg_entry = regs.find(fde->cie->return_address_register);
- if (reg_entry == regs.end()) {
- return DWARF_LOCATION_INVALID;
- }
- return reg_entry->second.type;
-}
-
-static void VerifyReturnAddress(const FrameData& frame) {
- // Now go and find information about the register data and verify that the relative pc results in
- // an undefined register.
- Elf elf(Memory::CreateFileMemory(frame.map_name, 0).release());
- ASSERT_TRUE(elf.Init()) << "Failed to init elf object from " << frame.map_name;
- ASSERT_TRUE(elf.valid()) << "Elf " << frame.map_name << " is not valid.";
- ElfInterface* interface = elf.interface();
-
- // Only check the eh_frame and the debug_frame since the undefined register
- // is set using a cfi directive.
- // Check debug_frame first, then eh_frame since debug_frame always
- // contains the most specific data.
- DwarfLocationEnum location = GetReturnAddressLocation(frame.rel_pc, interface->debug_frame());
- if (location == DWARF_LOCATION_UNDEFINED) {
- return;
- }
-
- location = GetReturnAddressLocation(frame.rel_pc, interface->eh_frame());
- ASSERT_EQ(DWARF_LOCATION_UNDEFINED, location);
-}
-
-// This test assumes that it starts from the main thread, and that the
-// libc.so on device will include symbols so that function names can
-// be resolved.
-TEST(VerifyBionicTermination, local_terminate) {
- std::unique_ptr<Regs> regs(Regs::CreateFromLocal());
-
- UnwinderFromPid unwinder(512, getpid());
- ASSERT_TRUE(unwinder.Init(regs->Arch()));
- unwinder.SetRegs(regs.get());
-
- RegsGetLocal(regs.get());
- unwinder.Unwind();
- ASSERT_LT(0U, unwinder.NumFrames());
-
- SCOPED_TRACE(DumpFrames(unwinder));
-
- // Look for the frame that includes __libc_init, there should only
- // be one and it should be the last.
- bool found = false;
- const std::vector<FrameData>& frames = unwinder.frames();
- for (size_t i = 0; i < unwinder.NumFrames(); i++) {
- const FrameData& frame = frames[i];
- if (frame.function_name == "__libc_init" && !frame.map_name.empty() &&
- std::string("libc.so") == basename(frame.map_name.c_str())) {
- ASSERT_EQ(unwinder.NumFrames(), i + 1) << "__libc_init is not last frame.";
- ASSERT_NO_FATAL_FAILURE(VerifyReturnAddress(frame));
- found = true;
- }
- }
- ASSERT_TRUE(found) << "Unable to find libc.so:__libc_init frame\n";
-}
-
-} // namespace unwindstack
-
-#endif
diff --git a/libunwindstack/tests/files/elf32.xz b/libunwindstack/tests/files/elf32.xz
deleted file mode 100644
index f25d433..0000000
--- a/libunwindstack/tests/files/elf32.xz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/elf64.xz b/libunwindstack/tests/files/elf64.xz
deleted file mode 100644
index eb1618e..0000000
--- a/libunwindstack/tests/files/elf64.xz
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data
deleted file mode 100644
index 300646b..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/descriptor.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data
deleted file mode 100644
index 999cb79..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data
deleted file mode 100644
index 6aa1c82..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/entry1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data
deleted file mode 100644
index 19d7b65..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data
deleted file mode 100644
index edcd3e1..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/jit1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
deleted file mode 100644
index 09ba495..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libart.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so
deleted file mode 100644
index 39c9025..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
deleted file mode 100644
index 1ff12db..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-d0250000-d2600000 r-xp 0 00:00 0 <anonymous:d0250000>
-e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
-e4af1000-e4af2000 rw-p 482000 00:00 0 libart.so
-e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt
deleted file mode 100644
index 0b51814..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/regs.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-r0: e814103c
-r1: 12dcf218
-r2: 1a90df75
-r3: ffffffbf
-r4: 0
-r5: 12dc0800
-r6: 12dcf218
-r7: 1a90df75
-r8: 0
-r9: dd23cc00
-r10: 1c
-r11: cd4ff16c
-ip: 0
-sp: cd4ff140
-lr: d025cdd7
-pc: d025c788
diff --git a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data b/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data
deleted file mode 100644
index f00917b..0000000
--- a/libunwindstack/tests/files/offline/art_quick_osr_stub_arm/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
deleted file mode 100644
index 78449bf..0000000
--- a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
deleted file mode 100644
index 7cada15..0000000
--- a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/maps.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-60a9fdf000-60a9fe0000 r-xp 0 00:00 0 waiter64
-7542cc0000-7542d8e000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
deleted file mode 100644
index c24adbe..0000000
--- a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/regs.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-pc: 60a9fdf550
-sp: 7fdd141990
-lr: 60a9fdf56c
-x29: 7fdd1419a0
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
deleted file mode 100644
index b56d420..0000000
--- a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64 b/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
deleted file mode 100644
index 81bda1d..0000000
--- a/libunwindstack/tests/files/offline/bad_eh_frame_hdr_arm64/waiter64
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so b/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
deleted file mode 100644
index 9c78790..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_first_x86/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
deleted file mode 100644
index 74fc89f..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_first_x86/maps.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-56598000-56599000 r-xp 0 00:00 0 waiter
-f7432000-f75e3000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt b/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
deleted file mode 100644
index 48f4440..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_first_x86/regs.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-eax: 1d88ef8c
-ebx: 56599fe8
-ecx: 3
-edx: ffcf9ea4
-ebp: ffcf9e48
-edi: f75e5000
-esi: 1
-esp: ffcf9e38
-eip: 56598685
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data b/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
deleted file mode 100644
index 0cf7d55..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_first_x86/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter b/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
deleted file mode 100644
index b1fc024..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_first_x86/waiter
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so
deleted file mode 100644
index 4b7bf44..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libbinder.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so
deleted file mode 100644
index 013858e..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt
deleted file mode 100644
index 10f1325..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/maps.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-8d1c000-8d1f000 r-xp 0 00:00 0 mediaserver
-f0b91000-f0c2c000 r-xp 0 00:00 0 libc.so
-f1a41000-f1a97000 r-xp 0 00:00 0 libbinder.so
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver
deleted file mode 100644
index 9e4a83f..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/mediaserver
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt
deleted file mode 100644
index f147247..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/regs.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-r0: 3
-r1: c0306201
-r2: ffd4a658
-r3: 0
-r4: f0c36d8c
-r5: ffd4a658
-r6: f0168000
-r7: 36
-r8: ffd4a678
-r9: f016802c
-r10: ffd4a660
-r11: 0
-ip: 0
-sp: ffd4a638
-lr: f0bb2413
-pc: f0be238c
diff --git a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data b/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data
deleted file mode 100644
index 847c819..0000000
--- a/libunwindstack/tests/files/offline/debug_frame_load_bias_arm/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so b/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so
deleted file mode 100644
index f3eb615..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_bias_x86/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt b/libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt
deleted file mode 100644
index 7d52483..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_bias_x86/maps.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-eb503000-eb5e8000 r-xp 0 00:00 0 libc.so
-eb831000-eb852000 r-xp 0 00:00 0 tombstoned
-ffffe000-fffff000 r-xp 0 00:00 0 vdso.so
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt b/libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt
deleted file mode 100644
index 821928e..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_bias_x86/regs.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-eax: fffffffc
-ebx: 4
-ecx: eb290180
-edx: 20
-ebp: 8
-edi: 0
-esi: ffffffff
-esp: fffe1a30
-eip: ffffe430
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data b/libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data
deleted file mode 100644
index b95bfac..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_bias_x86/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned b/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned
deleted file mode 100644
index aefdb6b..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_bias_x86/tombstoned
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so b/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so
deleted file mode 100644
index c71dcfb..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_bias_x86/vdso.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so
deleted file mode 100644
index 46b6f456..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt
deleted file mode 100644
index ac2e564..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-561550b17000-561550b1a000 r-xp 0 00:00 0 unwind_test64
-7f4de61f6000-7f4de638b000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt
deleted file mode 100644
index 38af274..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-rax: 92134c6fbbdc12ff
-rbx: 0
-rcx: 92134c6fbbdc1200
-rdx: 92134c6fbbdc1200
-r8: 561552153034
-r12: 561550b17930
-r13: 7ffcc8597270
-rsi: 561552153034
-rbp: 7ffcc8596f30
-rsp: 7ffcc8596ce8
-rip: 561550b17a80
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data
deleted file mode 100644
index cc7882b..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64 b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64
deleted file mode 100644
index ab0ef8f..0000000
--- a/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/empty_arm64/libbinder.so b/libunwindstack/tests/files/offline/empty_arm64/libbinder.so
deleted file mode 100644
index f30384c..0000000
--- a/libunwindstack/tests/files/offline/empty_arm64/libbinder.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/empty_arm64/libc.so b/libunwindstack/tests/files/offline/empty_arm64/libc.so
deleted file mode 100644
index b05dcaf..0000000
--- a/libunwindstack/tests/files/offline/empty_arm64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/empty_arm64/maps.txt b/libunwindstack/tests/files/offline/empty_arm64/maps.txt
deleted file mode 100644
index edb83c6..0000000
--- a/libunwindstack/tests/files/offline/empty_arm64/maps.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-5d4786b000-5d47893000 r--p 0 00:00 0 netd
-5d47893000-5d47894000 ---p 0 00:00 0
-5d47894000-5d47901000 --xp 29000 00:00 0 netd
-729f709000-729f750000 r--p 0 00:00 0 libbinder.so
-729f750000-729f751000 ---p 0 00:00 0
-729f751000-729f794000 --xp 48000 00:00 0 libbinder.so
-72a018a000-72a01c2000 r--p 0 00:00 0 libc.so
-72a01c2000-72a01c3000 ---p 0 00:00 0
-72a01c3000-72a023b000 --xp 39000 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/empty_arm64/netd b/libunwindstack/tests/files/offline/empty_arm64/netd
deleted file mode 100644
index 8a72e94..0000000
--- a/libunwindstack/tests/files/offline/empty_arm64/netd
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/empty_arm64/regs.txt b/libunwindstack/tests/files/offline/empty_arm64/regs.txt
deleted file mode 100644
index 3d4279f..0000000
--- a/libunwindstack/tests/files/offline/empty_arm64/regs.txt
+++ /dev/null
@@ -1,34 +0,0 @@
-x0: 1d
-x1: c0306201
-x2: 7ffb6c0c50
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 0
-x8: 1d
-x9: 7ffb6c0c00
-x10: 7ffb6c0c50
-x11: 7ffb6c0bd0
-x12: ffffff80ffffffd0
-x13: 0
-x14: 72a0240ce2
-x15: 20
-x16: 729f7a54e8
-x17: 72a01dd3c0
-x18: 72a0ac2000
-x19: 72a0666000
-x20: 719769b610
-x21: 719769b730
-x22: c0306201
-x23: fffffff7
-x24: 72a0666000
-x25: 0
-x26: 0
-x27: 0
-x28: 0
-x29: 7ffb6c0c30
-sp: 7ffb6c0b50
-lr: 72a01dd450
-pc: 72a02203a4
-pst: a0000000
diff --git a/libunwindstack/tests/files/offline/empty_arm64/stack.data b/libunwindstack/tests/files/offline/empty_arm64/stack.data
deleted file mode 100644
index 6d6108c..0000000
--- a/libunwindstack/tests/files/offline/empty_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so b/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
deleted file mode 100644
index e4283e6..0000000
--- a/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
deleted file mode 100644
index 1bcddb6..0000000
--- a/libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
+++ /dev/null
@@ -1 +0,0 @@
-f1f10000-f2049000 r-xp 00000000 00:00 0 libandroid_runtime.so
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
deleted file mode 100644
index c6a93dc..0000000
--- a/libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-pc: f1f6dc49
-sp: d8fe6930
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data b/libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
deleted file mode 100644
index 19cdf2d..0000000
--- a/libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt
deleted file mode 100644
index 022404c..0000000
--- a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/maps.txt
+++ /dev/null
@@ -1 +0,0 @@
-c7ee8000-c8c52fff r-xp 12e4000 00:00 0 invalid.apk
diff --git a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt b/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt
deleted file mode 100644
index b7f10ef..0000000
--- a/libunwindstack/tests/files/offline/invalid_elf_offset_arm/regs.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-r0: c0434c00
-r1: 2a4c9fbc
-r2: 00000000
-r3: c83ef1f9
-r4: 00000004
-r5: c2044904
-r6: 00000000
-r7: c20443b8
-r8: 000b33ff
-r9: c20444b0
-r10: cac90740
-r11: 00000000
-ip: ed891ca4
-sp: c2044218
-lr: ed807265
-pc: c898f508
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
deleted file mode 100644
index 35a6bc5..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
deleted file mode 100644
index def299e..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
deleted file mode 100644
index 7b876b5..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
deleted file mode 100644
index 3c468d6..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/entry0.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
deleted file mode 100644
index 2c7689b..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/entry1.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
deleted file mode 100644
index 22a35b8..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/entry2.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
deleted file mode 100644
index 61f3927..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/entry3.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
deleted file mode 100644
index 1a37628..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/entry4.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
deleted file mode 100644
index 7ef62ca..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/entry5.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
deleted file mode 100644
index 6d27c89..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/entry6.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
deleted file mode 100644
index bfbceea..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/jit0.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
deleted file mode 100644
index b78848e..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/jit1.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
deleted file mode 100644
index 8f927ac..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/jit2.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
deleted file mode 100644
index 1d1dfca..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/jit3.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
deleted file mode 100644
index 89aeb43..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/jit4.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
deleted file mode 100644
index e076934..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/jit5.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
deleted file mode 100644
index 17d6041..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/jit6.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
deleted file mode 100644
index aaff037..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libart.so b/libunwindstack/tests/files/offline/jit_debug_arm/libart.so
deleted file mode 100644
index 0527893..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/libart.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
deleted file mode 100644
index 8559056..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
deleted file mode 100644
index 06dbf10..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/libc.so b/libunwindstack/tests/files/offline/jit_debug_arm/libc.so
deleted file mode 100644
index 9894e66..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
deleted file mode 100644
index 3b87f2f..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-ab0d3000-ab0d8000 r-xp 0 00:00 0 dalvikvm32
-dfe4e000-dfe7b000 r-xp 0 00:00 0 libarttestd.so
-e0445000-e0447000 r--p 0 00:00 0 137-cfi.odex
-e0447000-e0448000 r-xp 2000 00:00 0 137-cfi.odex
-e2796000-e4796000 r-xp 0 00:00 0 anonymous:e2796000
-e648e000-e690f000 r-xp 0 00:00 0 libart.so
-e6918000-e6919000 rw-p 489000 00:00 0 libart.so
-ed306000-ed801000 r-xp 0 00:00 0 libartd.so
-ed80a000-ed80b000 rw-p 503000 00:00 0 libartd.so
-eda88000-edb23000 r-xp 0 00:00 0 libc.so
-ede4e000-ede50000 r-xp 0 00:00 0 anonymous:ede4e000
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/regs.txt b/libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
deleted file mode 100644
index 0e20066..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-r0: dfe7c0f8
-r1: 0
-r2: 0
-r3: 40000000
-r4: e051ffb4
-r5: 0
-r6: e051ffc0
-r7: ede514e8
-r8: ff85d1a8
-r9: ed9210c0
-r10: 58
-r11: 0
-ip: edb26d04
-sp: ff85d180
-lr: edaff5af
-pc: dfe66a5e
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm/stack.data b/libunwindstack/tests/files/offline/jit_debug_arm/stack.data
deleted file mode 100644
index b2ff14e..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_arm/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
deleted file mode 100644
index 870ac0a..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
deleted file mode 100644
index 76ffad9..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
deleted file mode 100644
index 466dae2..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/entry0.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
deleted file mode 100644
index 3a725e8..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/entry1.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
deleted file mode 100644
index 767550f..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/entry2.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
deleted file mode 100644
index e7e492e..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/entry3.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
deleted file mode 100644
index 65f9cd4..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/entry4.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
deleted file mode 100644
index 30aa28c..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/entry5.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
deleted file mode 100644
index 3c89673..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/entry6.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
deleted file mode 100644
index 9c9b83c..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/jit0.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
deleted file mode 100644
index eaad142..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/jit1.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
deleted file mode 100644
index d534816..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/jit2.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
deleted file mode 100644
index dbeb886..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/jit3.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
deleted file mode 100644
index bf2142d..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/jit4.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
deleted file mode 100644
index e2ba1b0..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/jit5.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
deleted file mode 100644
index c27ba54..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/jit6.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
deleted file mode 100644
index 5fc8fae..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
deleted file mode 100644
index 92ed991..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
deleted file mode 100644
index 5efae02..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/libc.so b/libunwindstack/tests/files/offline/jit_debug_x86/libc.so
deleted file mode 100644
index 9c78790..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
deleted file mode 100644
index c22b5de..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-56573000-56577000 r-xp 0 00:00 0 dalvikvm32
-eb833000-eb8cc000 r-xp 0 00:00 0 libarttestd.so
-ec604000-ec606000 r--p 0 00:00 0 137-cfi.odex
-ec606000-ec607000 r-xp 2000 00:00 0 137-cfi.odex
-ee74c000-f074c000 r-xp 0 00:00 0 anonymous:ee74c000
-f6be1000-f732b000 r-xp 0 00:00 0 libartd.so
-f7334000-f7335000 rw-p 752000 00:00 0 libartd.so
-f734b000-f74fc000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/regs.txt b/libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
deleted file mode 100644
index f68305b..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-eax: eb8cccd0
-ebx: eb8cccd0
-ecx: ff
-edx: ffeb2ca8
-ebp: ffeb5298
-edi: ffeb5c08
-esi: ffeb5c00
-esp: ffeb5280
-eip: eb89bfb8
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86/stack.data b/libunwindstack/tests/files/offline/jit_debug_x86/stack.data
deleted file mode 100644
index c345762..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
deleted file mode 100644
index e667883..0000000
--- a/libunwindstack/tests/files/offline/jit_map_arm/jit_map0.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so b/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
deleted file mode 100644
index 9a1d714..0000000
--- a/libunwindstack/tests/files/offline/jit_map_arm/jit_map1.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libart.so b/libunwindstack/tests/files/offline/jit_map_arm/libart.so
deleted file mode 100644
index 09ba495..0000000
--- a/libunwindstack/tests/files/offline/jit_map_arm/libart.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/libc.so b/libunwindstack/tests/files/offline/jit_map_arm/libc.so
deleted file mode 100644
index 39c9025..0000000
--- a/libunwindstack/tests/files/offline/jit_map_arm/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/maps.txt b/libunwindstack/tests/files/offline/jit_map_arm/maps.txt
deleted file mode 100644
index 5aaec54..0000000
--- a/libunwindstack/tests/files/offline/jit_map_arm/maps.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-e466e000-e4ae8000 r-xp 0 00:00 0 libart.so
-e7d91000-e7e31000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/regs.txt b/libunwindstack/tests/files/offline/jit_map_arm/regs.txt
deleted file mode 100644
index 0b51814..0000000
--- a/libunwindstack/tests/files/offline/jit_map_arm/regs.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-r0: e814103c
-r1: 12dcf218
-r2: 1a90df75
-r3: ffffffbf
-r4: 0
-r5: 12dc0800
-r6: 12dcf218
-r7: 1a90df75
-r8: 0
-r9: dd23cc00
-r10: 1c
-r11: cd4ff16c
-ip: 0
-sp: cd4ff140
-lr: d025cdd7
-pc: d025c788
diff --git a/libunwindstack/tests/files/offline/jit_map_arm/stack.data b/libunwindstack/tests/files/offline/jit_map_arm/stack.data
deleted file mode 100644
index fb8feeb..0000000
--- a/libunwindstack/tests/files/offline/jit_map_arm/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so
deleted file mode 100644
index 7bb7156..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64 b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64
deleted file mode 100644
index 00a3896..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/linker64
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt
deleted file mode 100644
index a2babee..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/maps.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-5f73997000-5f739dc000 r--p 0 00:00 0 test
-5f739dc000-5f73a43000 r-xp 44000 00:00 0 test
-711152c000-711156e000 r--p 0 00:00 0 libc.so
-711156e000-7111611000 --xp 42000 00:00 0 libc.so
-7112be2000-7112be4000 r-xp 0 00:00 0 vdso
-7112be4000-7112c1c000 r--p 0 00:00 0 linker64
-7112c1c000-7112ce1000 r-xp 38000 00:00 0 linker64
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt
deleted file mode 100644
index 3c601e1..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/regs.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-x0: 7112bdbc24
-x1: 0
-x2: ffffffff
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 7f7f7f7f7f7f7f7f
-x8: 62
-x9: a78826643b37f4a1
-x10: 7112bdbc20
-x11: 4100
-x12: 7112bdbb70
-x13: 18
-x14: 1d6518077
-x15: 2a43148faf732a
-x16: 16fc0
-x17: 71115f61a0
-x18: 7111d6a000
-x19: 7112cef1b0
-x20: 7112bdbda0
-x21: 59616d61
-x22: 1
-x23: 7112bdbc24
-x24: 4b0e
-x25: 62
-x26: 2
-x27: 0
-x28: 7111934020
-x29: 7112bdbd90
-sp: 7112bdbbf0
-lr: 7112c394ec
-pc: 7112cb99bc
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data
deleted file mode 100644
index 1674733..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data
deleted file mode 100644
index 6d7b48a..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/stack1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test
deleted file mode 100644
index 3a75b8f..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/test
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso b/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso
deleted file mode 100644
index 4940916..0000000
--- a/libunwindstack/tests/files/offline/load_bias_different_section_bias_arm64/vdso
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
deleted file mode 100644
index 63383d0..0000000
--- a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
deleted file mode 100644
index ba5a31b..0000000
--- a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/maps.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-200000-919000 r--p 0 00:00 0 perfetto_unittests
-919000-1a0c000 r-xp 719000 00:00 0 perfetto_unittests
-7f932696e000-7f9326b23000 r-xp 0 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
deleted file mode 100644
index a30e599..0000000
--- a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/perfetto_unittests
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
deleted file mode 100644
index 6cb4055..0000000
--- a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/regs.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-rax: 3b
-rbx: 3b
-rcx: 7f9326a57dd4
-rdx: 3b
-r8: 7ffd22415b09
-r9: 7ffd224155e0
-r10: 0
-r11: 246
-r12: 7f9326d28760
-r13: 3b
-r14: 7f9326d23760
-r15: 3b
-rdi: 1
-rsi: 2678850
-rbp: 2678850
-rsp: 7ffd224153c8
-rip: 7f9326a57dd4
diff --git a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data b/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
deleted file mode 100644
index 4edfe07..0000000
--- a/libunwindstack/tests/files/offline/load_bias_ro_rx_x86_64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/libc.so b/libunwindstack/tests/files/offline/offset_arm/libc.so
deleted file mode 100644
index 9f5c8ca..0000000
--- a/libunwindstack/tests/files/offline/offset_arm/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test b/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
deleted file mode 100644
index 7a30bfa..0000000
--- a/libunwindstack/tests/files/offline/offset_arm/libunwindstack_test
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/maps.txt b/libunwindstack/tests/files/offline/offset_arm/maps.txt
deleted file mode 100644
index 768dd9f..0000000
--- a/libunwindstack/tests/files/offline/offset_arm/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-2b2a000-2b6c000 r--p 0 00:00 0 libunwindstack_test
-2b6c000-2e92000 r-xp 42000 00:00 0 libunwindstack_test
-f4110000-f4135000 r--p 0 00:00 0 libc.so
-f4135000-f41a9000 r-xp 25000 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/offset_arm/regs.txt b/libunwindstack/tests/files/offline/offset_arm/regs.txt
deleted file mode 100644
index 1f4ac8f..0000000
--- a/libunwindstack/tests/files/offline/offset_arm/regs.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-r0: 5
-r1: 5
-r2: 4
-r3: 1
-r4: 73804b6b
-r5: f3c9c000
-r6: 2ea09ac
-r7: 10624dd3
-r8: f41b5d8c
-r9: f3c9c000
-r10: 6f17
-r11: f3c94048
-ip: 2ea0807
-sp: f43d2ccc
-lr: 2e55fef
-pc: 2e55fa0
diff --git a/libunwindstack/tests/files/offline/offset_arm/stack0.data b/libunwindstack/tests/files/offline/offset_arm/stack0.data
deleted file mode 100644
index 23a9874..0000000
--- a/libunwindstack/tests/files/offline/offset_arm/stack0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/offset_arm/stack1.data b/libunwindstack/tests/files/offline/offset_arm/stack1.data
deleted file mode 100644
index 49bdd1e..0000000
--- a/libunwindstack/tests/files/offline/offset_arm/stack1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk
deleted file mode 100644
index 0277359..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/ANGLEPrebuilt.apk
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so
deleted file mode 100644
index 20008fd..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64 b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64
deleted file mode 100644
index b90933b..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/linker64
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt
deleted file mode 100644
index c4fc067..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/maps.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-7dabc03000-7dabc3f000 r--p 4000 00:00 0 ANGLEPrebuilt.apk
-7dabc3f000-7dabcf0000 r-xp 40000 00:00 0 ANGLEPrebuilt.apk
-7e7ee48000-7e7ee88000 r--p 0 00:00 0 libc.so
-7e7ee88000-7e7ef32000 r-xp 40000 00:00 0 libc.so
-7e82b01000-7e82b03000 r-xp 0 00:00 0 vdso.so
-7e82b03000-7e82b3c000 r--p 0 00:00 0 linker64
-7e82b3c000-7e82c77000 r-xp 39000 00:00 0 linker64
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt
deleted file mode 100644
index 1e2ea32..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/regs.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-x0: 7df8ca3c24
-x1: 0
-x2: ffffffff
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 7f7f7f7f7f7f7f7f
-x8: 62
-x9: 20dd5829922a93ac
-x10: 7e82b57420
-x11: 4100
-x12: 7df8ca3b70
-x13: 7df8ca3b98
-x14: 73d015e5
-x15: 39a36122467299
-x16: 76ac
-x17: 0
-x18: 7df8cfc000
-x19: 7dabf3e7a0
-x20: 7df8ca3da0
-x21: 59616d61
-x22: 1
-x23: 7df8ca3c24
-x24: 1894
-x25: 62
-x26: 2
-x27: 0
-x28: 7dabf3e790
-x29: 7df8ca3d90
-sp: 7df8ca3bf0
-lr: 7e82b57270
-pc: 7e82c4fcbc
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data
deleted file mode 100644
index ec07e15..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data
deleted file mode 100644
index 825bb1a..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/stack1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so
deleted file mode 100644
index 205ebd4..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_arm64/vdso.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data
deleted file mode 100644
index f39d127..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/lib_mem.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so
deleted file mode 100644
index 20008fd..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64 b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64
deleted file mode 100644
index b90933b..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/linker64
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt
deleted file mode 100644
index 386d57a..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/maps.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-7dabc03000-7dabc3f000 r--p 21d5000 00:00 0 ANGLEPrebuilt.apk
-7dabc3f000-7dabcf0000 r-xp 2211000 00:00 0 ANGLEPrebuilt.apk
-7e7ee48000-7e7ee88000 r--p 0 00:00 0 libc.so
-7e7ee88000-7e7ef32000 r-xp 40000 00:00 0 libc.so
-7e82b01000-7e82b03000 r-xp 0 00:00 0 vdso.so
-7e82b03000-7e82b3c000 r--p 0 00:00 0 linker64
-7e82b3c000-7e82c77000 r-xp 39000 00:00 0 linker64
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt
deleted file mode 100644
index 1e2ea32..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/regs.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-x0: 7df8ca3c24
-x1: 0
-x2: ffffffff
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 7f7f7f7f7f7f7f7f
-x8: 62
-x9: 20dd5829922a93ac
-x10: 7e82b57420
-x11: 4100
-x12: 7df8ca3b70
-x13: 7df8ca3b98
-x14: 73d015e5
-x15: 39a36122467299
-x16: 76ac
-x17: 0
-x18: 7df8cfc000
-x19: 7dabf3e7a0
-x20: 7df8ca3da0
-x21: 59616d61
-x22: 1
-x23: 7df8ca3c24
-x24: 1894
-x25: 62
-x26: 2
-x27: 0
-x28: 7dabf3e790
-x29: 7df8ca3d90
-sp: 7df8ca3bf0
-lr: 7e82b57270
-pc: 7e82c4fcbc
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data
deleted file mode 100644
index ec07e15..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data
deleted file mode 100644
index 825bb1a..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/stack1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so
deleted file mode 100644
index 205ebd4..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_memory_only_arm64/vdso.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
deleted file mode 100644
index cac1dd9..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
deleted file mode 100644
index 2c5ca62..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/maps.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-7be5e48000-7be6b2b000 r-xp 5000 00:00 0 test.apk
-7cbe030000-7cbe070000 r--p 0 00:00 0 libc.so
-7cbe070000-7cbe11a000 r-xp 40000 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
deleted file mode 100644
index 090aeda..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/regs.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-x0: 7c326f6568
-x1: 80
-x2: 0
-x3: 0
-x4: 0
-x5: 0
-x6: 0
-x7: 7f7f7f7f7f7f7f7f
-x8: 62
-x9: 1
-x10: 1
-x11: 0
-x12: ffffffffc4653600
-x13: 17645696f
-x14: 2742ed97ca77a3
-x15: 3ab49084
-x16: 7be6b6bdb8
-x17: 7cbe0b14a0
-x18: 7c2b02a000
-x19: 0
-x20: 7c326f6568
-x21: 7be69c827c
-x22: 7be69c8272
-x23: 1
-x24: 7be74f7100
-x25: 881
-x26: 7be4f07a00
-x27: c479c000
-x28: 7be4f07998
-x29: 7be4f079b4
-sp: 7be4f077d0
-lr: 7be6715f60
-pc: 7cbe0b14bc
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
deleted file mode 100644
index 27d5bf3..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk b/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
deleted file mode 100644
index 70a9c71..0000000
--- a/libunwindstack/tests/files/offline/shared_lib_in_apk_single_map_arm64/test.apk
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so b/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so
deleted file mode 100644
index f046624..0000000
--- a/libunwindstack/tests/files/offline/signal_load_bias_arm/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test b/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test
deleted file mode 100644
index f460dd6..0000000
--- a/libunwindstack/tests/files/offline/signal_load_bias_arm/libunwindstack_unit_test
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt b/libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt
deleted file mode 100644
index 165ae49..0000000
--- a/libunwindstack/tests/files/offline/signal_load_bias_arm/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-b66b7000-b670c000 r--p 0 00:00 0 libunwindstack_unit_test
-b670c000-b69a8000 r-xp 54000 00:00 0 libunwindstack_unit_test
-f23a6000-f23d0000 r--p 0 00:00 0 libc.so
-f23d0000-f2451000 r-xp 29000 00:00 0 libc.so
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt b/libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt
deleted file mode 100644
index e03f8fd..0000000
--- a/libunwindstack/tests/files/offline/signal_load_bias_arm/regs.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-r0: b69b7c84
-r1: 1
-r2: 1
-r3: 1
-r4: f1e52bd0
-r5: f1e11000
-r6: f1e52bd0
-r7: f1e52a38
-r8: f1e11000
-r9: 5de82a8f
-r10: f1e06030
-r11: f1e6d080
-ip: ffe67a88
-sp: f2790ce8
-lr: b6955fab
-pc: b6955f9e
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data
deleted file mode 100644
index d9f23f8..0000000
--- a/libunwindstack/tests/files/offline/signal_load_bias_arm/stack0.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data b/libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data
deleted file mode 100644
index 6011883..0000000
--- a/libunwindstack/tests/files/offline/signal_load_bias_arm/stack1.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm/libbase.so b/libunwindstack/tests/files/offline/straddle_arm/libbase.so
deleted file mode 100644
index d1f16ee..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm/libbase.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm/libc.so b/libunwindstack/tests/files/offline/straddle_arm/libc.so
deleted file mode 100644
index 4dc19ca..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm/libc.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm/maps.txt b/libunwindstack/tests/files/offline/straddle_arm/maps.txt
deleted file mode 100644
index 8c26479..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm/maps.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-f2d9a000-f2da7fff r-xp 00000000 00:00 0 libbase.so
-f3002000-f3005fff rw-p 00000000 00:00 0 [stack:25941]
-f31d0000-f326bfff r-xp 00000000 00:00 0 libc.so
-f3352000-f336bfff r-xp 00000000 00:00 0 /does/not/exist/libhidlbase.so
diff --git a/libunwindstack/tests/files/offline/straddle_arm/regs.txt b/libunwindstack/tests/files/offline/straddle_arm/regs.txt
deleted file mode 100644
index 3baedf3..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm/regs.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-pc: f31ea9f8
-sp: e9c866f8
-lr: f31f179f
diff --git a/libunwindstack/tests/files/offline/straddle_arm/stack.data b/libunwindstack/tests/files/offline/straddle_arm/stack.data
deleted file mode 100644
index 83aeb4a..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test b/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
deleted file mode 100644
index 092fc3a..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm64/libunwindstack_test
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/maps.txt b/libunwindstack/tests/files/offline/straddle_arm64/maps.txt
deleted file mode 100644
index bdf29b5..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm64/maps.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-00000064d05ab000-00000064d0a6cfff r-xp 00000000 00:00 0 libunwindstack_test
-0000007fe0d64000-0000007fe0d84fff rw-p 00000000 00:00 0 [stack]
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/regs.txt b/libunwindstack/tests/files/offline/straddle_arm64/regs.txt
deleted file mode 100644
index ff8a936..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm64/regs.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-pc: 00000064d09d4fd8
-sp: 0000007fe0d84040
-lr: 00000064d09d507c
-x29: 0000007fe0d84070
diff --git a/libunwindstack/tests/files/offline/straddle_arm64/stack.data b/libunwindstack/tests/files/offline/straddle_arm64/stack.data
deleted file mode 100644
index 824d0e2..0000000
--- a/libunwindstack/tests/files/offline/straddle_arm64/stack.data
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp b/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
deleted file mode 100644
index 0415ef6..0000000
--- a/libunwindstack/tests/fuzz/UnwinderComponentCreator.cpp
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright 2020 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 "UnwinderComponentCreator.h"
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-std::unique_ptr<Regs> GetRegisters(ArchEnum arch) {
- switch (arch) {
- case unwindstack::ARCH_ARM: {
- std::unique_ptr<unwindstack::RegsArm> regs = std::make_unique<unwindstack::RegsArm>();
- return regs;
- }
- case unwindstack::ARCH_ARM64: {
- std::unique_ptr<unwindstack::RegsArm64> regs = std::make_unique<unwindstack::RegsArm64>();
- return regs;
- }
- case unwindstack::ARCH_X86: {
- std::unique_ptr<unwindstack::RegsX86> regs = std::make_unique<unwindstack::RegsX86>();
- return regs;
- }
- case unwindstack::ARCH_X86_64: {
- std::unique_ptr<unwindstack::RegsX86_64> regs = std::make_unique<unwindstack::RegsX86_64>();
- return regs;
- }
- case unwindstack::ARCH_MIPS: {
- std::unique_ptr<unwindstack::RegsMips> regs = std::make_unique<unwindstack::RegsMips>();
- return regs;
- }
- case unwindstack::ARCH_MIPS64: {
- std::unique_ptr<unwindstack::RegsMips64> regs = std::make_unique<unwindstack::RegsMips64>();
- return regs;
- }
- case unwindstack::ARCH_UNKNOWN:
- default: {
- std::unique_ptr<unwindstack::RegsX86_64> regs = std::make_unique<unwindstack::RegsX86_64>();
- return regs;
- }
- }
-}
-
-ArchEnum GetArch(FuzzedDataProvider* data_provider) {
- uint8_t arch = data_provider->ConsumeIntegralInRange<uint8_t>(1, kArchCount);
- return static_cast<ArchEnum>(arch);
-}
-
-void ElfAddMapInfo(Maps* maps, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
- const char* name, Elf* elf = nullptr) {
- std::string str_name(name);
- maps->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
- if (elf != nullptr) {
- const auto& map_info = *--maps->end();
- map_info->elf.reset(elf);
- }
-}
-
-void ElfPushFakeFunctionData(FuzzedDataProvider* data_provider, ElfInterfaceFake* elf) {
- uint8_t func_count = data_provider->ConsumeIntegralInRange<uint>(0, kMaxFuncCount);
- for (uint8_t i = 0; i < func_count; i++) {
- std::string func_name = data_provider->ConsumeRandomLengthString(kMaxFuncNameLen);
- bool global = data_provider->ConsumeBool();
- if (global) {
- elf->FakeSetGlobalVariable(func_name, data_provider->ConsumeIntegral<uint64_t>());
- } else {
- ElfInterfaceFake::FakePushFunctionData(FunctionData(func_name, i));
- }
- }
-}
-void ElfPushFakeStepData(FuzzedDataProvider* data_provider) {
- uint8_t step_count = data_provider->ConsumeIntegralInRange<uint>(0, kMaxStepCount);
- for (uint8_t i = 0; i < step_count; i++) {
- uint64_t pc = data_provider->ConsumeIntegral<uint64_t>();
- uint64_t sp = data_provider->ConsumeIntegral<uint64_t>();
- bool finished = i + 1 == step_count;
- ElfInterfaceFake::FakePushStepData(StepData(pc, sp, finished));
- }
-}
-
-ElfFake* PopulateElfFake(FuzzedDataProvider* data_provider) {
- // This will be passed to a smart pointer in ElfAddMapInfo.
- ElfFake* elf = new ElfFake(new MemoryFake);
-
- // This will be handled by a smart pointer within Elf.
- ElfInterfaceFake* interface_fake = new ElfInterfaceFake(nullptr);
- std::string build_id = data_provider->ConsumeRandomLengthString(kMaxBuildIdLen);
- interface_fake->FakeSetBuildID(build_id);
- std::string so_name = data_provider->ConsumeRandomLengthString(kMaxSoNameLen);
- interface_fake->FakeSetSoname(so_name.c_str());
-
- elf->FakeSetArch(GetArch(data_provider));
- elf->FakeSetLoadBias(data_provider->ConsumeIntegral<uint64_t>());
-
- ElfPushFakeFunctionData(data_provider, interface_fake);
- ElfPushFakeStepData(data_provider);
-
- elf->FakeSetInterface(interface_fake);
- ElfInterfaceFake::FakeClear();
- return elf;
-}
-
-static constexpr size_t kPageSize = 4096;
-
-static constexpr uint64_t AlignToPage(uint64_t address) {
- return (address + kPageSize - 1) & ~(kPageSize - 1);
-}
-
-std::unique_ptr<Maps> GetMaps(FuzzedDataProvider* data_provider) {
- std::unique_ptr<Maps> maps = std::make_unique<Maps>();
- std::map<uint64_t, uint64_t> map_ends;
- uint8_t entry_count = data_provider->ConsumeIntegralInRange<uint8_t>(0, kMaxMapEntryCount);
- for (uint8_t i = 0; i < entry_count; i++) {
- uint64_t start = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
- uint64_t end = AlignToPage(data_provider->ConsumeIntegralInRange<uint64_t>(start, UINT64_MAX));
- // Make sure not to add overlapping maps, that is not something that can
- // happen in the real world.
- auto entry = map_ends.upper_bound(start);
- if (entry != map_ends.end() && end > entry->second) {
- continue;
- }
- map_ends[end] = start;
-
- uint64_t offset = AlignToPage(data_provider->ConsumeIntegral<uint64_t>());
- std::string map_info_name = data_provider->ConsumeRandomLengthString(kMaxMapInfoNameLen);
- uint8_t flags = PROT_READ | PROT_WRITE;
-
- bool exec = data_provider->ConsumeBool();
- if (exec) {
- flags |= PROT_EXEC;
- }
-
- bool shouldAddElf = data_provider->ConsumeBool();
- if (shouldAddElf) {
- ElfAddMapInfo(maps.get(), start, end, offset, flags, map_info_name.c_str(),
- PopulateElfFake(data_provider));
- } else {
- ElfAddMapInfo(maps.get(), start, end, offset, flags, map_info_name.c_str());
- }
- }
- maps->Sort();
- return maps;
-}
-
-// This code (until PutElfFilesInMemory) is pretty much directly copied from JitDebugTest.cpp
-// There's a few minor modifications, most notably, all methods accept a MemoryFake pointer, and
-// PutElfInMemory inserts JIT data when called.
-void WriteDescriptor32(MemoryFake* memory, 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 WriteDescriptor64(MemoryFake* memory, 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 WriteEntry32Pack(MemoryFake* memory, uint64_t addr, uint32_t prev, uint32_t next,
- uint32_t elf_addr, uint64_t elf_size) {
- // Format of the 32 bit JITCodeEntry structure:
- // uint32_t next
- memory->SetData32(addr, next);
- // uint32_t prev
- memory->SetData32(addr + 4, prev);
- // uint32_t symfile_addr
- memory->SetData32(addr + 8, elf_addr);
- // uint64_t symfile_size
- memory->SetData64(addr + 12, elf_size);
-}
-
-void WriteEntry32Pad(MemoryFake* memory, uint64_t addr, uint32_t prev, uint32_t next,
- uint32_t elf_addr, uint64_t elf_size) {
- // Format of the 32 bit JITCodeEntry structure:
- // uint32_t next
- memory->SetData32(addr, next);
- // uint32_t prev
- memory->SetData32(addr + 4, prev);
- // uint32_t symfile_addr
- memory->SetData32(addr + 8, elf_addr);
- // uint32_t pad
- memory->SetData32(addr + 12, 0);
- // uint64_t symfile_size
- memory->SetData64(addr + 16, elf_size);
-}
-
-void WriteEntry64(MemoryFake* memory, uint64_t addr, uint64_t prev, uint64_t next,
- uint64_t elf_addr, uint64_t elf_size) {
- // Format of the 64 bit JITCodeEntry structure:
- // uint64_t next
- memory->SetData64(addr, next);
- // uint64_t prev
- memory->SetData64(addr + 8, prev);
- // uint64_t symfile_addr
- memory->SetData64(addr + 16, elf_addr);
- // uint64_t symfile_size
- memory->SetData64(addr + 24, elf_size);
-}
-
-template <typename EhdrType, typename ShdrType>
-void PutElfInMemory(MemoryFake* memory, uint64_t offset, uint8_t class_type, uint8_t machine_type,
- uint32_t pc, uint32_t size) {
- EhdrType ehdr;
- memset(&ehdr, 0, sizeof(ehdr));
- uint64_t sh_offset = sizeof(ehdr);
- memcpy(ehdr.e_ident, ELFMAG, SELFMAG);
- ehdr.e_ident[EI_CLASS] = class_type;
- ehdr.e_machine = machine_type;
- ehdr.e_shstrndx = 1;
- ehdr.e_shoff = sh_offset;
- ehdr.e_shentsize = sizeof(ShdrType);
- ehdr.e_shnum = 3;
- memory->SetMemory(offset, &ehdr, sizeof(ehdr));
-
- ShdrType shdr;
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_NULL;
- memory->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_STRTAB;
- shdr.sh_name = 1;
- shdr.sh_offset = 0x500;
- shdr.sh_size = 0x100;
- memory->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
- memory->SetMemory(offset + 0x500, ".debug_frame");
-
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_PROGBITS;
- shdr.sh_name = 0;
- shdr.sh_addr = 0x600;
- shdr.sh_offset = 0x600;
- shdr.sh_size = 0x200;
- memory->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
-
- // Now add a single cie/fde.
- uint64_t dwarf_offset = offset + 0x600;
- if (class_type == ELFCLASS32) {
- // CIE 32 information.
- memory->SetData32(dwarf_offset, 0xfc);
- memory->SetData32(dwarf_offset + 0x4, 0xffffffff);
- memory->SetData8(dwarf_offset + 0x8, 1);
- memory->SetData8(dwarf_offset + 0x9, '\0');
- memory->SetData8(dwarf_offset + 0xa, 0x4);
- memory->SetData8(dwarf_offset + 0xb, 0x4);
- memory->SetData8(dwarf_offset + 0xc, 0x1);
-
- // FDE 32 information.
- memory->SetData32(dwarf_offset + 0x100, 0xfc);
- memory->SetData32(dwarf_offset + 0x104, 0);
- memory->SetData32(dwarf_offset + 0x108, pc);
- memory->SetData32(dwarf_offset + 0x10c, size);
- } else {
- // CIE 64 information.
- memory->SetData32(dwarf_offset, 0xffffffff);
- memory->SetData64(dwarf_offset + 4, 0xf4);
- memory->SetData64(dwarf_offset + 0xc, 0xffffffffffffffffULL);
- memory->SetData8(dwarf_offset + 0x14, 1);
- memory->SetData8(dwarf_offset + 0x15, '\0');
- memory->SetData8(dwarf_offset + 0x16, 0x4);
- memory->SetData8(dwarf_offset + 0x17, 0x4);
- memory->SetData8(dwarf_offset + 0x18, 0x1);
-
- // FDE 64 information.
- memory->SetData32(dwarf_offset + 0x100, 0xffffffff);
- memory->SetData64(dwarf_offset + 0x104, 0xf4);
- memory->SetData64(dwarf_offset + 0x10c, 0);
- memory->SetData64(dwarf_offset + 0x114, pc);
- memory->SetData64(dwarf_offset + 0x11c, size);
- }
-}
-
-void PutElfFilesInMemory(MemoryFake* memory, FuzzedDataProvider* data_provider) {
- uint8_t elf_file_count = data_provider->ConsumeIntegralInRange<uint8_t>(0, kMaxJitElfFiles);
- int entry_offset = 0;
- int prev_jit_addr = 0;
- for (uint8_t i = 0; i < elf_file_count; i++) {
- uint64_t offset = data_provider->ConsumeIntegral<uint64_t>();
- // Technically the max valid value is ELFCLASSNUM - 1 (2), but
- // we want to test values outside of that range.
- uint8_t class_type = data_provider->ConsumeIntegral<uint8_t>();
- // Same here, EM_NUM is 253, max valid machine type is 252
- uint8_t machine_type = data_provider->ConsumeIntegral<uint8_t>();
- uint32_t pc = data_provider->ConsumeIntegral<uint32_t>();
- uint32_t size = data_provider->ConsumeIntegral<uint32_t>();
- bool sixty_four_bit = data_provider->ConsumeBool();
- bool write_jit = data_provider->ConsumeBool();
- if (sixty_four_bit) {
- PutElfInMemory<Elf64_Ehdr, Elf64_Shdr>(memory, offset, class_type, machine_type, pc, size);
- } else {
- PutElfInMemory<Elf32_Ehdr, Elf32_Shdr>(memory, offset, class_type, machine_type, pc, size);
- }
- if (write_jit) {
- bool use_pad = data_provider->ConsumeBool();
- // It is possible this will overwrite part of the ELF.
- // This provides an interesting test of how malformed ELF
- // data is handled.
- uint64_t cur_descriptor_addr = 0x11800 + entry_offset;
- uint64_t cur_jit_addr = 0x200000 + entry_offset;
- uint64_t next_jit_addr = cur_jit_addr + size;
- if (sixty_four_bit) {
- WriteDescriptor64(memory, 0x11800, cur_jit_addr);
- WriteEntry64(memory, cur_jit_addr, prev_jit_addr, next_jit_addr, pc, size);
- } else {
- // Loop back. Again, this may corrupt data,
- // but that will allow for testing edge cases with
- // malformed JIT data.
- if (cur_jit_addr > UINT32_MAX) {
- entry_offset = 0;
- cur_jit_addr = 0x200000;
- cur_descriptor_addr = 0x11800;
- next_jit_addr = cur_jit_addr + size;
- }
- WriteDescriptor32(memory, cur_descriptor_addr, cur_jit_addr);
- if (use_pad) {
- WriteEntry32Pad(memory, cur_jit_addr, prev_jit_addr, next_jit_addr, pc, size);
- } else {
- WriteEntry32Pack(memory, cur_jit_addr, prev_jit_addr, next_jit_addr, pc, size);
- }
- }
- entry_offset += size;
- prev_jit_addr = cur_jit_addr;
- }
- }
-}
-
-std::vector<std::string> GetStringList(FuzzedDataProvider* data_provider, uint max_str_len,
- uint max_strings) {
- uint str_count = data_provider->ConsumeIntegralInRange<uint>(0, max_strings);
- std::vector<std::string> strings;
- for (uint i = 0; i < str_count; i++) {
- strings.push_back(data_provider->ConsumeRandomLengthString(max_str_len));
- }
- return strings;
-}
-
-std::unique_ptr<DexFiles> GetDexFiles(FuzzedDataProvider* data_provider,
- std::shared_ptr<Memory> memory, uint max_library_length,
- uint max_libraries) {
- std::vector<std::string> search_libs =
- GetStringList(data_provider, max_library_length, max_libraries);
- if (search_libs.size() <= 0) {
- return std::make_unique<DexFiles>(memory);
- }
-
- return std::make_unique<DexFiles>(memory, search_libs);
-}
diff --git a/libunwindstack/tests/fuzz/UnwinderComponentCreator.h b/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
deleted file mode 100644
index 09b3379..0000000
--- a/libunwindstack/tests/fuzz/UnwinderComponentCreator.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2020 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_UNWINDERCOMPONENTCREATOR_H
-#define _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
-
-#include <elf.h>
-#include <sys/mman.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <fuzzer/FuzzedDataProvider.h>
-#include <unwindstack/DexFiles.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/RegsArm.h>
-#include <unwindstack/RegsArm64.h>
-#include <unwindstack/RegsMips.h>
-#include <unwindstack/RegsMips64.h>
-#include <unwindstack/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
-
-#include "../ElfFake.h"
-#include "../MemoryFake.h"
-
-#include "fuzzer/FuzzedDataProvider.h"
-
-using unwindstack::ArchEnum;
-using unwindstack::DexFiles;
-using unwindstack::Elf;
-using unwindstack::ElfFake;
-using unwindstack::ElfInterfaceFake;
-using unwindstack::FunctionData;
-using unwindstack::Maps;
-using unwindstack::Memory;
-using unwindstack::MemoryFake;
-using unwindstack::Regs;
-using unwindstack::StepData;
-
-static constexpr uint8_t kArchCount = 6;
-
-static constexpr uint8_t kMaxSoNameLen = 150;
-
-static constexpr uint8_t kMaxFuncNameLen = 50;
-static constexpr uint8_t kMaxFuncCount = 100;
-
-static constexpr uint8_t kMaxJitElfFiles = 20;
-static constexpr uint8_t kJitElfPadding = 32;
-
-static constexpr uint8_t kMaxStepCount = 100;
-static constexpr uint8_t kMaxMapEntryCount = 50;
-static constexpr uint8_t kMaxBuildIdLen = 100;
-static constexpr uint8_t kMaxMapInfoNameLen = 150;
-
-std::unique_ptr<unwindstack::Regs> GetRegisters(unwindstack::ArchEnum arch);
-std::unique_ptr<unwindstack::Maps> GetMaps(FuzzedDataProvider* data_provider);
-std::vector<std::string> GetStringList(FuzzedDataProvider* data_provider, uint max_str_len,
- uint max_strings);
-unwindstack::ArchEnum GetArch(FuzzedDataProvider* data_provider);
-
-void AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name,
- Elf* elf = nullptr);
-void PutElfFilesInMemory(MemoryFake* memory, FuzzedDataProvider* data_provider);
-
-std::unique_ptr<unwindstack::DexFiles> GetDexFiles(FuzzedDataProvider* data_provider,
- std::shared_ptr<unwindstack::Memory> memory,
- uint max_libraries, uint max_library_length);
-#endif // _LIBUNWINDSTACK_UNWINDERCOMPONENTCREATOR_H
diff --git a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp b/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
deleted file mode 100644
index 2f4986a..0000000
--- a/libunwindstack/tests/fuzz/UnwinderFuzz.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2020 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 <functional>
-#include <iostream>
-#include <vector>
-
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Unwinder.h>
-
-#include "../MemoryFake.h"
-#include "UnwinderComponentCreator.h"
-#include "fuzzer/FuzzedDataProvider.h"
-
-namespace unwindstack {
-
-static constexpr int kMaxUnwindStringLen = 50;
-static constexpr int kMaxUnwindStrings = 50;
-
-void PerformUnwind(FuzzedDataProvider* data_provider, Unwinder* unwinder) {
- // 0 = don't set any values
- // 1 = set initial_map_names_to_skip
- // 2 = set map_suffixes_to_ignore
- // 3 = set both
- uint8_t set_values = data_provider->ConsumeIntegral<uint8_t>() % 4;
- if (set_values == 0) {
- unwinder->Unwind();
- } else if (set_values == 1) {
- // Only setting initial_map_names_to_skip
- std::vector<std::string> skip_names =
- GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
-
- unwinder->Unwind(&skip_names, nullptr);
- } else if (set_values == 2) {
- // Only setting map_suffixes_to_ignore
- std::vector<std::string> ignore_suffixes =
- GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
-
- unwinder->Unwind(nullptr, &ignore_suffixes);
- } else if (set_values == 3) {
- // Setting both values
- std::vector<std::string> skip_names =
- GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
- std::vector<std::string> ignore_suffixes =
- GetStringList(data_provider, kMaxUnwindStringLen, kMaxUnwindStrings);
-
- unwinder->Unwind(&skip_names, &ignore_suffixes);
- }
-}
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider data_provider(data, size);
-
- // We need to construct an unwinder.
- // Generate the Maps:
- std::unique_ptr<Maps> maps = GetMaps(&data_provider);
-
- // Generate the Regs:
- uint8_t arch_val = data_provider.ConsumeIntegralInRange<uint8_t>(1, kArchCount);
- ArchEnum arch = static_cast<ArchEnum>(arch_val);
- std::unique_ptr<Regs> regs = GetRegisters(arch);
-
- // Generate memory:
- std::shared_ptr<Memory> memory = std::make_shared<MemoryFake>();
- PutElfFilesInMemory(reinterpret_cast<MemoryFake*>(memory.get()), &data_provider);
-
- size_t max_frames = data_provider.ConsumeIntegralInRange<size_t>(0, 5000);
-
- std::unique_ptr<JitDebug> jit_debug_ptr = std::make_unique<JitDebug>(memory);
-
- // Create instance
- Unwinder unwinder(max_frames, maps.get(), regs.get(), memory);
- unwinder.SetJitDebug(jit_debug_ptr.get(), arch);
- unwinder.SetResolveNames(data_provider.ConsumeBool());
- // Call unwind
- PerformUnwind(&data_provider, &unwinder);
-
- // Run some additional logic that changes after unwind
- uint64_t pc = data_provider.ConsumeIntegral<uint64_t>();
- unwinder.BuildFrameFromPcOnly(pc);
- unwinder.ConsumeFrames();
- return 0;
-}
-} // namespace unwindstack
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
deleted file mode 100644
index 1812e50..0000000
--- a/libunwindstack/tools/unwind.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <unwindstack/DexFiles.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
-
-static bool Attach(pid_t pid) {
- if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) {
- return false;
- }
-
- if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) {
- ptrace(PTRACE_DETACH, pid, 0, 0);
- return false;
- }
-
- // Allow at least 1 second to attach properly.
- for (size_t i = 0; i < 1000; i++) {
- siginfo_t si;
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- return true;
- }
- usleep(1000);
- }
- printf("%d: Failed to stop.\n", pid);
- return false;
-}
-
-void DoUnwind(pid_t pid) {
- unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
- if (regs == nullptr) {
- printf("Unable to get remote reg data\n");
- return;
- }
-
- printf("ABI: ");
- switch (regs->Arch()) {
- case unwindstack::ARCH_ARM:
- printf("arm");
- break;
- case unwindstack::ARCH_X86:
- printf("x86");
- break;
- case unwindstack::ARCH_ARM64:
- printf("arm64");
- break;
- case unwindstack::ARCH_X86_64:
- printf("x86_64");
- break;
- case unwindstack::ARCH_MIPS:
- printf("mips");
- break;
- case unwindstack::ARCH_MIPS64:
- printf("mips64");
- break;
- default:
- printf("unknown\n");
- return;
- }
- printf("\n");
-
- unwindstack::UnwinderFromPid unwinder(1024, pid);
- if (!unwinder.Init(regs->Arch())) {
- printf("Failed to init unwinder object.\n");
- return;
- }
-
- unwinder.SetRegs(regs);
- unwinder.Unwind();
-
- // Print the frames.
- for (size_t i = 0; i < unwinder.NumFrames(); i++) {
- printf("%s\n", unwinder.FormatFrame(i).c_str());
- }
-}
-
-int main(int argc, char** argv) {
- if (argc != 2) {
- printf("Usage: unwind <PID>\n");
- return 1;
- }
-
- pid_t pid = atoi(argv[1]);
- if (!Attach(pid)) {
- printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
- return 1;
- }
-
- DoUnwind(pid);
-
- ptrace(PTRACE_DETACH, pid, 0, 0);
-
- return 0;
-}
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
deleted file mode 100644
index 64b58a8..0000000
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _GNU_SOURCE 1
-#include <errno.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
-#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
-#include <unwindstack/Regs.h>
-#include <unwindstack/Unwinder.h>
-
-#include <android-base/stringprintf.h>
-
-struct map_info_t {
- uint64_t start;
- uint64_t end;
- uint64_t offset;
- uint64_t flags;
- std::string name;
-};
-
-static bool Attach(pid_t pid) {
- if (ptrace(PTRACE_SEIZE, pid, 0, 0) == -1) {
- return false;
- }
-
- if (ptrace(PTRACE_INTERRUPT, pid, 0, 0) == -1) {
- ptrace(PTRACE_DETACH, pid, 0, 0);
- return false;
- }
-
- // Allow at least 1 second to attach properly.
- for (size_t i = 0; i < 1000; i++) {
- siginfo_t si;
- if (ptrace(PTRACE_GETSIGINFO, pid, 0, &si) == 0) {
- return true;
- }
- usleep(1000);
- }
- printf("%d: Failed to stop.\n", pid);
- return false;
-}
-
-bool SaveRegs(unwindstack::Regs* regs) {
- std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("regs.txt", "w+"), &fclose);
- if (fp == nullptr) {
- perror("Failed to create file regs.txt");
- return false;
- }
- regs->IterateRegisters([&fp](const char* name, uint64_t value) {
- fprintf(fp.get(), "%s: %" PRIx64 "\n", name, value);
- });
-
- return true;
-}
-
-bool SaveStack(pid_t pid, const std::vector<std::pair<uint64_t, uint64_t>>& stacks) {
- for (size_t i = 0; i < stacks.size(); i++) {
- std::string file_name;
- if (stacks.size() != 1) {
- file_name = "stack" + std::to_string(i) + ".data";
- } else {
- file_name = "stack.data";
- }
-
- // Do this first, so if it fails, we don't create the file.
- uint64_t sp_start = stacks[i].first;
- uint64_t sp_end = stacks[i].second;
- std::vector<uint8_t> buffer(sp_end - sp_start);
- auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
- if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
- printf("Unable to read stack data.\n");
- return false;
- }
-
- printf("Saving the stack 0x%" PRIx64 "-0x%" PRIx64 "\n", sp_start, sp_end);
-
- std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file_name.c_str(), "w+"), &fclose);
- if (fp == nullptr) {
- perror("Failed to create stack.data");
- return false;
- }
-
- size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
- if (bytes != sizeof(sp_start)) {
- printf("Failed to write sp_start data: sizeof(sp_start) %zu, written %zu\n", sizeof(sp_start),
- bytes);
- return false;
- }
-
- bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
- if (bytes != buffer.size()) {
- printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
- return false;
- }
- }
-
- return true;
-}
-
-bool CreateElfFromMemory(std::shared_ptr<unwindstack::Memory>& memory, map_info_t* info) {
- std::string cur_name;
- if (info->name.empty()) {
- cur_name = android::base::StringPrintf("anonymous_%" PRIx64, info->start);
- } else {
- cur_name = android::base::StringPrintf("%s_%" PRIx64, basename(info->name.c_str()), info->start);
- }
-
- std::vector<uint8_t> buffer(info->end - info->start);
- // If this is a mapped in file, it might not be possible to read the entire
- // map, so read all that is readable.
- size_t bytes = memory->Read(info->start, buffer.data(), buffer.size());
- if (bytes == 0) {
- printf("Cannot read data from address %" PRIx64 " length %zu\n", info->start, buffer.size());
- return false;
- }
-
- std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
- if (output == nullptr) {
- perror((std::string("Cannot create ") + cur_name).c_str());
- return false;
- }
-
- size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
- if (bytes_written != bytes) {
- printf("Failed to write all data to file: bytes read %zu, written %zu\n", bytes, bytes_written);
- return false;
- }
-
- // Replace the name with the new name.
- info->name = cur_name;
-
- return true;
-}
-
-bool CopyElfFromFile(map_info_t* info, bool* file_copied) {
- std::string cur_name = basename(info->name.c_str());
- if (*file_copied) {
- info->name = cur_name;
- return true;
- }
-
- std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(info->name.c_str(), "r"), &fclose);
- if (fp == nullptr) {
- perror((std::string("Cannot open ") + info->name).c_str());
- return false;
- }
-
- std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
- if (output == nullptr) {
- perror((std::string("Cannot create file " + cur_name)).c_str());
- return false;
- }
- std::vector<uint8_t> buffer(10000);
- size_t bytes;
- while ((bytes = fread(buffer.data(), 1, buffer.size(), fp.get())) > 0) {
- size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
- if (bytes_written != bytes) {
- printf("Bytes written doesn't match bytes read: read %zu, written %zu\n", bytes,
- bytes_written);
- return false;
- }
- }
-
- // Replace the name with the new name.
- info->name = cur_name;
-
- return true;
-}
-
-map_info_t* FillInAndGetMapInfo(std::unordered_map<uint64_t, map_info_t>& maps_by_start,
- unwindstack::MapInfo* map_info) {
- auto info = &maps_by_start[map_info->start];
- info->start = map_info->start;
- info->end = map_info->end;
- info->offset = map_info->offset;
- info->name = map_info->name;
- info->flags = map_info->flags;
-
- return info;
-}
-
-void SaveMapInformation(std::shared_ptr<unwindstack::Memory>& process_memory, map_info_t* info,
- bool* file_copied) {
- if (CopyElfFromFile(info, file_copied)) {
- return;
- }
- *file_copied = false;
-
- // Try to create the elf from memory, this will handle cases where
- // the data only exists in memory such as vdso data on x86.
- if (CreateElfFromMemory(process_memory, info)) {
- return;
- }
-
- printf("Cannot save memory or file for map ");
- if (!info->name.empty()) {
- printf("%s\n", info->name.c_str());
- } else {
- printf("anonymous:%" PRIx64 "\n", info->start);
- }
-}
-
-int SaveData(pid_t pid) {
- unwindstack::Regs* regs = unwindstack::Regs::RemoteGet(pid);
- if (regs == nullptr) {
- printf("Unable to get remote reg data.\n");
- return 1;
- }
-
- // Save the current state of the registers.
- if (!SaveRegs(regs)) {
- return 1;
- }
-
- // 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(regs->Arch())) {
- printf("Unable to init unwinder object.\n");
- return 1;
- }
- unwinder.SetRegs(regs);
- uint64_t sp = regs->sp();
- unwinder.Unwind();
-
- std::unordered_map<uint64_t, map_info_t> maps_by_start;
- std::vector<std::pair<uint64_t, uint64_t>> stacks;
- unwindstack::Maps* maps = unwinder.GetMaps();
- uint64_t sp_map_start = 0;
- unwindstack::MapInfo* map_info = maps->Find(sp);
- if (map_info != nullptr) {
- stacks.emplace_back(std::make_pair(sp, map_info->end));
- sp_map_start = map_info->start;
- }
-
- for (const auto& frame : unwinder.frames()) {
- map_info = maps->Find(frame.sp);
- if (map_info != nullptr && sp_map_start != map_info->start) {
- stacks.emplace_back(std::make_pair(frame.sp, map_info->end));
- sp_map_start = map_info->start;
- }
-
- if (maps_by_start.count(frame.map_start) == 0) {
- map_info = maps->Find(frame.map_start);
- if (map_info == nullptr) {
- continue;
- }
-
- auto info = FillInAndGetMapInfo(maps_by_start, map_info);
- bool file_copied = false;
- SaveMapInformation(unwinder.GetProcessMemory(), info, &file_copied);
-
- // If you are using a a linker that creates two maps (one read-only, one
- // read-executable), it's necessary to capture the previous map
- // information if needed.
- unwindstack::MapInfo* prev_map = map_info->prev_map;
- if (prev_map != nullptr && map_info->offset != 0 && prev_map->offset == 0 &&
- prev_map->flags == PROT_READ && map_info->name == prev_map->name &&
- maps_by_start.count(prev_map->start) == 0) {
- info = FillInAndGetMapInfo(maps_by_start, prev_map);
- SaveMapInformation(unwinder.GetProcessMemory(), info, &file_copied);
- }
- }
- }
-
- for (size_t i = 0; i < unwinder.NumFrames(); i++) {
- printf("%s\n", unwinder.FormatFrame(i).c_str());
- }
-
- if (!SaveStack(pid, stacks)) {
- return 1;
- }
-
- std::vector<std::pair<uint64_t, map_info_t>> sorted_maps(maps_by_start.begin(),
- maps_by_start.end());
- std::sort(sorted_maps.begin(), sorted_maps.end(),
- [](auto& a, auto& b) { return a.first < b.first; });
-
- std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("maps.txt", "w+"), &fclose);
- if (fp == nullptr) {
- perror("Failed to create maps.txt");
- return false;
- }
-
- for (auto& element : sorted_maps) {
- char perms[5] = {"---p"};
- map_info_t& map = element.second;
- if (map.flags & PROT_READ) {
- perms[0] = 'r';
- }
- if (map.flags & PROT_WRITE) {
- perms[1] = 'w';
- }
- if (map.flags & PROT_EXEC) {
- perms[2] = 'x';
- }
- fprintf(fp.get(), "%" PRIx64 "-%" PRIx64 " %s %" PRIx64 " 00:00 0", map.start, map.end, perms,
- map.offset);
- if (!map.name.empty()) {
- fprintf(fp.get(), " %s", map.name.c_str());
- }
- fprintf(fp.get(), "\n");
- }
-
- return 0;
-}
-
-int main(int argc, char** argv) {
- if (argc != 2) {
- printf("Usage: unwind_for_offline <PID>\n");
- return 1;
- }
-
- pid_t pid = atoi(argv[1]);
- if (!Attach(pid)) {
- printf("Failed to attach to pid %d: %s\n", pid, strerror(errno));
- return 1;
- }
-
- int return_code = SaveData(pid);
-
- ptrace(PTRACE_DETACH, pid, 0, 0);
-
- return return_code;
-}
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
deleted file mode 100644
index a5002f2..0000000
--- a/libunwindstack/tools/unwind_info.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/DwarfStructs.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/Memory.h>
-
-#include "ArmExidx.h"
-#include "ElfInterfaceArm.h"
-
-namespace unwindstack {
-
-void DumpArm(Elf* elf, ElfInterfaceArm* interface) {
- if (interface == nullptr) {
- printf("No ARM Unwind Information.\n\n");
- return;
- }
-
- printf("ARM Unwind Information:\n");
- uint64_t load_bias = elf->GetLoadBias();
- for (const auto& entry : interface->pt_loads()) {
- printf(" PC Range 0x%" PRIx64 " - 0x%" PRIx64 "\n", entry.second.offset + load_bias,
- entry.second.offset + entry.second.table_size + load_bias);
- for (auto pc : *interface) {
- std::string name;
- printf(" PC 0x%" PRIx64, pc + load_bias);
- uint64_t func_offset;
- if (elf->GetFunctionName(pc + load_bias, &name, &func_offset) && !name.empty()) {
- printf(" <%s>", name.c_str());
- }
- printf("\n");
- uint64_t entry;
- if (!interface->FindEntry(pc, &entry)) {
- printf(" Cannot find entry for address.\n");
- continue;
- }
- ArmExidx arm(nullptr, interface->memory(), nullptr);
- arm.set_log(ARM_LOG_FULL);
- arm.set_log_skip_execution(true);
- arm.set_log_indent(2);
- if (!arm.ExtractEntryData(entry)) {
- if (arm.status() != ARM_STATUS_NO_UNWIND) {
- printf(" Error trying to extract data.\n");
- }
- continue;
- }
- if (arm.data()->size() > 0) {
- if (!arm.Eval() && arm.status() != ARM_STATUS_NO_UNWIND) {
- printf(" Error trying to evaluate dwarf data.\n");
- }
- }
- }
- }
- printf("\n");
-}
-
-void DumpDwarfSection(Elf* elf, DwarfSection* section, uint64_t) {
- for (const DwarfFde* fde : *section) {
- // Sometimes there are entries that have empty length, skip those since
- // they don't contain any interesting information.
- if (fde == nullptr || fde->pc_start == fde->pc_end) {
- continue;
- }
- printf("\n PC 0x%" PRIx64 "-0x%" PRIx64, fde->pc_start, fde->pc_end);
- std::string name;
- uint64_t func_offset;
- if (elf->GetFunctionName(fde->pc_start, &name, &func_offset) && !name.empty()) {
- printf(" <%s>", name.c_str());
- }
- printf("\n");
- if (!section->Log(2, UINT64_MAX, fde, elf->arch())) {
- printf("Failed to process cfa information for entry at 0x%" PRIx64 "\n", fde->pc_start);
- }
- }
-}
-
-int GetElfInfo(const char* file, uint64_t offset) {
- // Send all log messages to stdout.
- log_to_stdout(true);
-
- Elf elf(Memory::CreateFileMemory(file, offset).release());
- if (!elf.Init() || !elf.valid()) {
- printf("%s is not a valid elf file.\n", file);
- return 1;
- }
-
- std::string soname(elf.GetSoname());
- if (!soname.empty()) {
- printf("Soname: %s\n", soname.c_str());
- }
-
- std::string build_id = elf.GetBuildID();
- if (!build_id.empty()) {
- printf("Build ID: ");
- for (size_t i = 0; i < build_id.size(); ++i) {
- printf("%02hhx", build_id[i]);
- }
- printf("\n");
- }
-
- ElfInterface* interface = elf.interface();
- if (elf.machine_type() == EM_ARM) {
- DumpArm(&elf, reinterpret_cast<ElfInterfaceArm*>(interface));
- printf("\n");
- }
-
- if (interface->eh_frame() != nullptr) {
- printf("eh_frame information:\n");
- DumpDwarfSection(&elf, interface->eh_frame(), elf.GetLoadBias());
- printf("\n");
- } else {
- printf("\nno eh_frame information\n");
- }
-
- if (interface->debug_frame() != nullptr) {
- printf("\ndebug_frame information:\n");
- DumpDwarfSection(&elf, interface->debug_frame(), elf.GetLoadBias());
- printf("\n");
- } else {
- printf("\nno debug_frame information\n");
- }
-
- // If there is a gnu_debugdata interface, dump the information for that.
- ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface();
- if (gnu_debugdata_interface != nullptr) {
- if (gnu_debugdata_interface->eh_frame() != nullptr) {
- printf("\ngnu_debugdata (eh_frame):\n");
- DumpDwarfSection(&elf, gnu_debugdata_interface->eh_frame(), 0);
- printf("\n");
- }
- if (gnu_debugdata_interface->debug_frame() != nullptr) {
- printf("\ngnu_debugdata (debug_frame):\n");
- DumpDwarfSection(&elf, gnu_debugdata_interface->debug_frame(), 0);
- printf("\n");
- }
- } else {
- printf("\nno valid gnu_debugdata information\n");
- }
-
- return 0;
-}
-
-} // namespace unwindstack
-
-int main(int argc, char** argv) {
- if (argc != 2 && argc != 3) {
- printf("Usage: unwind_info ELF_FILE [OFFSET]\n");
- printf(" ELF_FILE\n");
- printf(" The path to an elf file.\n");
- printf(" OFFSET\n");
- printf(" Use the offset into the ELF file as the beginning of the elf.\n");
- return 1;
- }
-
- struct stat st;
- if (stat(argv[1], &st) == -1) {
- printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
- return 1;
- }
- if (!S_ISREG(st.st_mode)) {
- printf("%s is not a regular file.\n", argv[1]);
- return 1;
- }
-
- uint64_t offset = 0;
- if (argc == 3) {
- char* end;
- offset = strtoull(argv[2], &end, 16);
- if (*end != '\0') {
- printf("Malformed OFFSET value: %s\n", argv[2]);
- return 1;
- }
- }
-
- return unwindstack::GetElfInfo(argv[1], offset);
-}
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
deleted file mode 100644
index 68e0273..0000000
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * 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 <elf.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <unwindstack/DwarfLocation.h>
-#include <unwindstack/DwarfMemory.h>
-#include <unwindstack/DwarfSection.h>
-#include <unwindstack/DwarfStructs.h>
-#include <unwindstack/Elf.h>
-#include <unwindstack/ElfInterface.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/Memory.h>
-
-#include "ArmExidx.h"
-#include "DwarfOp.h"
-#include "ElfInterfaceArm.h"
-
-namespace unwindstack {
-
-void PrintSignedValue(int64_t value) {
- if (value < 0) {
- printf("- %" PRId64, -value);
- } else if (value > 0) {
- printf("+ %" PRId64, value);
- }
-}
-
-void PrintExpression(Memory* memory, uint8_t class_type, uint64_t end, uint64_t length) {
- std::vector<std::string> lines;
- DwarfMemory dwarf_memory(memory);
- if (class_type == ELFCLASS32) {
- DwarfOp<uint32_t> op(&dwarf_memory, nullptr);
- op.GetLogInfo(end - length, end, &lines);
- } else {
- DwarfOp<uint64_t> op(&dwarf_memory, nullptr);
- op.GetLogInfo(end - length, end, &lines);
- }
- for (auto& line : lines) {
- printf(" %s\n", line.c_str());
- }
-}
-
-void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type,
- ArchEnum arch) {
- const DwarfFde* fde = section->GetFdeFromPc(pc);
- if (fde == nullptr) {
- printf(" No fde found.\n");
- return;
- }
-
- dwarf_loc_regs_t regs;
- if (!section->GetCfaLocationInfo(pc, fde, ®s, arch)) {
- printf(" Cannot get location information.\n");
- return;
- }
-
- std::vector<std::pair<uint32_t, DwarfLocation>> loc_regs;
- for (auto& loc : regs) {
- loc_regs.push_back(loc);
- }
- std::sort(loc_regs.begin(), loc_regs.end(), [](auto a, auto b) {
- if (a.first == CFA_REG) {
- return true;
- } else if (b.first == CFA_REG) {
- return false;
- }
- return a.first < b.first;
- });
-
- for (auto& entry : loc_regs) {
- const DwarfLocation* loc = &entry.second;
- if (entry.first == CFA_REG) {
- printf(" cfa = ");
- } else {
- printf(" r%d = ", entry.first);
- }
- switch (loc->type) {
- case DWARF_LOCATION_OFFSET:
- printf("[cfa ");
- PrintSignedValue(loc->values[0]);
- printf("]\n");
- break;
-
- case DWARF_LOCATION_VAL_OFFSET:
- printf("cfa ");
- PrintSignedValue(loc->values[0]);
- printf("\n");
- break;
-
- case DWARF_LOCATION_REGISTER:
- printf("r%" PRId64 " ", loc->values[0]);
- PrintSignedValue(loc->values[1]);
- printf("\n");
- break;
-
- case DWARF_LOCATION_EXPRESSION: {
- printf("EXPRESSION\n");
- PrintExpression(memory, class_type, loc->values[1], loc->values[0]);
- break;
- }
-
- case DWARF_LOCATION_VAL_EXPRESSION: {
- printf("VAL EXPRESSION\n");
- PrintExpression(memory, class_type, loc->values[1], loc->values[0]);
- break;
- }
-
- case DWARF_LOCATION_PSEUDO_REGISTER: {
- printf("%" PRId64 " (pseudo)\n", loc->values[0]);
- break;
- }
-
- case DWARF_LOCATION_UNDEFINED:
- printf("undefine\n");
- break;
-
- case DWARF_LOCATION_INVALID:
- printf("INVALID\n");
- break;
- }
- }
-}
-
-void PrintArmRegInformation(ElfInterfaceArm* interface, uint64_t pc) {
- printf("\nArm exidx:\n");
- uint64_t entry_offset;
- if (!interface->FindEntry(pc, &entry_offset)) {
- return;
- }
-
- ArmExidx arm(nullptr, interface->memory(), nullptr);
-
- log_to_stdout(true);
- arm.set_log(ARM_LOG_BY_REG);
- arm.set_log_skip_execution(true);
- arm.set_log_indent(1);
- if (!arm.ExtractEntryData(entry_offset)) {
- if (arm.status() != ARM_STATUS_NO_UNWIND) {
- printf(" Error trying to extract data.\n");
- }
- return;
- }
- if (arm.data()->size() != 0 && arm.Eval()) {
- arm.LogByReg();
- } else {
- printf(" Error tring to evaluate exidx data.\n");
- }
-}
-
-int GetInfo(const char* file, uint64_t offset, uint64_t pc) {
- Elf elf(Memory::CreateFileMemory(file, offset).release());
- if (!elf.Init() || !elf.valid()) {
- printf("%s is not a valid elf file.\n", file);
- return 1;
- }
-
- ElfInterface* interface = elf.interface();
- uint64_t load_bias = elf.GetLoadBias();
- if (pc < load_bias) {
- printf("PC is less than load bias.\n");
- return 1;
- }
-
- std::string soname(elf.GetSoname());
- if (!soname.empty()) {
- printf("Soname: %s\n\n", soname.c_str());
- }
-
- printf("PC 0x%" PRIx64, pc);
- std::string function_name;
- uint64_t function_offset;
- if (elf.GetFunctionName(pc, &function_name, &function_offset)) {
- printf(" (%s)", function_name.c_str());
- }
- printf(":\n");
-
- if (elf.machine_type() == EM_ARM) {
- PrintArmRegInformation(reinterpret_cast<ElfInterfaceArm*>(interface), pc - load_bias);
- }
-
- DwarfSection* section = interface->eh_frame();
- if (section != nullptr) {
- printf("\neh_frame:\n");
- PrintRegInformation(section, elf.memory(), pc, elf.class_type(), elf.arch());
- } else {
- printf("\nno eh_frame information\n");
- }
-
- section = interface->debug_frame();
- if (section != nullptr) {
- printf("\ndebug_frame:\n");
- PrintRegInformation(section, elf.memory(), pc, elf.class_type(), elf.arch());
- printf("\n");
- } else {
- printf("\nno debug_frame information\n");
- }
-
- // If there is a gnu_debugdata interface, dump the information for that.
- ElfInterface* gnu_debugdata_interface = elf.gnu_debugdata_interface();
- if (gnu_debugdata_interface != nullptr) {
- section = gnu_debugdata_interface->eh_frame();
- if (section != nullptr) {
- printf("\ngnu_debugdata (eh_frame):\n");
- PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type(),
- elf.arch());
- printf("\n");
- } else {
- printf("\nno gnu_debugdata (eh_frame)\n");
- }
-
- section = gnu_debugdata_interface->debug_frame();
- if (section != nullptr) {
- printf("\ngnu_debugdata (debug_frame):\n");
- PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type(),
- elf.arch());
- printf("\n");
- } else {
- printf("\nno gnu_debugdata (debug_frame)\n");
- }
- } else {
- printf("\nno valid gnu_debugdata information\n");
- }
-
- return 0;
-}
-
-} // namespace unwindstack
-
-int main(int argc, char** argv) {
- if (argc != 3 && argc != 4) {
- printf("Usage: unwind_reg_info ELF_FILE PC [OFFSET]\n");
- printf(" ELF_FILE\n");
- printf(" The path to an elf file.\n");
- printf(" PC\n");
- printf(" The pc for which the register information should be obtained.\n");
- printf(" OFFSET\n");
- printf(" Use the offset into the ELF file as the beginning of the elf.\n");
- return 1;
- }
-
- struct stat st;
- if (stat(argv[1], &st) == -1) {
- printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
- return 1;
- }
- if (!S_ISREG(st.st_mode)) {
- printf("%s is not a regular file.\n", argv[1]);
- return 1;
- }
-
- uint64_t pc = 0;
- char* end;
- pc = strtoull(argv[2], &end, 16);
- if (*end != '\0') {
- printf("Malformed OFFSET value: %s\n", argv[2]);
- return 1;
- }
-
- uint64_t offset = 0;
- if (argc == 4) {
- char* end;
- offset = strtoull(argv[3], &end, 16);
- if (*end != '\0') {
- printf("Malformed OFFSET value: %s\n", argv[3]);
- return 1;
- }
- }
-
- return unwindstack::GetInfo(argv[1], offset, pc);
-}
diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp
deleted file mode 100644
index 8df2284..0000000
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <elf.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <unwindstack/Elf.h>
-#include <unwindstack/Log.h>
-#include <unwindstack/Memory.h>
-
-int main(int argc, char** argv) {
- if (argc != 2 && argc != 3) {
- printf("Usage: unwind_symbols <ELF_FILE> [<FUNC_ADDRESS>]\n");
- printf(" Dump all function symbols in ELF_FILE. If FUNC_ADDRESS is\n");
- printf(" specified, then get the function at that address.\n");
- printf(" FUNC_ADDRESS must be a hex number.\n");
- return 1;
- }
-
- struct stat st;
- if (stat(argv[1], &st) == -1) {
- printf("Cannot stat %s: %s\n", argv[1], strerror(errno));
- return 1;
- }
- if (!S_ISREG(st.st_mode)) {
- printf("%s is not a regular file.\n", argv[1]);
- return 1;
- }
-
- uint64_t func_addr;
- if (argc == 3) {
- char* name;
- func_addr = strtoull(argv[2], &name, 16);
- if (*name != '\0') {
- printf("%s is not a hex number.\n", argv[2]);
- return 1;
- }
- }
-
- // Send all log messages to stdout.
- unwindstack::log_to_stdout(true);
-
- unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(argv[1], 0).release());
- if (!elf.Init() || !elf.valid()) {
- printf("%s is not a valid elf file.\n", argv[1]);
- return 1;
- }
-
- std::string soname(elf.GetSoname());
- if (!soname.empty()) {
- printf("Soname: %s\n\n", soname.c_str());
- }
-
- switch (elf.machine_type()) {
- case EM_ARM:
- printf("ABI: arm\n");
- break;
- case EM_AARCH64:
- printf("ABI: arm64\n");
- break;
- case EM_386:
- printf("ABI: x86\n");
- break;
- case EM_X86_64:
- printf("ABI: x86_64\n");
- break;
- default:
- printf("ABI: unknown\n");
- return 1;
- }
-
- std::string name;
- if (argc == 3) {
- std::string cur_name;
- uint64_t func_offset;
- if (!elf.GetFunctionName(func_addr, &cur_name, &func_offset)) {
- printf("No known function at 0x%" PRIx64 "\n", func_addr);
- return 1;
- }
- printf("<0x%" PRIx64 ">", func_addr - func_offset);
- if (func_offset != 0) {
- printf("+%" PRId64, func_offset);
- }
- printf(": %s\n", cur_name.c_str());
- return 0;
- }
-
- // This is a crude way to get the symbols in order.
- for (const auto& entry : elf.interface()->pt_loads()) {
- uint64_t start = entry.second.offset;
- uint64_t end = entry.second.table_size;
- for (uint64_t addr = start; addr < end; addr += 4) {
- std::string cur_name;
- uint64_t func_offset;
- if (elf.GetFunctionName(addr, &cur_name, &func_offset)) {
- if (cur_name != name) {
- printf("<0x%" PRIx64 "> Function: %s\n", addr - func_offset, cur_name.c_str());
- }
- name = cur_name;
- }
- }
- }
-
- return 0;
-}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index 9c012a9..dd9fea0 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -132,7 +132,6 @@
"JenkinsHash.cpp",
"NativeHandle.cpp",
"Printer.cpp",
- "PropertyMap.cpp",
"RefBase.cpp",
"SharedBuffer.cpp",
"StopWatch.cpp",
@@ -270,18 +269,6 @@
}
cc_fuzz {
- name: "libutils_fuzz_propertymap",
- defaults: ["libutils_fuzz_defaults"],
- srcs: ["PropertyMap_fuzz.cpp"],
-}
-
-cc_fuzz {
- name: "libutils_fuzz_rwlock",
- defaults: ["libutils_fuzz_defaults"],
- srcs: ["RWLock_fuzz.cpp"],
-}
-
-cc_fuzz {
name: "libutils_fuzz_refbase",
defaults: ["libutils_fuzz_defaults"],
srcs: ["RefBase_fuzz.cpp"],
diff --git a/libutils/FuzzFormatTypes.h b/libutils/FuzzFormatTypes.h
new file mode 100644
index 0000000..aa9e503
--- /dev/null
+++ b/libutils/FuzzFormatTypes.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#pragma once
+#include <string>
+
+static const std::string kFormatChars = std::string("duoxXfFeEgGaAcsp");
+static constexpr int32_t kMaxFormatFlagValue = INT16_MAX;
+enum FormatChar : uint8_t {
+ SIGNED_DECIMAL = 0,
+ UNSIGNED_DECIMAL = 1,
+ UNSIGNED_OCTAL = 2,
+ UNSIGNED_HEX_LOWER = 3,
+ UNSIGNED_HEX_UPPER = 4,
+ // Uppercase/lowercase floating point impacts 'inf', 'infinity', and 'nan'
+ FLOAT_LOWER = 5,
+ FLOAT_UPPER = 6,
+ // Upper/lower impacts the "e" in exponents.
+ EXPONENT_LOWER = 7,
+ EXPONENT_UPPER = 8,
+ // %g will use %e or %f, whichever is shortest
+ SHORT_EXP_LOWER = 9,
+ // %G will use %E or %F, whichever is shortest
+ SHORT_EXP_UPPER = 10,
+ HEX_FLOAT_LOWER = 11,
+ HEX_FLOAT_UPPER = 12,
+ CHAR = 13,
+ STRING = 14,
+ POINTER = 15,
+ // Used by libfuzzer
+ kMaxValue = POINTER
+};
+
+bool canApplyFlag(FormatChar formatChar, char modifier) {
+ if (modifier == '#') {
+ return formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER;
+ } else if (modifier == '.') {
+ return formatChar == SIGNED_DECIMAL || formatChar == UNSIGNED_DECIMAL ||
+ formatChar == UNSIGNED_OCTAL || formatChar == UNSIGNED_HEX_LOWER ||
+ formatChar == UNSIGNED_HEX_UPPER || formatChar == FLOAT_LOWER ||
+ formatChar == FLOAT_UPPER || formatChar == SHORT_EXP_LOWER ||
+ formatChar == SHORT_EXP_UPPER || formatChar == STRING;
+ }
+ return true;
+}
diff --git a/libutils/PropertyMap.cpp b/libutils/PropertyMap.cpp
deleted file mode 100644
index f00272a..0000000
--- a/libutils/PropertyMap.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "PropertyMap"
-
-#include <utils/PropertyMap.h>
-
-// Enables debug output for the parser.
-#define DEBUG_PARSER 0
-
-// Enables debug output for parser performance.
-#define DEBUG_PARSER_PERFORMANCE 0
-
-
-namespace android {
-
-static const char* WHITESPACE = " \t\r";
-static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r=";
-
-
-// --- PropertyMap ---
-
-PropertyMap::PropertyMap() {
-}
-
-PropertyMap::~PropertyMap() {
-}
-
-void PropertyMap::clear() {
- mProperties.clear();
-}
-
-void PropertyMap::addProperty(const String8& key, const String8& value) {
- mProperties.add(key, value);
-}
-
-bool PropertyMap::hasProperty(const String8& key) const {
- return mProperties.indexOfKey(key) >= 0;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const {
- ssize_t index = mProperties.indexOfKey(key);
- if (index < 0) {
- return false;
- }
-
- outValue = mProperties.valueAt(index);
- return true;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const {
- int32_t intValue;
- if (!tryGetProperty(key, intValue)) {
- return false;
- }
-
- outValue = intValue;
- return true;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
- String8 stringValue;
- if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
- }
-
- char* end;
- int value = strtol(stringValue.string(), & end, 10);
- if (*end != '\0') {
- ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
- String8 stringValue;
- if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
- }
-
- char* end;
- float value = strtof(stringValue.string(), & end);
- if (*end != '\0') {
- ALOGW("Property key '%s' has invalid value '%s'. Expected a float.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-void PropertyMap::addAll(const PropertyMap* map) {
- for (size_t i = 0; i < map->mProperties.size(); i++) {
- mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i));
- }
-}
-
-status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
- *outMap = nullptr;
-
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);
- if (status) {
- ALOGE("Error %d opening property file %s.", status, filename.string());
- } else {
- PropertyMap* map = new PropertyMap();
- if (!map) {
- ALOGE("Error allocating property map.");
- status = NO_MEMORY;
- } else {
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
-#endif
- Parser parser(map, tokenizer);
- status = parser.parse();
-#if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed property file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
-#endif
- if (status) {
- delete map;
- } else {
- *outMap = map;
- }
- }
- delete tokenizer;
- }
- return status;
-}
-
-
-// --- PropertyMap::Parser ---
-
-PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) :
- mMap(map), mTokenizer(tokenizer) {
-}
-
-PropertyMap::Parser::~Parser() {
-}
-
-status_t PropertyMap::Parser::parse() {
- while (!mTokenizer->isEof()) {
-#if DEBUG_PARSER
- ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
-#endif
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
- String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
- if (keyToken.isEmpty()) {
- ALOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- if (mTokenizer->nextChar() != '=') {
- ALOGE("%s: Expected '=' between property key and value.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
-
- String8 valueToken = mTokenizer->nextToken(WHITESPACE);
- if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) {
- ALOGE("%s: Found reserved character '\\' or '\"' in property value.",
- mTokenizer->getLocation().string());
- return BAD_VALUE;
- }
-
- mTokenizer->skipDelimiters(WHITESPACE);
- if (!mTokenizer->isEol()) {
- ALOGE("%s: Expected end of line, got '%s'.",
- mTokenizer->getLocation().string(),
- mTokenizer->peekRemainderOfLine().string());
- return BAD_VALUE;
- }
-
- if (mMap->hasProperty(keyToken)) {
- ALOGE("%s: Duplicate property value for key '%s'.",
- mTokenizer->getLocation().string(), keyToken.string());
- return BAD_VALUE;
- }
-
- mMap->addProperty(keyToken, valueToken);
- }
-
- mTokenizer->nextLine();
- }
- return OK;
-}
-
-} // namespace android
diff --git a/libutils/PropertyMap_fuzz.cpp b/libutils/PropertyMap_fuzz.cpp
deleted file mode 100755
index fd50729..0000000
--- a/libutils/PropertyMap_fuzz.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2020 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/file.h"
-#include "fuzzer/FuzzedDataProvider.h"
-#include "utils/PropertyMap.h"
-#include "utils/String8.h"
-
-static constexpr int MAX_FILE_SIZE = 256;
-static constexpr int MAX_STR_LEN = 2048;
-static constexpr int MAX_OPERATIONS = 1000;
-
-static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap)>>
- operations = {
- [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void {
- propertyMap.getProperties();
- },
- [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void {
- propertyMap.clear();
- },
- [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
- std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
- android::String8 key = android::String8(keyStr.c_str());
- propertyMap.hasProperty(key);
- },
- [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
- std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
- android::String8 key = android::String8(keyStr.c_str());
- android::String8 out;
- propertyMap.tryGetProperty(key, out);
- },
- [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
- TemporaryFile tf;
- // Generate file contents
- std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE);
- // If we have string contents, dump them into the file.
- // Otherwise, just leave it as an empty file.
- if (contents.length() > 0) {
- const char* bytes = contents.c_str();
- android::base::WriteStringToFd(bytes, tf.fd);
- }
- android::PropertyMap* mapPtr = &propertyMap;
- android::PropertyMap::load(android::String8(tf.path), &mapPtr);
- },
- [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
- std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
- std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
- android::String8 key = android::String8(keyStr.c_str());
- android::String8 val = android::String8(valStr.c_str());
- propertyMap.addProperty(key, val);
- },
-};
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider dataProvider(data, size);
- android::PropertyMap proprtyMap = android::PropertyMap();
-
- int opsRun = 0;
- while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
- uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
- operations[op](&dataProvider, proprtyMap);
- }
- return 0;
-}
diff --git a/libutils/RWLock_fuzz.cpp b/libutils/RWLock_fuzz.cpp
deleted file mode 100755
index e075905..0000000
--- a/libutils/RWLock_fuzz.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2020 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 <functional>
-
-#include "fuzzer/FuzzedDataProvider.h"
-#include "utils/RWLock.h"
-
-static constexpr int MAX_OPERATIONS = 100;
-static constexpr int MAX_NAME_LEN = 2048;
-
-static const std::vector<std::function<void(android::RWLock*)>> operations = {
- [](android::RWLock* lock) -> void {
- // This might return a non-zero value if already locked
- // Either way we are definitely locked now.
- lock->tryWriteLock();
- },
- [](android::RWLock* lock) -> void { lock->tryReadLock(); },
- [](android::RWLock* lock) -> void { lock->unlock(); },
-};
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider dataProvider(data, size);
- std::string nameStr = dataProvider.ConsumeRandomLengthString(MAX_NAME_LEN);
- int type = dataProvider.ConsumeIntegral<int>();
- android::RWLock rwLock = android::RWLock(type, nameStr.c_str());
- std::vector<uint8_t> opsToRun = dataProvider.ConsumeRemainingBytes<uint8_t>();
- int opsRun = 0;
- for (auto it : opsToRun) {
- if (opsRun++ >= MAX_OPERATIONS) {
- break;
- }
- it = it % operations.size();
- operations[it](&rwLock);
- }
- rwLock.unlock();
- return 0;
-}
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index d514f29..70bf5a0 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -441,7 +441,7 @@
mString = getEmptyString();
return OK;
}
- if ((begin+len) > N) len = N-begin;
+ if (len > N || len > N - begin) len = N - begin;
if (begin == 0 && len == N) {
return OK;
}
diff --git a/libutils/String8.cpp b/libutils/String8.cpp
index c837891..3dc2026 100644
--- a/libutils/String8.cpp
+++ b/libutils/String8.cpp
@@ -309,8 +309,14 @@
n = vsnprintf(nullptr, 0, fmt, tmp_args);
va_end(tmp_args);
- if (n != 0) {
+ if (n < 0) return UNKNOWN_ERROR;
+
+ if (n > 0) {
size_t oldLength = length();
+ if ((size_t)n > SIZE_MAX - 1 ||
+ oldLength > SIZE_MAX - (size_t)n - 1) {
+ return NO_MEMORY;
+ }
char* buf = lockBuffer(oldLength + n);
if (buf) {
vsnprintf(buf + oldLength, n + 1, fmt, args);
diff --git a/libutils/String8_fuzz.cpp b/libutils/String8_fuzz.cpp
index 2adfe98..b02683c 100644
--- a/libutils/String8_fuzz.cpp
+++ b/libutils/String8_fuzz.cpp
@@ -15,97 +15,199 @@
*/
#include <functional>
#include <iostream>
+#include <memory>
+#include "FuzzFormatTypes.h"
#include "fuzzer/FuzzedDataProvider.h"
#include "utils/String8.h"
static constexpr int MAX_STRING_BYTES = 256;
static constexpr uint8_t MAX_OPERATIONS = 50;
+// Interestingly, 2147483614 (INT32_MAX - 33) seems to be the max value that is handled for format
+// flags. Unfortunately we need to use a smaller value so we avoid consuming too much memory.
-std::vector<std::function<void(FuzzedDataProvider&, android::String8, android::String8)>>
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend);
+std::vector<std::function<void(FuzzedDataProvider*, android::String8*, android::String8*)>>
operations = {
-
// Bytes and size
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.bytes();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->bytes();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.isEmpty();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->isEmpty();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.length();
- },
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.size();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->length();
},
// Casing
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.toUpper();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->toUpper();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.toLower();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->toLower();
},
-
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.removeAll(str2.c_str());
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ str1->removeAll(str2->c_str());
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.compare(str2);
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ const android::String8& constRef(*str2);
+ str1->compare(constRef);
},
// Append and format
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.append(str2);
+ [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
+ str1->append(str2->c_str());
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.appendFormat(str1.c_str(), str2.c_str());
- },
- [](FuzzedDataProvider&, android::String8 str1, android::String8 str2) -> void {
- str1.format(str1.c_str(), str2.c_str());
- },
+ [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
+ -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
// Find operation
- [](FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8) -> void {
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8* str2) -> void {
// We need to get a value from our fuzzer here.
- int start_index = dataProvider.ConsumeIntegralInRange<int>(0, str1.size());
- str1.find(str1.c_str(), start_index);
+ int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
+ str1->find(str2->c_str(), start_index);
},
// Path handling
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getBasePath();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getBasePath();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getPathExtension();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getPathExtension();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getPathLeaf();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getPathLeaf();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.getPathDir();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->getPathDir();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- str1.convertToResPath();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ str1->convertToResPath();
},
- [](FuzzedDataProvider&, android::String8 str1, android::String8) -> void {
- android::String8 path_out_str = android::String8();
- str1.walkPath(&path_out_str);
- path_out_str.clear();
+ [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
+ std::shared_ptr<android::String8> path_out_str =
+ std::make_shared<android::String8>();
+ str1->walkPath(path_out_str.get());
+ path_out_str->clear();
},
- [](FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8) -> void {
- str1.setPathName(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8*) -> void {
+ str1->setPathName(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
},
- [](FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8) -> void {
- str1.appendPath(dataProvider.ConsumeBytesWithTerminator<char>(5).data());
+ [](FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8*) -> void {
+ str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
},
};
-void callFunc(uint8_t index, FuzzedDataProvider& dataProvider, android::String8 str1,
- android::String8 str2) {
+void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
+ FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
+
+ std::string formatString("%");
+ // Width specifier
+ if (dataProvider->ConsumeBool()) {
+ // Left pad with zeroes
+ if (dataProvider->ConsumeBool()) {
+ formatString.push_back('0');
+ }
+ // Right justify (or left justify if negative)
+ int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
+ kMaxFormatFlagValue);
+ formatString += std::to_string(justify);
+ }
+
+ // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
+ if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
+ formatString.push_back('#');
+ }
+
+ // Precision specifier
+ if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
+ formatString.push_back('.');
+ formatString +=
+ std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
+ }
+
+ formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
+
+ switch (formatType) {
+ case SIGNED_DECIMAL: {
+ int val = dataProvider->ConsumeIntegral<int>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
+ }
+ break;
+ }
+
+ case UNSIGNED_DECIMAL:
+ case UNSIGNED_OCTAL:
+ case UNSIGNED_HEX_LOWER:
+ case UNSIGNED_HEX_UPPER: {
+ // Unsigned integers for u, o, x, and X
+ uint val = dataProvider->ConsumeIntegral<uint>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case FLOAT_LOWER:
+ case FLOAT_UPPER:
+ case EXPONENT_LOWER:
+ case EXPONENT_UPPER:
+ case SHORT_EXP_LOWER:
+ case SHORT_EXP_UPPER:
+ case HEX_FLOAT_LOWER:
+ case HEX_FLOAT_UPPER: {
+ // Floating points for f, F, e, E, g, G, a, and A
+ float val = dataProvider->ConsumeFloatingPoint<float>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case CHAR: {
+ char val = dataProvider->ConsumeIntegral<char>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+
+ case STRING: {
+ std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val.c_str());
+ } else {
+ str1->format(formatString.c_str(), val.c_str());
+ }
+ break;
+ }
+ case POINTER: {
+ uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
+ if (shouldAppend) {
+ str1->appendFormat(formatString.c_str(), val);
+ } else {
+ str1->format(formatString.c_str(), val);
+ }
+ break;
+ }
+ }
+}
+
+void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
+ android::String8* str2) {
operations[index](dataProvider, str1, str2);
}
@@ -120,14 +222,12 @@
// Create UTF-8 pointers
android::String8 str_one_utf8 = android::String8(vec.data());
android::String8 str_two_utf8 = android::String8(vec_two.data());
-
// Run operations against strings
int opsRun = 0;
while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
- callFunc(op, dataProvider, str_one_utf8, str_two_utf8);
+ operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
}
-
// Just to be extra sure these can be freed, we're going to explicitly clear
// them
str_one_utf8.clear();
diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp
index 55eadb0..540dcf4 100644
--- a/libutils/Threads.cpp
+++ b/libutils/Threads.cpp
@@ -302,8 +302,8 @@
}
#if defined(__ANDROID__)
-namespace {
-int androidSetThreadPriorityInternal(pid_t tid, int pri, bool change_policy) {
+int androidSetThreadPriority(pid_t tid, int pri)
+{
int rc = 0;
int lasterr = 0;
int curr_pri = getpriority(PRIO_PROCESS, tid);
@@ -312,19 +312,17 @@
return rc;
}
- if (change_policy) {
- if (pri >= ANDROID_PRIORITY_BACKGROUND) {
- rc = SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
- } else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
- SchedPolicy policy = SP_FOREGROUND;
- // Change to the sched policy group of the process.
- get_sched_policy(getpid(), &policy);
- rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
- }
+ if (pri >= ANDROID_PRIORITY_BACKGROUND) {
+ rc = SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1;
+ } else if (curr_pri >= ANDROID_PRIORITY_BACKGROUND) {
+ SchedPolicy policy = SP_FOREGROUND;
+ // Change to the sched policy group of the process.
+ get_sched_policy(getpid(), &policy);
+ rc = SetTaskProfiles(tid, {get_sched_policy_profile_name(policy)}, true) ? 0 : -1;
+ }
- if (rc) {
- lasterr = errno;
- }
+ if (rc) {
+ lasterr = errno;
}
if (setpriority(PRIO_PROCESS, tid, pri) < 0) {
@@ -335,15 +333,6 @@
return rc;
}
-} // namespace
-
-int androidSetThreadPriority(pid_t tid, int pri) {
- return androidSetThreadPriorityInternal(tid, pri, true);
-}
-
-int androidSetThreadPriorityAndPolicy(pid_t tid, int pri, bool change_policy) {
- return androidSetThreadPriorityInternal(tid, pri, change_policy);
-}
int androidGetThreadPriority(pid_t tid) {
return getpriority(PRIO_PROCESS, tid);
diff --git a/libutils/include/utils/AndroidThreads.h b/libutils/include/utils/AndroidThreads.h
index cdb5442..a8d7851 100644
--- a/libutils/include/utils/AndroidThreads.h
+++ b/libutils/include/utils/AndroidThreads.h
@@ -78,13 +78,8 @@
// should be one of the ANDROID_PRIORITY constants. Returns INVALID_OPERATION
// if the priority set failed, else another value if just the group set failed;
// in either case errno is set. Thread ID zero means current thread.
-// This is equivalent to androidSetThreadPriorityAndPolicy(tid, prio, true);
extern int androidSetThreadPriority(pid_t tid, int prio);
-// Parameter "change_policy" indicates if sched policy should be changed. It needs
-// not be checked again if the change is done elsewhere like activity manager.
-extern int androidSetThreadPriorityAndPolicy(pid_t tid, int prio, bool change_policy);
-
// Get the current priority of a particular thread. Returns one of the
// ANDROID_PRIORITY constants or a negative result in case of error.
extern int androidGetThreadPriority(pid_t tid);
diff --git a/libutils/include/utils/PropertyMap.h b/libutils/include/utils/PropertyMap.h
deleted file mode 100644
index a9e674f..0000000
--- a/libutils/include/utils/PropertyMap.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2010 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 _UTILS_PROPERTY_MAP_H
-#define _UTILS_PROPERTY_MAP_H
-
-#include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Errors.h>
-#include <utils/Tokenizer.h>
-
-namespace android {
-
-/*
- * Provides a mechanism for passing around string-based property key / value pairs
- * and loading them from property files.
- *
- * The property files have the following simple structure:
- *
- * # Comment
- * key = value
- *
- * Keys and values are any sequence of printable ASCII characters.
- * The '=' separates the key from the value.
- * The key and value may not contain whitespace.
- *
- * The '\' character is reserved for escape sequences and is not currently supported.
- * The '"" character is reserved for quoting and is not currently supported.
- * Files that contain the '\' or '"' character will fail to parse.
- *
- * The file must not contain duplicate keys.
- *
- * TODO Support escape sequences and quoted values when needed.
- */
-class PropertyMap {
-public:
- /* Creates an empty property map. */
- PropertyMap();
- ~PropertyMap();
-
- /* Clears the property map. */
- void clear();
-
- /* Adds a property.
- * Replaces the property with the same key if it is already present.
- */
- void addProperty(const String8& key, const String8& value);
-
- /* Returns true if the property map contains the specified key. */
- bool hasProperty(const String8& key) const;
-
- /* Gets the value of a property and parses it.
- * Returns true and sets outValue if the key was found and its value was parsed successfully.
- * Otherwise returns false and does not modify outValue. (Also logs a warning.)
- */
- bool tryGetProperty(const String8& key, String8& outValue) const;
- bool tryGetProperty(const String8& key, bool& outValue) const;
- bool tryGetProperty(const String8& key, int32_t& outValue) const;
- bool tryGetProperty(const String8& key, float& outValue) const;
-
- /* Adds all values from the specified property map. */
- void addAll(const PropertyMap* map);
-
- /* Gets the underlying property map. */
- inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
-
- /* Loads a property map from a file. */
- static status_t load(const String8& filename, PropertyMap** outMap);
-
-private:
- class Parser {
- PropertyMap* mMap;
- Tokenizer* mTokenizer;
-
- public:
- Parser(PropertyMap* map, Tokenizer* tokenizer);
- ~Parser();
- status_t parse();
-
- private:
- status_t parseType();
- status_t parseKey();
- status_t parseKeyProperty();
- status_t parseModifier(const String8& token, int32_t* outMetaState);
- status_t parseCharacterLiteral(char16_t* outCharacter);
- };
-
- KeyedVector<String8, String8> mProperties;
-};
-
-} // namespace android
-
-#endif // _UTILS_PROPERTY_MAP_H
diff --git a/logcat/Android.bp b/logcat/Android.bp
deleted file mode 100644
index 61fba59..0000000
--- a/logcat/Android.bp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (C) 2006 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.
-//
-
-cc_defaults {
- name: "logcat_defaults",
-
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
- ],
- shared_libs: [
- "libbase",
- "libprocessgroup",
- ],
- static_libs: ["liblog"],
- logtags: ["event.logtags"],
-}
-
-cc_binary {
- name: "logcat",
-
- defaults: ["logcat_defaults"],
- srcs: [
- "logcat.cpp",
- ],
-}
-
-sh_binary {
- name: "logcatd",
- src: "logcatd",
-}
-
-sh_binary {
- name: "logpersist.start",
- src: "logpersist",
- init_rc: ["logcatd.rc"],
- required: ["logcatd"],
- symlinks: [
- "logpersist.stop",
- "logpersist.cat",
- ],
-}
diff --git a/logcat/MODULE_LICENSE_APACHE2 b/logcat/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/logcat/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/logcat/NOTICE b/logcat/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/logcat/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/logcat/OWNERS b/logcat/OWNERS
deleted file mode 100644
index babbe4d..0000000
--- a/logcat/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tomcherry@google.com
diff --git a/logcat/event.logtags b/logcat/event.logtags
deleted file mode 100644
index 93c3d6d..0000000
--- a/logcat/event.logtags
+++ /dev/null
@@ -1,159 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace. Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-# (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-# 5: float
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# s: Number of seconds (monotonic time)
-# Default value for data of type int/long is 2 (bytes).
-#
-# TODO: generate ".java" and ".h" files with integer constants from this file.
-
-# These are used for testing, do not modify without updating
-# tests/framework-tests/src/android/util/EventLogFunctionalTest.java.
-# system/core/liblog/tests/liblog_benchmark.cpp
-# system/core/liblog/tests/liblog_test.cpp
-42 answer (to life the universe etc|3)
-314 pi
-2718 e
-
-# "account" is the java hash of the account name
-2720 sync (id|3),(event|1|5),(source|1|5),(account|1|5)
-
-# This event is logged when the location service uploads location data.
-2740 location_controller
-# This event is logged when someone is deciding to force a garbage collection
-2741 force_gc (reason|3)
-# This event is logged on each tickle
-2742 tickle (authority|3)
-
-# contacts aggregation: time and number of contacts.
-# count is negative for query phase, positive for merge phase
-2747 contacts_aggregation (aggregation time|2|3), (count|1|1)
-
-# Device boot timings. We include monotonic clock values because the
-# intrinsic event log times are wall-clock.
-#
-# Runtime starts:
-3000 boot_progress_start (time|2|3)
-# ZygoteInit class preloading starts:
-3020 boot_progress_preload_start (time|2|3)
-# ZygoteInit class preloading ends:
-3030 boot_progress_preload_end (time|2|3)
-
-# Dalvik VM / ART
-20003 dvm_lock_sample (process|3),(main|1|5),(thread|3),(time|1|3),(file|3),(line|1|5),(ownerfile|3),(ownerline|1|5),(sample_percent|1|6)
-20004 art_hidden_api_access (access_method|1),(flags|1),(class|3),(member|3),(type_signature|3)
-
-75000 sqlite_mem_alarm_current (current|1|2)
-75001 sqlite_mem_alarm_max (max|1|2)
-75002 sqlite_mem_alarm_alloc_attempt (attempts|1|4)
-75003 sqlite_mem_released (Memory released|1|2)
-75004 sqlite_db_corrupt (Database file corrupt|3)
-
-50000 menu_item_selected (Menu type where 0 is options and 1 is context|1|5),(Menu item title|3)
-50001 menu_opened (Menu type where 0 is options and 1 is context|1|5)
-
-# HSM wifi state change
-# Hierarchical state class name (as defined in WifiStateTracker.java)
-# Logged on every state change in the hierarchical state machine
-50021 wifi_state_changed (wifi_state|3)
-# HSM wifi event
-# [31-16] Reserved for future use
-# [15 - 0] HSM event (as defined in WifiStateTracker.java)
-# Logged when an event is handled in a hierarchical state
-50022 wifi_event_handled (wifi_event|1|5)
-# Supplicant state change
-# [31-13] Reserved for future use
-# [8 - 0] Supplicant state (as defined in SupplicantState.java)
-# Logged when the supplicant switches to a new state
-50023 wifi_supplicant_state_changed (supplicant_state|1|5)
-
-# Database operation samples.
-# db: the filename of the database
-# sql: the executed query (without query args)
-# time: cpu time millis (not wall time), including lock acquisition
-# blocking_package: if this is on a main thread, the package name, otherwise ""
-# sample_percent: the percent likelihood this query was logged
-52000 db_sample (db|3),(sql|3),(time|1|3),(blocking_package|3),(sample_percent|1|6)
-
-# http request/response stats
-52001 http_stats (useragent|3),(response|2|3),(processing|2|3),(tx|1|2),(rx|1|2)
-60000 viewroot_draw (Draw time|1|3)
-60001 viewroot_layout (Layout time|1|3)
-60002 view_build_drawing_cache (View created drawing cache|1|5)
-60003 view_use_drawing_cache (View drawn using bitmap cache|1|5)
-
-# graphics timestamp
-# 60100 - 60199 reserved for surfaceflinger
-
-# audio
-# 61000 - 61199 reserved for audioserver
-
-# input
-# 62000 - 62199 reserved for inputflinger
-
-# com.android.server.policy
-# 70000 - 70199 reserved for PhoneWindowManager and other policies
-
-# aggregation service
-70200 aggregation (aggregation time|2|3)
-70201 aggregation_test (field1|1|2),(field2|1|2),(field3|1|2),(field4|1|2),(field5|1|2)
-
-# gms refuses to register this log tag, b/30156345
-70220 gms_unknown
-
-# libc failure logging
-80100 bionic_event_memcpy_buffer_overflow (uid|1)
-80105 bionic_event_strcat_buffer_overflow (uid|1)
-80110 bionic_event_memmov_buffer_overflow (uid|1)
-80115 bionic_event_strncat_buffer_overflow (uid|1)
-80120 bionic_event_strncpy_buffer_overflow (uid|1)
-80125 bionic_event_memset_buffer_overflow (uid|1)
-80130 bionic_event_strcpy_buffer_overflow (uid|1)
-
-80200 bionic_event_strcat_integer_overflow (uid|1)
-80205 bionic_event_strncat_integer_overflow (uid|1)
-
-80300 bionic_event_resolver_old_response (uid|1)
-80305 bionic_event_resolver_wrong_server (uid|1)
-80310 bionic_event_resolver_wrong_query (uid|1)
-
-# libcore failure logging
-90100 exp_det_cert_pin_failure (certs|4)
-
-# 150000 - 160000 reserved for Android Automotive builds
-
-1397638484 snet_event_log (subtag|3) (uid|1) (message|3)
-
-# for events that go to stats log buffer
-1937006964 stats_log (atom_id|1|5),(data|4)
-
-# NOTE - the range 1000000-2000000 is reserved for partners and others who
-# want to define their own log tags without conflicting with the core platform.
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
deleted file mode 100644
index 6b7e016..0000000
--- a/logcat/logcat.cpp
+++ /dev/null
@@ -1,1212 +0,0 @@
-/*
- * Copyright (C) 2006-2017 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 <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <error.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <math.h>
-#include <sched.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/ioctl.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <memory>
-#include <regex>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/parseint.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <android/log.h>
-#include <log/event_tag_map.h>
-#include <log/log_id.h>
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <private/android_logger.h>
-#include <processgroup/sched_policy.h>
-#include <system/thread_defs.h>
-
-#define DEFAULT_MAX_ROTATED_LOGS 4
-
-using android::base::Join;
-using android::base::ParseByteCount;
-using android::base::ParseUint;
-using android::base::Split;
-using android::base::StringPrintf;
-using android::base::WriteFully;
-
-class Logcat {
- public:
- int Run(int argc, char** argv);
-
- private:
- void RotateLogs();
- void ProcessBuffer(struct log_msg* buf);
- void PrintDividers(log_id_t log_id, bool print_dividers);
- void SetupOutputAndSchedulingPolicy(bool blocking);
- int SetLogFormat(const char* format_string);
-
- // Used for all options
- android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
- std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
- android_log_format_new(), &android_log_format_free};
-
- // For logging to a file and log rotation
- const char* output_file_name_ = nullptr;
- size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
- size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
- size_t out_byte_count_ = 0;
-
- // For binary log buffers
- int print_binary_ = 0;
- std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
- nullptr, &android_closeEventTagMap};
- bool has_opened_event_tag_map_ = false;
-
- // For the related --regex, --max-count, --print
- std::unique_ptr<std::regex> regex_;
- size_t max_count_ = 0; // 0 means "infinite"
- size_t print_count_ = 0;
- bool print_it_anyways_ = false;
-
- // For PrintDividers()
- log_id_t last_printed_id_ = LOG_ID_MAX;
- bool printed_start_[LOG_ID_MAX] = {};
-
- bool debug_ = false;
-};
-
-#ifndef F2FS_IOC_SET_PIN_FILE
-#define F2FS_IOCTL_MAGIC 0xf5
-#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
-#endif
-
-static int openLogFile(const char* pathname, size_t sizeKB) {
- int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP);
- if (fd < 0) {
- return fd;
- }
-
- // no need to check errors
- __u32 set = 1;
- ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
- fallocate(fd, FALLOC_FL_KEEP_SIZE, 0, (sizeKB << 10));
- return fd;
-}
-
-static void closeLogFile(const char* pathname) {
- int fd = open(pathname, O_WRONLY | O_CLOEXEC);
- if (fd == -1) {
- return;
- }
-
- // no need to check errors
- __u32 set = 0;
- ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
- close(fd);
-}
-
-void Logcat::RotateLogs() {
- // Can't rotate logs if we're not outputting to a file
- if (!output_file_name_) return;
-
- output_fd_.reset();
-
- // Compute the maximum number of digits needed to count up to
- // maxRotatedLogs in decimal. eg:
- // maxRotatedLogs == 30
- // -> log10(30) == 1.477
- // -> maxRotationCountDigits == 2
- int max_rotation_count_digits =
- max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
-
- for (int i = max_rotated_logs_; i > 0; i--) {
- std::string file1 =
- StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
-
- std::string file0;
- if (!(i - 1)) {
- file0 = output_file_name_;
- } else {
- file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
- }
-
- if (!file0.length() || !file1.length()) {
- perror("while rotating log files");
- break;
- }
-
- closeLogFile(file0.c_str());
-
- int err = rename(file0.c_str(), file1.c_str());
-
- if (err < 0 && errno != ENOENT) {
- perror("while rotating log files");
- }
- }
-
- output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
-
- if (!output_fd_.ok()) {
- error(EXIT_FAILURE, errno, "Couldn't open output file");
- }
-
- out_byte_count_ = 0;
-}
-
-void Logcat::ProcessBuffer(struct log_msg* buf) {
- int bytesWritten = 0;
- int err;
- AndroidLogEntry entry;
- char binaryMsgBuf[1024];
-
- bool is_binary =
- buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
-
- if (is_binary) {
- if (!event_tag_map_ && !has_opened_event_tag_map_) {
- event_tag_map_.reset(android_openEventTagMap(nullptr));
- has_opened_event_tag_map_ = true;
- }
- err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
- binaryMsgBuf, sizeof(binaryMsgBuf));
- // printf(">>> pri=%d len=%d msg='%s'\n",
- // entry.priority, entry.messageLen, entry.message);
- } else {
- err = android_log_processLogBuffer(&buf->entry, &entry);
- }
- if (err < 0 && !debug_) return;
-
- if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
- entry.priority)) {
- bool match = !regex_ ||
- std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
-
- print_count_ += match;
- if (match || print_it_anyways_) {
- bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
-
- if (bytesWritten < 0) {
- error(EXIT_FAILURE, 0, "Output error.");
- }
- }
- }
-
- out_byte_count_ += bytesWritten;
-
- if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
- RotateLogs();
- }
-}
-
-void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
- if (log_id == last_printed_id_ || print_binary_) {
- return;
- }
- if (!printed_start_[log_id] || print_dividers) {
- if (dprintf(output_fd_.get(), "--------- %s %s\n",
- printed_start_[log_id] ? "switch to" : "beginning of",
- android_log_id_to_name(log_id)) < 0) {
- error(EXIT_FAILURE, errno, "Output error");
- }
- }
- last_printed_id_ = log_id;
- printed_start_[log_id] = true;
-}
-
-void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
- if (!output_file_name_) return;
-
- if (blocking) {
- // Lower priority and set to batch scheduling if we are saving
- // the logs into files and taking continuous content.
- if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- fprintf(stderr, "failed to set background scheduling policy\n");
- }
-
- struct sched_param param = {};
- if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
- fprintf(stderr, "failed to set to batch scheduler\n");
- }
-
- if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
- fprintf(stderr, "failed set to priority\n");
- }
- }
-
- output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
-
- if (!output_fd_.ok()) {
- error(EXIT_FAILURE, errno, "Couldn't open output file");
- }
-
- struct stat statbuf;
- if (fstat(output_fd_.get(), &statbuf) == -1) {
- error(EXIT_FAILURE, errno, "Couldn't get output file stat");
- }
-
- if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
- error(EXIT_FAILURE, 0, "Invalid output file stat.");
- }
-
- out_byte_count_ = statbuf.st_size;
-}
-
-// clang-format off
-static void show_help() {
- const char* cmd = getprogname();
-
- fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
-
- fprintf(stderr, R"init(
-General options:
- -b, --buffer=<buffer> Request alternate ring buffer(s):
- main system radio events crash default all
- Additionally, 'kernel' for userdebug and eng builds, and
- 'security' for Device Owner installations.
- Multiple -b parameters or comma separated list of buffers are
- allowed. Buffers are interleaved.
- Default -b main,system,crash,kernel.
- -L, --last Dump logs from prior to last reboot from pstore.
- -c, --clear Clear (flush) the entire log and exit.
- if -f is specified, clear the specified file and its related rotated
- log files instead.
- if -L is specified, clear pstore log instead.
- -d Dump the log and then exit (don't block).
- --pid=<pid> Only print logs from the given pid.
- --wrap Sleep for 2 hours or when buffer about to wrap whichever
- comes first. Improves efficiency of polling by providing
- an about-to-wrap wakeup.
-
-Formatting:
- -v, --format=<format> Sets log print format verb and adverbs, where <format> is one of:
- brief help long process raw tag thread threadtime time
- Modifying adverbs can be added:
- color descriptive epoch monotonic printable uid usec UTC year zone
- Multiple -v parameters or comma separated list of format and format
- modifiers are allowed.
- -D, --dividers Print dividers between each log buffer.
- -B, --binary Output the log in binary.
-
-Outfile files:
- -f, --file=<file> Log to file instead of stdout.
- -r, --rotate-kbytes=<n> Rotate log every <n> kbytes. Requires -f option.
- -n, --rotate-count=<count> Sets max number of rotated logs to <count>, default 4.
- --id=<id> If the signature <id> for logging to file changes, then clear the
- associated files and continue.
-
-Logd control:
- These options send a control message to the logd daemon on device, print its return message if
- applicable, then exit. They are incompatible with -L, as these attributes do not apply to pstore.
- -g, --buffer-size Get the size of the ring buffers within logd.
- -G, --buffer-size=<size> Set size of a ring buffer in logd. May suffix with K or M.
- This can individually control each buffer's size with -b.
- -S, --statistics Output statistics.
- --pid can be used to provide pid specific stats.
- -p, --prune Print prune rules. Each rule is specified as UID, UID/PID or /PID. A
- '~' prefix indicates that elements matching the rule should be pruned
- with higher priority otherwise they're pruned with lower priority. All
- other pruning activity is oldest first. Special case ~! represents an
- automatic pruning for the noisiest UID as determined by the current
- statistics. Special case ~1000/! represents pruning of the worst PID
- within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
- -P, --prune='<list> ...' Set prune rules, using same format as listed above. Must be quoted.
-
-Filtering:
- -s Set default filter to silent. Equivalent to filterspec '*:S'
- -e, --regex=<expr> Only print lines where the log message matches <expr> where <expr> is
- an ECMAScript regular expression.
- -m, --max-count=<count> Quit after printing <count> lines. This is meant to be paired with
- --regex, but will work on its own.
- --print This option is only applicable when --regex is set and only useful if
- --max-count is also provided.
- With --print, logcat will print all messages even if they do not
- match the regex. Logcat will quit after printing the max-count number
- of lines that match the regex.
- -t <count> Print only the most recent <count> lines (implies -d).
- -t '<time>' Print the lines since specified time (implies -d).
- -T <count> Print only the most recent <count> lines (does not imply -d).
- -T '<time>' Print the lines since specified time (not imply -d).
- count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
- 'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format.
- --uid=<uids> Only display log messages from UIDs present in the comma separate list
- <uids>. No name look-up is performed, so UIDs must be provided as
- numeric values. This option is only useful for the 'root', 'log', and
- 'system' users since only those users can view logs from other users.
-)init");
-
- fprintf(stderr, "\nfilterspecs are a series of \n"
- " <tag>[:priority]\n\n"
- "where <tag> is a log component tag (or * for all) and priority is:\n"
- " V Verbose (default for <tag>)\n"
- " D Debug (default for '*')\n"
- " I Info\n"
- " W Warn\n"
- " E Error\n"
- " F Fatal\n"
- " S Silent (suppress all output)\n"
- "\n'*' by itself means '*:D' and <tag> by itself means <tag>:V.\n"
- "If no '*' filterspec or -s on command line, all filter defaults to '*:V'.\n"
- "eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.\n"
- "\nIf not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.\n"
- "\nIf not specified with -v on command line, format is set from ANDROID_PRINTF_LOG\n"
- "or defaults to \"threadtime\"\n\n");
-}
-
-static void show_format_help() {
- fprintf(stderr,
- "-v <format>, --format=<format> options:\n"
- " Sets log print format verb and adverbs, where <format> is:\n"
- " brief long process raw tag thread threadtime time\n"
- " and individually flagged modifying adverbs can be added:\n"
- " color descriptive epoch monotonic printable uid usec UTC year zone\n"
- "\nSingle format verbs:\n"
- " brief — Display priority/tag and PID of the process issuing the message.\n"
- " long — Display all metadata fields, separate messages with blank lines.\n"
- " process — Display PID only.\n"
- " raw — Display the raw log message, with no other metadata fields.\n"
- " tag — Display the priority/tag only.\n"
- " thread — Display priority, PID and TID of process issuing the message.\n"
- " threadtime — Display the date, invocation time, priority, tag, and the PID\n"
- " and TID of the thread issuing the message. (the default format).\n"
- " time — Display the date, invocation time, priority/tag, and PID of the\n"
- " process issuing the message.\n"
- "\nAdverb modifiers can be used in combination:\n"
- " color — Display in highlighted color to match priority. i.e. \x1B[39mVERBOSE\n"
- " \x1B[34mDEBUG \x1B[32mINFO \x1B[33mWARNING \x1B[31mERROR FATAL\x1B[0m\n"
- " descriptive — events logs only, descriptions from event-log-tags database.\n"
- " epoch — Display time as seconds since Jan 1 1970.\n"
- " monotonic — Display time as cpu seconds since last boot.\n"
- " printable — Ensure that any binary logging content is escaped.\n"
- " uid — If permitted, display the UID or Android ID of logged process.\n"
- " usec — Display time down the microsecond precision.\n"
- " UTC — Display time as UTC.\n"
- " year — Add the year to the displayed time.\n"
- " zone — Add the local timezone to the displayed time.\n"
- " \"<zone>\" — Print using this public named timezone (experimental).\n\n"
- );
-}
-// clang-format on
-
-int Logcat::SetLogFormat(const char* format_string) {
- AndroidLogPrintFormat format = android_log_formatFromString(format_string);
-
- // invalid string?
- if (format == FORMAT_OFF) return -1;
-
- return android_log_setPrintFormat(logformat_.get(), format);
-}
-
-static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
- static const char multipliers[][3] = {{""}, {"Ki"}, {"Mi"}, {"Gi"}};
- size_t i;
- for (i = 0;
- (i < sizeof(multipliers) / sizeof(multipliers[0])) && (value >= 1024);
- value /= 1024, ++i)
- ;
- return std::make_pair(value, multipliers[i]);
-}
-
-static char* parseTime(log_time& t, const char* cp) {
- char* ep = t.strptime(cp, "%m-%d %H:%M:%S.%q");
- if (ep) return ep;
- ep = t.strptime(cp, "%Y-%m-%d %H:%M:%S.%q");
- if (ep) return ep;
- return t.strptime(cp, "%s.%q");
-}
-
-// Find last logged line in <outputFileName>, or <outputFileName>.1
-static log_time lastLogTime(const char* outputFileName) {
- log_time retval(log_time::EPOCH);
- if (!outputFileName) return retval;
-
- std::string directory;
- const char* file = strrchr(outputFileName, '/');
- if (!file) {
- directory = ".";
- file = outputFileName;
- } else {
- directory = std::string(outputFileName, file - outputFileName);
- ++file;
- }
-
- std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(directory.c_str()),
- closedir);
- if (!dir.get()) return retval;
-
- log_time now(CLOCK_REALTIME);
-
- size_t len = strlen(file);
- log_time modulo(0, NS_PER_SEC);
- struct dirent* dp;
-
- while (!!(dp = readdir(dir.get()))) {
- if ((dp->d_type != DT_REG) || !!strncmp(dp->d_name, file, len) ||
- (dp->d_name[len] && ((dp->d_name[len] != '.') ||
- (strtoll(dp->d_name + 1, nullptr, 10) != 1)))) {
- continue;
- }
-
- std::string file_name = directory;
- file_name += "/";
- file_name += dp->d_name;
- std::string file;
- if (!android::base::ReadFileToString(file_name, &file)) continue;
-
- bool found = false;
- for (const auto& line : android::base::Split(file, "\n")) {
- log_time t(log_time::EPOCH);
- char* ep = parseTime(t, line.c_str());
- if (!ep || (*ep != ' ')) continue;
- // determine the time precision of the logs (eg: msec or usec)
- for (unsigned long mod = 1UL; mod < modulo.tv_nsec; mod *= 10) {
- if (t.tv_nsec % (mod * 10)) {
- modulo.tv_nsec = mod;
- break;
- }
- }
- // We filter any times later than current as we may not have the
- // year stored with each log entry. Also, since it is possible for
- // entries to be recorded out of order (very rare) we select the
- // maximum we find just in case.
- if ((t < now) && (t > retval)) {
- retval = t;
- found = true;
- }
- }
- // We count on the basename file to be the definitive end, so stop here.
- if (!dp->d_name[len] && found) break;
- }
- if (retval == log_time::EPOCH) return retval;
- // tail_time prints matching or higher, round up by the modulo to prevent
- // a replay of the last entry we have just checked.
- retval += modulo;
- return retval;
-}
-
-void ReportErrorName(const std::string& name, bool allow_security,
- std::vector<std::string>* errors) {
- if (allow_security || name != "security") {
- errors->emplace_back(name);
- }
-}
-
-int Logcat::Run(int argc, char** argv) {
- bool hasSetLogFormat = false;
- bool clearLog = false;
- bool security_buffer_selected =
- false; // Do not report errors on the security buffer unless it is explicitly named.
- bool getLogSize = false;
- bool getPruneList = false;
- bool printStatistics = false;
- bool printDividers = false;
- unsigned long setLogSize = 0;
- const char* setPruneList = nullptr;
- const char* setId = nullptr;
- int mode = 0;
- std::string forceFilters;
- size_t tail_lines = 0;
- log_time tail_time(log_time::EPOCH);
- size_t pid = 0;
- bool got_t = false;
- unsigned id_mask = 0;
- std::set<uid_t> uids;
-
- if (argc == 2 && !strcmp(argv[1], "--help")) {
- show_help();
- return EXIT_SUCCESS;
- }
-
- // meant to catch comma-delimited values, but cast a wider
- // net for stability dealing with possible mistaken inputs.
- static const char delimiters[] = ",:; \t\n\r\f";
-
- optind = 0;
- while (true) {
- int option_index = 0;
- // list of long-argument only strings for later comparison
- static const char pid_str[] = "pid";
- static const char debug_str[] = "debug";
- static const char id_str[] = "id";
- static const char wrap_str[] = "wrap";
- static const char print_str[] = "print";
- static const char uid_str[] = "uid";
- // clang-format off
- static const struct option long_options[] = {
- { "binary", no_argument, nullptr, 'B' },
- { "buffer", required_argument, nullptr, 'b' },
- { "buffer-size", optional_argument, nullptr, 'g' },
- { "clear", no_argument, nullptr, 'c' },
- { debug_str, no_argument, nullptr, 0 },
- { "dividers", no_argument, nullptr, 'D' },
- { "file", required_argument, nullptr, 'f' },
- { "format", required_argument, nullptr, 'v' },
- // hidden and undocumented reserved alias for --regex
- { "grep", required_argument, nullptr, 'e' },
- // hidden and undocumented reserved alias for --max-count
- { "head", required_argument, nullptr, 'm' },
- { "help", no_argument, nullptr, 'h' },
- { id_str, required_argument, nullptr, 0 },
- { "last", no_argument, nullptr, 'L' },
- { "max-count", required_argument, nullptr, 'm' },
- { pid_str, required_argument, nullptr, 0 },
- { print_str, no_argument, nullptr, 0 },
- { "prune", optional_argument, nullptr, 'p' },
- { "regex", required_argument, nullptr, 'e' },
- { "rotate-count", required_argument, nullptr, 'n' },
- { "rotate-kbytes", required_argument, nullptr, 'r' },
- { "statistics", no_argument, nullptr, 'S' },
- // hidden and undocumented reserved alias for -t
- { "tail", required_argument, nullptr, 't' },
- { uid_str, required_argument, nullptr, 0 },
- // support, but ignore and do not document, the optional argument
- { wrap_str, optional_argument, nullptr, 0 },
- { nullptr, 0, nullptr, 0 }
- };
- // clang-format on
-
- int c = getopt_long(argc, argv, ":cdDhLt:T:gG:sQf:r:n:v:b:BSpP:m:e:", long_options,
- &option_index);
- if (c == -1) break;
-
- switch (c) {
- case 0:
- // only long options
- if (long_options[option_index].name == pid_str) {
- if (pid != 0) {
- error(EXIT_FAILURE, 0, "Only one --pid argument can be provided.");
- }
-
- if (!ParseUint(optarg, &pid) || pid < 1) {
- error(EXIT_FAILURE, 0, "%s %s out of range.",
- long_options[option_index].name, optarg);
- }
- break;
- }
- if (long_options[option_index].name == wrap_str) {
- mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK;
- // ToDo: implement API that supports setting a wrap timeout
- size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
- if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) {
- error(EXIT_FAILURE, 0, "%s %s out of range.",
- long_options[option_index].name, optarg);
- }
- if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
- fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
- long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
- timeout);
- }
- break;
- }
- if (long_options[option_index].name == print_str) {
- print_it_anyways_ = true;
- break;
- }
- if (long_options[option_index].name == debug_str) {
- debug_ = true;
- break;
- }
- if (long_options[option_index].name == id_str) {
- setId = (optarg && optarg[0]) ? optarg : nullptr;
- }
- if (long_options[option_index].name == uid_str) {
- auto uid_strings = Split(optarg, delimiters);
- for (const auto& uid_string : uid_strings) {
- uid_t uid;
- if (!ParseUint(uid_string, &uid)) {
- error(EXIT_FAILURE, 0, "Unable to parse UID '%s'", uid_string.c_str());
- }
- uids.emplace(uid);
- }
- break;
- }
- break;
-
- case 's':
- // default to all silent
- android_log_addFilterRule(logformat_.get(), "*:s");
- break;
-
- case 'c':
- clearLog = true;
- break;
-
- case 'L':
- mode |= ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK;
- break;
-
- case 'd':
- mode |= ANDROID_LOG_NONBLOCK;
- break;
-
- case 't':
- got_t = true;
- mode |= ANDROID_LOG_NONBLOCK;
- FALLTHROUGH_INTENDED;
- case 'T':
- if (strspn(optarg, "0123456789") != strlen(optarg)) {
- char* cp = parseTime(tail_time, optarg);
- if (!cp) {
- error(EXIT_FAILURE, 0, "-%c '%s' not in time format.", c, optarg);
- }
- if (*cp) {
- char ch = *cp;
- *cp = '\0';
- fprintf(stderr, "WARNING: -%c '%s' '%c%s' time truncated\n", c, optarg, ch,
- cp + 1);
- *cp = ch;
- }
- } else {
- if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
- fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
- tail_lines = 1;
- }
- }
- break;
-
- case 'D':
- printDividers = true;
- break;
-
- case 'e':
- regex_.reset(new std::regex(optarg));
- break;
-
- case 'm': {
- if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
- error(EXIT_FAILURE, 0, "-%c '%s' isn't an integer greater than zero.", c,
- optarg);
- }
- } break;
-
- case 'g':
- if (!optarg) {
- getLogSize = true;
- break;
- }
- FALLTHROUGH_INTENDED;
-
- case 'G': {
- if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
- error(EXIT_FAILURE, 0, "-G must be specified as <num><multiplier>.");
- }
- } break;
-
- case 'p':
- if (!optarg) {
- getPruneList = true;
- break;
- }
- FALLTHROUGH_INTENDED;
-
- case 'P':
- setPruneList = optarg;
- break;
-
- case 'b':
- for (const auto& buffer : Split(optarg, delimiters)) {
- if (buffer == "default") {
- id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
- } else if (buffer == "all") {
- id_mask = -1;
- } else {
- log_id_t log_id = android_name_to_log_id(buffer.c_str());
- if (log_id >= LOG_ID_MAX) {
- error(EXIT_FAILURE, 0, "Unknown buffer '%s' listed for -b.",
- buffer.c_str());
- }
- if (log_id == LOG_ID_SECURITY) {
- security_buffer_selected = true;
- }
- id_mask |= (1 << log_id);
- }
- }
- break;
-
- case 'B':
- print_binary_ = 1;
- break;
-
- case 'f':
- if ((tail_time == log_time::EPOCH) && !tail_lines) {
- tail_time = lastLogTime(optarg);
- }
- // redirect output to a file
- output_file_name_ = optarg;
- break;
-
- case 'r':
- if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -r.", optarg);
- }
- break;
-
- case 'n':
- if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -n.", optarg);
- }
- break;
-
- case 'v':
- if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
- show_format_help();
- return EXIT_SUCCESS;
- }
- for (const auto& arg : Split(optarg, delimiters)) {
- int err = SetLogFormat(arg.c_str());
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid parameter '%s' to -v.", arg.c_str());
- }
- if (err) hasSetLogFormat = true;
- }
- break;
-
- case 'Q':
-#define LOGCAT_FILTER "androidboot.logcat="
-#define CONSOLE_PIPE_OPTION "androidboot.consolepipe="
-#define CONSOLE_OPTION "androidboot.console="
-#define QEMU_PROPERTY "ro.kernel.qemu"
-#define QEMU_CMDLINE "qemu.cmdline"
- // This is a *hidden* option used to start a version of logcat
- // in an emulated device only. It basically looks for
- // androidboot.logcat= on the kernel command line. If
- // something is found, it extracts a log filter and uses it to
- // run the program. The logcat output will go to consolepipe if
- // androiboot.consolepipe (e.g. qemu_pipe) is given, otherwise,
- // it goes to androidboot.console (e.g. tty)
- {
- // if not in emulator, exit quietly
- if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
- return EXIT_SUCCESS;
- }
-
- std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
- if (cmdline.empty()) {
- android::base::ReadFileToString("/proc/cmdline", &cmdline);
- }
-
- const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
- // if nothing found or invalid filters, exit quietly
- if (!logcatFilter) {
- return EXIT_SUCCESS;
- }
-
- const char* p = logcatFilter + strlen(LOGCAT_FILTER);
- const char* q = strpbrk(p, " \t\n\r");
- if (!q) q = p + strlen(p);
- forceFilters = std::string(p, q);
-
- // redirect our output to the emulator console pipe or console
- const char* consolePipe =
- strstr(cmdline.c_str(), CONSOLE_PIPE_OPTION);
- const char* console =
- strstr(cmdline.c_str(), CONSOLE_OPTION);
-
- if (consolePipe) {
- p = consolePipe + strlen(CONSOLE_PIPE_OPTION);
- } else if (console) {
- p = console + strlen(CONSOLE_OPTION);
- } else {
- return EXIT_FAILURE;
- }
-
- q = strpbrk(p, " \t\n\r");
- int len = q ? q - p : strlen(p);
- std::string devname = "/dev/" + std::string(p, len);
- std::string pipePurpose("pipe:logcat");
- if (consolePipe) {
- // example: "qemu_pipe,pipe:logcat"
- // upon opening of /dev/qemu_pipe, the "pipe:logcat"
- // string with trailing '\0' should be written to the fd
- size_t pos = devname.find(',');
- if (pos != std::string::npos) {
- pipePurpose = devname.substr(pos + 1);
- devname = devname.substr(0, pos);
- }
- }
-
- fprintf(stderr, "logcat using %s\n", devname.c_str());
-
- int fd = open(devname.c_str(), O_WRONLY | O_CLOEXEC);
- if (fd < 0) {
- break;
- }
-
- if (consolePipe) {
- // need the trailing '\0'
- if (!WriteFully(fd, pipePurpose.c_str(), pipePurpose.size() + 1)) {
- close(fd);
- return EXIT_FAILURE;
- }
- }
- // close output and error channels, replace with console
- dup2(fd, output_fd_.get());
- dup2(fd, STDERR_FILENO);
- close(fd);
- }
- break;
-
- case 'S':
- printStatistics = true;
- break;
-
- case ':':
- error(EXIT_FAILURE, 0, "Option '%s' needs an argument.", argv[optind - 1]);
- break;
-
- case 'h':
- show_help();
- show_format_help();
- return EXIT_SUCCESS;
-
- case '?':
- error(EXIT_FAILURE, 0, "Unknown option '%s'.", argv[optind - 1]);
- break;
-
- default:
- error(EXIT_FAILURE, 0, "Unknown getopt_long() result '%c'.", c);
- }
- }
-
- if (max_count_ && got_t) {
- error(EXIT_FAILURE, 0, "Cannot use -m (--max-count) and -t together.");
- }
- if (print_it_anyways_ && (!regex_ || !max_count_)) {
- // One day it would be nice if --print -v color and --regex <expr>
- // could play with each other and show regex highlighted content.
- fprintf(stderr,
- "WARNING: "
- "--print ignored, to be used in combination with\n"
- " "
- "--regex <expr> and --max-count <N>\n");
- print_it_anyways_ = false;
- }
-
- // If no buffers are specified, default to using these buffers.
- if (id_mask == 0) {
- id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
- (1 << LOG_ID_KERNEL);
- }
-
- if (log_rotate_size_kb_ != 0 && !output_file_name_) {
- error(EXIT_FAILURE, 0, "-r requires -f as well.");
- }
-
- if (setId != 0) {
- if (!output_file_name_) {
- error(EXIT_FAILURE, 0, "--id='%s' requires -f as well.", setId);
- }
-
- std::string file_name = StringPrintf("%s.id", output_file_name_);
- std::string file;
- bool file_ok = android::base::ReadFileToString(file_name, &file);
- android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
- getuid(), getgid());
- if (!file_ok || !file.compare(setId)) setId = nullptr;
- }
-
- if (!hasSetLogFormat) {
- const char* logFormat = getenv("ANDROID_PRINTF_LOG");
-
- if (!!logFormat) {
- for (const auto& arg : Split(logFormat, delimiters)) {
- int err = SetLogFormat(arg.c_str());
- // environment should not cause crash of logcat
- if (err < 0) {
- fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
- }
- if (err > 0) hasSetLogFormat = true;
- }
- }
- if (!hasSetLogFormat) {
- SetLogFormat("threadtime");
- }
- }
-
- if (forceFilters.size()) {
- int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression in logcat args.");
- }
- } else if (argc == optind) {
- // Add from environment variable
- const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
-
- if (!!env_tags_orig) {
- int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
-
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression in ANDROID_LOG_TAGS.");
- }
- }
- } else {
- // Add from commandline
- for (int i = optind ; i < argc ; i++) {
- int err = android_log_addFilterString(logformat_.get(), argv[i]);
- if (err < 0) {
- error(EXIT_FAILURE, 0, "Invalid filter expression '%s'.", argv[i]);
- }
- }
- }
-
- if (mode & ANDROID_LOG_PSTORE) {
- if (output_file_name_) {
- error(EXIT_FAILURE, 0, "-c is ambiguous with both -f and -L specified.");
- }
- if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
- error(EXIT_FAILURE, 0, "-L is incompatible with -g/-G, -S, and -p/-P.");
- }
- if (clearLog) {
- unlink("/sys/fs/pstore/pmsg-ramoops-0");
- return EXIT_SUCCESS;
- }
- }
-
- if (output_file_name_) {
- if (setLogSize || getLogSize || printStatistics || getPruneList || setPruneList) {
- error(EXIT_FAILURE, 0, "-f is incompatible with -g/-G, -S, and -p/-P.");
- }
-
- if (clearLog || setId) {
- int max_rotation_count_digits =
- max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
-
- for (int i = max_rotated_logs_; i >= 0; --i) {
- std::string file;
-
- if (!i) {
- file = output_file_name_;
- } else {
- file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
- }
-
- int err = unlink(file.c_str());
-
- if (err < 0 && errno != ENOENT) {
- fprintf(stderr, "failed to delete log file '%s': %s\n", file.c_str(),
- strerror(errno));
- }
- }
- }
-
- if (clearLog) {
- return EXIT_SUCCESS;
- }
- }
-
- std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
- nullptr, &android_logger_list_free};
- if (tail_time != log_time::EPOCH) {
- logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
- } else {
- logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
- }
- // We have three orthogonal actions below to clear, set log size and
- // get log size. All sharing the same iteration loop.
- std::vector<std::string> open_device_failures;
- std::vector<std::string> clear_failures;
- std::vector<std::string> set_size_failures;
- std::vector<std::string> get_size_failures;
-
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- if (!(id_mask & (1 << i))) continue;
- const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
-
- auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
- if (logger == nullptr) {
- ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
- continue;
- }
-
- if (clearLog) {
- if (android_logger_clear(logger)) {
- ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
- }
- }
-
- if (setLogSize) {
- if (android_logger_set_log_size(logger, setLogSize)) {
- ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
- }
- }
-
- if (getLogSize) {
- long size = android_logger_get_log_size(logger);
- long readable = android_logger_get_log_readable_size(logger);
- long consumed = android_logger_get_log_consumed_size(logger);
-
- if (size < 0 || readable < 0) {
- ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
- } else {
- auto size_format = format_of_size(size);
- auto readable_format = format_of_size(readable);
- auto consumed_format = format_of_size(consumed);
- std::string str = android::base::StringPrintf(
- "%s: ring buffer is %lu %sB (%lu %sB consumed, %lu %sB readable),"
- " max entry is %d B, max payload is %d B\n",
- buffer_name, size_format.first, size_format.second, consumed_format.first,
- consumed_format.second, readable_format.first, readable_format.second,
- (int)LOGGER_ENTRY_MAX_LEN, (int)LOGGER_ENTRY_MAX_PAYLOAD);
- if (!WriteFully(output_fd_, str.data(), str.length())) {
- error(EXIT_FAILURE, errno, "Failed to write to output fd");
- }
- }
- }
- }
-
- // report any errors in the above loop and exit
- if (!open_device_failures.empty()) {
- error(EXIT_FAILURE, 0, "Unable to open log device%s '%s'.",
- open_device_failures.size() > 1 ? "s" : "", Join(open_device_failures, ",").c_str());
- }
- if (!clear_failures.empty()) {
- error(EXIT_FAILURE, 0, "failed to clear the '%s' log%s.", Join(clear_failures, ",").c_str(),
- clear_failures.size() > 1 ? "s" : "");
- }
- if (!set_size_failures.empty()) {
- error(EXIT_FAILURE, 0, "failed to set the '%s' log size%s.",
- Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
- }
- if (!get_size_failures.empty()) {
- error(EXIT_FAILURE, 0, "failed to get the readable '%s' log size%s.",
- Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
- }
-
- if (setPruneList) {
- size_t len = strlen(setPruneList);
- if (android_logger_set_prune_list(logger_list.get(), setPruneList, len)) {
- error(EXIT_FAILURE, 0, "Failed to set the prune list.");
- }
- return EXIT_SUCCESS;
- }
-
- if (printStatistics || getPruneList) {
- std::string buf(8192, '\0');
- size_t ret_length = 0;
- int retry = 32;
-
- for (; retry >= 0; --retry) {
- if (getPruneList) {
- android_logger_get_prune_list(logger_list.get(), buf.data(), buf.size());
- } else {
- android_logger_get_statistics(logger_list.get(), buf.data(), buf.size());
- }
-
- ret_length = atol(buf.c_str());
- if (ret_length < 3) {
- error(EXIT_FAILURE, 0, "Failed to read data.");
- }
-
- if (ret_length < buf.size()) {
- break;
- }
-
- buf.resize(ret_length + 1);
- }
-
- if (retry < 0) {
- error(EXIT_FAILURE, 0, "Failed to read data.");
- }
-
- buf.resize(ret_length);
- if (buf.back() == '\f') {
- buf.pop_back();
- }
-
- // Remove the byte count prefix
- const char* cp = buf.c_str();
- while (isdigit(*cp)) ++cp;
- if (*cp == '\n') ++cp;
-
- size_t len = strlen(cp);
- if (!WriteFully(output_fd_, cp, len)) {
- error(EXIT_FAILURE, errno, "Failed to write to output fd");
- }
- return EXIT_SUCCESS;
- }
-
- if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
-
- SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
-
- while (!max_count_ || print_count_ < max_count_) {
- struct log_msg log_msg;
- int ret = android_logger_list_read(logger_list.get(), &log_msg);
- if (!ret) {
- error(EXIT_FAILURE, 0, R"init(Unexpected EOF!
-
-This means that either the device shut down, logd crashed, or this instance of logcat was unable to read log
-messages as quickly as they were being produced.
-
-If you have enabled significant logging, look into using the -G option to increase log buffer sizes.)init");
- }
-
- if (ret < 0) {
- if (ret == -EAGAIN) break;
-
- if (ret == -EIO) {
- error(EXIT_FAILURE, 0, "Unexpected EOF!");
- }
- if (ret == -EINVAL) {
- error(EXIT_FAILURE, 0, "Unexpected length.");
- }
- error(EXIT_FAILURE, errno, "Logcat read failure");
- }
-
- if (log_msg.id() > LOG_ID_MAX) {
- error(EXIT_FAILURE, 0, "Unexpected log id (%d) over LOG_ID_MAX (%d).", log_msg.id(),
- LOG_ID_MAX);
- }
-
- if (!uids.empty() && uids.count(log_msg.entry.uid) == 0) {
- continue;
- }
-
- PrintDividers(log_msg.id(), printDividers);
-
- if (print_binary_) {
- if (!WriteFully(output_fd_, &log_msg, log_msg.len())) {
- error(EXIT_FAILURE, errno, "Failed to write to output fd");
- }
- } else {
- ProcessBuffer(&log_msg);
- }
- }
- return EXIT_SUCCESS;
-}
-
-int main(int argc, char** argv) {
- Logcat logcat;
- return logcat.Run(argc, argv);
-}
diff --git a/logcat/logcatd b/logcat/logcatd
deleted file mode 100755
index 5a1415d..0000000
--- a/logcat/logcatd
+++ /dev/null
@@ -1,29 +0,0 @@
-#! /system/bin/sh
-
-# This is primarily meant to be used by logpersist. This script is run as an init service, which
-# first reads the 'last' logcat to persistent storage with `-L` then run logcat again without
-# `-L` to read the current logcat buffers to persistent storage.
-
-# init sets the umask to 077 for forked processes. logpersist needs to create files that are group
-# readable. So relax the umask to only disallow group wx and world rwx.
-umask 037
-
-has_last="false"
-for arg in "$@"; do
- if [ "$arg" == "-L" -o "$arg" == "--last" ]; then
- has_last="true"
- fi
-done
-
-if [ "$has_last" == "true" ]; then
- logcat "$@"
-fi
-
-args_without_last=()
-for arg in "$@"; do
- if [ "$arg" != "-L" -a "$arg" != "--last" ]; then
- ARGS+=("$arg")
- fi
-done
-
-exec logcat "${ARGS[@]}"
diff --git a/logcat/logcatd.rc b/logcat/logcatd.rc
deleted file mode 100644
index 64d5500..0000000
--- a/logcat/logcatd.rc
+++ /dev/null
@@ -1,62 +0,0 @@
-#
-# init scriptures for logcatd persistent logging.
-#
-# Make sure any property changes are only performed with /data mounted, after
-# post-fs-data state because otherwise behavior is undefined. The exceptions
-# are device adjustments for logcatd service properties (persist.* overrides
-# notwithstanding) for logd.logpersistd.size logd.logpersistd.rotate_kbytes and
-# logd.logpersistd.buffer.
-
-# persist to non-persistent trampolines to permit device properties can be
-# overridden when /data mounts, or during runtime.
-on property:persist.logd.logpersistd.count=*
- # expect /init to report failure if property empty (default)
- setprop persist.logd.logpersistd.size ${persist.logd.logpersistd.count}
-
-on property:persist.logd.logpersistd.size=*
- setprop logd.logpersistd.size ${persist.logd.logpersistd.size}
-
-on property:persist.logd.logpersistd.rotate_kbytes=*
- setprop logd.logpersistd.rotate_kbytes ${persist.logd.logpersistd.rotate_kbytes}
-
-on property:persist.logd.logpersistd.buffer=*
- setprop logd.logpersistd.buffer ${persist.logd.logpersistd.buffer}
-
-on property:persist.logd.logpersistd=logcatd
- setprop logd.logpersistd logcatd
-
-# enable, prep and start logcatd service
-on load_persist_props_action
- setprop logd.logpersistd.enable true
-
-on property:logd.logpersistd.enable=true && property:logd.logpersistd=logcatd
- # log group should be able to read persisted logs
- mkdir /data/misc/logd 0750 logd log
- start logcatd
-
-# stop logcatd service and clear data
-on property:logd.logpersistd.enable=true && property:logd.logpersistd=clear
- setprop persist.logd.logpersistd ""
- stop logcatd
- # logd for clear of only our files in /data/misc/logd
- exec - logd log -- /system/bin/logcat -c -f /data/misc/logd/logcat -n ${logd.logpersistd.size:-256}
- setprop logd.logpersistd ""
-
-# stop logcatd service
-on property:logd.logpersistd=stop
- setprop persist.logd.logpersistd ""
- stop logcatd
- setprop logd.logpersistd ""
-
-on property:logd.logpersistd.enable=false
- stop logcatd
-
-# logcatd service
-service logcatd /system/bin/logcatd -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r ${logd.logpersistd.rotate_kbytes:-2048} -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
- class late_start
- disabled
- # logd for write to /data/misc/logd, log group for read from log daemon
- user logd
- group log
- writepid /dev/cpuset/system-background/tasks
- oom_score_adjust -600
diff --git a/logcat/logpersist b/logcat/logpersist
deleted file mode 100755
index 05b46f0..0000000
--- a/logcat/logpersist
+++ /dev/null
@@ -1,178 +0,0 @@
-#! /system/bin/sh
-# logpersist cat, start and stop handlers
-progname="${0##*/}"
-case `getprop ro.debuggable` in
-1) ;;
-*) echo "${progname} - Permission denied"
- exit 1
- ;;
-esac
-
-property=persist.logd.logpersistd
-
-case `getprop ${property#persist.}.enable` in
-true) ;;
-*) echo "${progname} - Disabled"
- exit 1
- ;;
-esac
-
-log_uid=logd
-log_tag_property=persist.log.tag
-data=/data/misc/logd/logcat
-service=logcatd
-size_default=256
-buffer_default=all
-args="${@}"
-
-size=${size_default}
-buffer=${buffer_default}
-clear=false
-while [ ${#} -gt 0 ]; do
- case ${1} in
- -c|--clear) clear=true ;;
- --size=*) size="${1#--size=}" ;;
- --rotate-count=*) size="${1#--rotate-count=}" ;;
- -n|--size|--rotate-count) size="${2}" ; shift ;;
- --buffer=*) buffer="${1#--buffer=}" ;;
- -b|--buffer) buffer="${2}" ; shift ;;
- -h|--help|*)
- LEAD_SPACE_="`echo ${progname%.*} | tr '[ -~]' ' '`"
- echo "${progname%.*}.cat - dump current ${service} logs"
- echo "${progname%.*}.start [--size=<size_in_kb>] [--buffer=<buffers>] [--clear]"
- echo "${LEAD_SPACE_} - start ${service} service"
- echo "${progname%.*}.stop [--clear] - stop ${service} service"
- case ${1} in
- -h|--help) exit 0 ;;
- *) echo ERROR: bad argument ${@} >&2 ; exit 1 ;;
- esac
- ;;
- esac
- shift
-done
-
-if [ -z "${size}" -o "${size_default}" = "${size}" ]; then
- unset size
-fi
-if [ -n "${size}" ] &&
- ! ( [ 0 -lt "${size}" ] && [ 2048 -ge "${size}" ] ) >/dev/null 2>&1; then
- echo ERROR: Invalid --size ${size} >&2
- exit 1
-fi
-if [ -z "${buffer}" -o "${buffer_default}" = "${buffer}" ]; then
- unset buffer
-fi
-if [ -n "${buffer}" ] && ! logcat -b ${buffer} -g >/dev/null 2>&1; then
- echo ERROR: Invalid --buffer ${buffer} >&2
- exit 1
-fi
-
-log_tag="`getprop ${log_tag_property}`"
-logd_logpersistd="`getprop ${property}`"
-
-case ${progname} in
-*.cat)
- if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
- echo WARNING: Can not use --clear, --size or --buffer with ${progname%.*}.cat >&2
- fi
- su ${log_uid} ls "${data%/*}" |
- tr -d '\r' |
- sort -ru |
- sed "s#^#${data%/*}/#" |
- grep "${data}[.]*[0-9]*\$" |
- su ${log_uid} xargs cat
- ;;
-*.start)
- current_buffer="`getprop ${property#persist.}.buffer`"
- current_size="`getprop ${property#persist.}.size`"
- if [ "${service}" = "`getprop ${property#persist.}`" ]; then
- if [ "true" = "${clear}" ]; then
- setprop ${property#persist.} "clear"
- elif [ "${buffer}|${size}" != "${current_buffer}|${current_size}" ]; then
- echo "ERROR: Changing existing collection parameters from" >&2
- if [ "${buffer}" != "${current_buffer}" ]; then
- a=${current_buffer}
- b=${buffer}
- if [ -z "${a}" ]; then a="${default_buffer}"; fi
- if [ -z "${b}" ]; then b="${default_buffer}"; fi
- echo " --buffer ${a} to ${b}" >&2
- fi
- if [ "${size}" != "${current_size}" ]; then
- a=${current_size}
- b=${size}
- if [ -z "${a}" ]; then a="${default_size}"; fi
- if [ -z "${b}" ]; then b="${default_size}"; fi
- echo " --size ${a} to ${b}" >&2
- fi
- echo " Are you sure you want to do this?" >&2
- echo " Suggest add --clear to erase data and restart with new settings." >&2
- echo " To blindly override and retain data, ${progname%.*}.stop first." >&2
- exit 1
- fi
- elif [ "true" = "${clear}" ]; then
- setprop ${property#persist.} "clear"
- fi
- if [ -n "${buffer}${current_buffer}" ]; then
- setprop ${property}.buffer "${buffer}"
- if [ -z "${buffer}" ]; then
- # deal with trampoline for empty properties
- setprop ${property#persist.}.buffer ""
- fi
- fi
- if [ -n "${size}${current_size}" ]; then
- setprop ${property}.size "${size}"
- if [ -z "${size}" ]; then
- # deal with trampoline for empty properties
- setprop ${property#persist.}.size ""
- fi
- fi
- while [ "clear" = "`getprop ${property#persist.}`" ]; do
- continue
- done
- # Tell Settings that we are back on again if we turned logging off
- tag="${log_tag#Settings}"
- if [ X"${log_tag}" != X"${tag}" ]; then
- echo "WARNING: enabling logd service" >&2
- setprop ${log_tag_property} "${tag#,}"
- fi
- # ${service}.rc does the heavy lifting with the following trigger
- setprop ${property} ${service}
- # 20ms done, to permit process feedback check
- sleep 1
- getprop ${property#persist.}
- # also generate an error return code if not found running
- pgrep -u ${log_uid} ${service%d}
- ;;
-*.stop)
- if [ -n "${size}${buffer}" ]; then
- echo "WARNING: Can not use --size or --buffer with ${progname%.*}.stop" >&2
- fi
- if [ "true" = "${clear}" ]; then
- setprop ${property#persist.} "clear"
- else
- setprop ${property#persist.} "stop"
- fi
- if [ -n "`getprop ${property#persist.}.buffer`" ]; then
- setprop ${property}.buffer ""
- # deal with trampoline for empty properties
- setprop ${property#persist.}.buffer ""
- fi
- if [ -n "`getprop ${property#persist.}.size`" ]; then
- setprop ${property}.size ""
- # deal with trampoline for empty properties
- setprop ${property#persist.}.size ""
- fi
- while [ "clear" = "`getprop ${property#persist.}`" ]; do
- continue
- done
- ;;
-*)
- echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
- exit 1
-esac
-
-if [ X"${log_tag}" != X"`getprop ${log_tag_property}`" ] ||
- [ X"${logd_logpersistd}" != X"`getprop ${property}`" ]; then
- echo "WARNING: killing Settings application to pull in new values" >&2
- am force-stop com.android.settings
-fi
diff --git a/logcat/tests/Android.bp b/logcat/tests/Android.bp
deleted file mode 100644
index ab84150..0000000
--- a/logcat/tests/Android.bp
+++ /dev/null
@@ -1,57 +0,0 @@
-//
-// Copyright (C) 2013-2014 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.
-//
-
-cc_defaults {
- name: "logcat-tests-defaults",
- cflags: [
- "-fstack-protector-all",
- "-g",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ],
-}
-
-// -----------------------------------------------------------------------------
-// Benchmarks
-// ----------------------------------------------------------------------------
-
-// Build benchmarks for the device. Run with:
-// adb shell /data/nativetest/logcat-benchmarks/logcat-benchmarks
-cc_benchmark {
- name: "logcat-benchmarks",
- defaults: ["logcat-tests-defaults"],
- srcs: ["logcat_benchmark.cpp"],
- shared_libs: ["libbase"],
-}
-
-// -----------------------------------------------------------------------------
-// Unit tests.
-// -----------------------------------------------------------------------------
-
-// Build tests for the device (with .so). Run with:
-// adb shell /data/nativetest/logcat-unit-tests/logcat-unit-tests
-cc_test {
- name: "logcat-unit-tests",
- defaults: ["logcat-tests-defaults"],
- shared_libs: ["libbase"],
- static_libs: ["liblog"],
- srcs: [
- "logcat_test.cpp",
- "logcatd_test.cpp",
- ],
-}
diff --git a/logcat/tests/logcat_benchmark.cpp b/logcat/tests/logcat_benchmark.cpp
deleted file mode 100644
index 8d88628..0000000
--- a/logcat/tests/logcat_benchmark.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2013-2014 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <benchmark/benchmark.h>
-
-static const char begin[] = "--------- beginning of ";
-
-static void BM_logcat_sorted_order(benchmark::State& state) {
- FILE* fp;
-
- if (!state.KeepRunning()) return;
-
- fp = popen(
- "logcat -v time -b radio -b events -b system -b main -d 2>/dev/null",
- "r");
- if (!fp) return;
-
- class timestamp {
- private:
- int month;
- int day;
- int hour;
- int minute;
- int second;
- int millisecond;
- bool ok;
-
- public:
- void init(const char* buffer) {
- ok = false;
- if (buffer != NULL) {
- ok = sscanf(buffer, "%d-%d %d:%d:%d.%d ", &month, &day, &hour,
- &minute, &second, &millisecond) == 6;
- }
- }
-
- explicit timestamp(const char* buffer) {
- init(buffer);
- }
-
- bool operator<(timestamp& T) {
- return !ok || !T.ok || (month < T.month) ||
- ((month == T.month) &&
- ((day < T.day) ||
- ((day == T.day) &&
- ((hour < T.hour) ||
- ((hour == T.hour) &&
- ((minute < T.minute) ||
- ((minute == T.minute) &&
- ((second < T.second) ||
- ((second == T.second) &&
- (millisecond < T.millisecond))))))))));
- }
-
- bool valid(void) {
- return ok;
- }
- } last(NULL);
-
- char* last_buffer = NULL;
- char buffer[5120];
-
- int count = 0;
- int next_lt_last = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
- if (!last.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- timestamp next(buffer);
- if (next < last) {
- if (last_buffer) {
- fprintf(stderr, "<%s", last_buffer);
- }
- fprintf(stderr, ">%s", buffer);
- ++next_lt_last;
- }
- if (next.valid()) {
- free(last_buffer);
- last_buffer = strdup(buffer);
- last.init(buffer);
- }
- ++count;
- }
- free(last_buffer);
-
- pclose(fp);
-
- static const int max_ok = 2;
-
- // Allow few fails, happens with readers active
- fprintf(stderr, "%s: %d/%d out of order entries\n",
- (next_lt_last) ? ((next_lt_last <= max_ok) ? "WARNING" : "ERROR")
- : "INFO",
- next_lt_last, count);
-
- if (next_lt_last > max_ok) {
- fprintf(stderr, "EXPECT_GE(max_ok=%d, next_lt_last=%d)\n", max_ok,
- next_lt_last);
- }
-
- // sample statistically too small
- if (count < 100) {
- fprintf(stderr, "EXPECT_LT(100, count=%d)\n", count);
- }
-
- state.KeepRunning();
-}
-BENCHMARK(BM_logcat_sorted_order);
-
-BENCHMARK_MAIN();
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
deleted file mode 100644
index 0860000..0000000
--- a/logcat/tests/logcat_test.cpp
+++ /dev/null
@@ -1,1791 +0,0 @@
-/*
- * Copyright (C) 2013-2014 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 <ctype.h>
-#include <dirent.h>
-#include <pwd.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <memory>
-#include <regex>
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <gtest/gtest.h>
-#include <log/event_tag_map.h>
-#include <log/log.h>
-#include <log/log_event_list.h>
-
-#ifndef logcat_executable
-#define USING_LOGCAT_EXECUTABLE_DEFAULT
-#define logcat_executable "logcat"
-#endif
-
-#define BIG_BUFFER (5 * 1024)
-
-// rest(), let the logs settle.
-//
-// logd is in a background cgroup and under extreme load can take up to
-// 3 seconds to land a log entry. Under moderate load we can do with 200ms.
-static void rest() {
- static const useconds_t restPeriod = 200000;
-
- usleep(restPeriod);
-}
-
-// enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
-// non-syscall libs. Since we are only using this in the emergency of
-// a signal to stuff a terminating code into the logs, we will spin rather
-// than try a usleep.
-#define LOG_FAILURE_RETRY(exp) \
- ({ \
- typeof(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (((_rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) || \
- (_rc == -EINTR) || (_rc == -EAGAIN)); \
- _rc; \
- })
-
-static const char begin[] = "--------- beginning of ";
-
-TEST(logcat, buckets) {
- FILE* fp;
-
-#undef LOG_TAG
-#define LOG_TAG "inject.buckets"
- // inject messages into radio, system, main and events buffers to
- // ensure that we see all the begin[] bucket messages.
- RLOGE(logcat_executable);
- SLOGE(logcat_executable);
- ALOGE(logcat_executable);
- __android_log_bswrite(0, logcat_executable ".inject.buckets");
- rest();
-
- ASSERT_TRUE(NULL != (fp = popen(logcat_executable
- " -b radio -b events -b system -b main -d 2>/dev/null",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int ids = 0;
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- while (char* cp = strrchr(buffer, '\n')) {
- *cp = '\0';
- }
- log_id_t id = android_name_to_log_id(buffer + sizeof(begin) - 1);
- ids |= 1 << id;
- ++count;
- }
- }
-
- pclose(fp);
-
- EXPECT_EQ(ids, 15);
-
- EXPECT_EQ(count, 4);
-}
-
-TEST(logcat, event_tag_filter) {
- FILE* fp;
-
-#undef LOG_TAG
-#define LOG_TAG "inject.filter"
- // inject messages into radio, system and main buffers
- // with our unique log tag to test logcat filter.
- RLOGE(logcat_executable);
- SLOGE(logcat_executable);
- ALOGE(logcat_executable);
- rest();
-
- std::string command = android::base::StringPrintf(
- logcat_executable
- " -b radio -b system -b main --pid=%d -d -s inject.filter 2>/dev/null",
- getpid());
- ASSERT_TRUE(NULL != (fp = popen(command.c_str(), "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (strncmp(begin, buffer, sizeof(begin) - 1)) ++count;
- }
-
- pclose(fp);
-
- // logcat, liblogcat and logcatd test instances result in the progression
- // of 3, 6 and 9 for our counts as each round is performed.
- EXPECT_GE(count, 3);
- EXPECT_LE(count, 9);
- EXPECT_EQ(count % 3, 0);
-}
-
-// If there is not enough background noise in the logs, then spam the logs to
-// permit tail checking so that the tests can progress.
-static size_t inject(ssize_t count) {
- if (count <= 0) return 0;
-
- static const size_t retry = 4;
- size_t errors = retry;
- size_t num = 0;
- for (;;) {
- log_time ts(CLOCK_MONOTONIC);
- if (__android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)) >= 0) {
- if (++num >= (size_t)count) {
- // let data settle end-to-end
- sleep(3);
- return num;
- }
- errors = retry;
- usleep(100); // ~32 per timer tick, we are a spammer regardless
- } else if (--errors <= 0) {
- return num;
- }
- }
- // NOTREACH
- return num;
-}
-
-TEST(logcat, year) {
- int count;
- int tries = 3; // in case run too soon after system start or buffer clear
-
- do {
- FILE* fp;
-
- char needle[32];
- time_t now;
- time(&now);
- struct tm* ptm;
-#if !defined(_WIN32)
- struct tm tmBuf;
- ptm = localtime_r(&now, &tmBuf);
-#else
- ptm = localtime(&&now);
-#endif
- strftime(needle, sizeof(needle), "[ %Y-", ptm);
-
- ASSERT_TRUE(NULL !=
- (fp = popen(logcat_executable " -v long -v year -b all -t 3 2>/dev/null", "r")));
-
- char buffer[BIG_BUFFER];
-
- count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, needle, strlen(needle))) {
- ++count;
- }
- }
- pclose(fp);
-
- } while ((count < 3) && --tries && inject(3 - count));
-
- ASSERT_EQ(3, count);
-}
-
-// Return a pointer to each null terminated -v long time field.
-static char* fgetLongTime(char* buffer, size_t buflen, FILE* fp) {
- while (fgets(buffer, buflen, fp)) {
- char* cp = buffer;
- if (*cp != '[') {
- continue;
- }
- while (*++cp == ' ') {
- ;
- }
- char* ep = cp;
- while (isdigit(*ep)) {
- ++ep;
- }
- if ((*ep != '-') && (*ep != '.')) {
- continue;
- }
- // Find PID field. Look for ': ' or ':[0-9][0-9][0-9]'
- while (((ep = strchr(ep, ':'))) && (*++ep != ' ')) {
- if (isdigit(ep[0]) && isdigit(ep[1]) && isdigit(ep[2])) break;
- }
- if (!ep) {
- continue;
- }
- static const size_t pid_field_width = 7;
- ep -= pid_field_width;
- *ep = '\0';
- return cp;
- }
- return NULL;
-}
-
-TEST(logcat, tz) {
- int tries = 4; // in case run too soon after system start or buffer clear
- int count;
-
- do {
- FILE* fp;
-
- ASSERT_TRUE(NULL != (fp = popen(logcat_executable
- " -v long -v America/Los_Angeles -b all -t 3 2>/dev/null",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- count = 0;
-
- while (fgetLongTime(buffer, sizeof(buffer), fp)) {
- if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
- ++count;
- } else {
- fprintf(stderr, "ts=\"%s\"\n", buffer + 2);
- }
- }
-
- pclose(fp);
-
- } while ((count < 3) && --tries && inject(3 - count));
-
- ASSERT_EQ(3, count);
-}
-
-TEST(logcat, ntz) {
- FILE* fp;
-
- ASSERT_TRUE(NULL !=
- (fp = popen(logcat_executable
- " -v long -v America/Los_Angeles -v zone -b all -t 3 2>/dev/null",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgetLongTime(buffer, sizeof(buffer), fp)) {
- if (strstr(buffer, " -0700") || strstr(buffer, " -0800")) {
- ++count;
- }
- }
-
- pclose(fp);
-
- ASSERT_EQ(0, count);
-}
-
-static void do_tail(int num) {
- int tries = 4; // in case run too soon after system start or buffer clear
- int count;
-
- if (num > 10) ++tries;
- if (num > 100) ++tries;
- do {
- char buffer[BIG_BUFFER];
-
- snprintf(buffer, sizeof(buffer),
- "ANDROID_PRINTF_LOG=long logcat -b all -t %d 2>/dev/null", num);
-
- FILE* fp;
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- count = 0;
-
- while (fgetLongTime(buffer, sizeof(buffer), fp)) {
- ++count;
- }
-
- pclose(fp);
-
- } while ((count < num) && --tries && inject(num - count));
-
- ASSERT_EQ(num, count);
-}
-
-TEST(logcat, tail_3) {
- do_tail(3);
-}
-
-TEST(logcat, tail_10) {
- do_tail(10);
-}
-
-TEST(logcat, tail_100) {
- do_tail(100);
-}
-
-TEST(logcat, tail_1000) {
- do_tail(1000);
-}
-
-static void do_tail_time(const char* cmd) {
- FILE* fp;
- int count;
- char buffer[BIG_BUFFER];
- char* last_timestamp = NULL;
- // Hard to predict 100% if first (overlap) or second line will match.
- // -v nsec will in a substantial majority be the second line.
- char* first_timestamp = NULL;
- char* second_timestamp = NULL;
- char* input;
-
- int tries = 4; // in case run too soon after system start or buffer clear
-
- do {
- snprintf(buffer, sizeof(buffer), "%s -t 10 2>&1", cmd);
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
- count = 0;
-
- while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) {
- ++count;
- if (!first_timestamp) {
- first_timestamp = strdup(input);
- } else if (!second_timestamp) {
- second_timestamp = strdup(input);
- }
- free(last_timestamp);
- last_timestamp = strdup(input);
- }
- pclose(fp);
-
- } while ((count < 10) && --tries && inject(10 - count));
-
- EXPECT_EQ(count, 10); // We want _some_ history, too small, falses below
- EXPECT_TRUE(last_timestamp != NULL);
- EXPECT_TRUE(first_timestamp != NULL);
- EXPECT_TRUE(second_timestamp != NULL);
-
- snprintf(buffer, sizeof(buffer), "%s -t '%s' 2>&1", cmd, first_timestamp);
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- int second_count = 0;
- int last_timestamp_count = -1;
-
- --count; // One less unless we match the first_timestamp
- bool found = false;
- while ((input = fgetLongTime(buffer, sizeof(buffer), fp))) {
- ++second_count;
- // We want to highlight if we skip to the next entry.
- // WAI, if the time in logd is *exactly*
- // XX-XX XX:XX:XX.XXXXXX000 (usec) or XX-XX XX:XX:XX.XXX000000
- // this can happen, but it should not happen with nsec.
- // We can make this WAI behavior happen 1000 times less
- // frequently if the caller does not use the -v usec flag,
- // but always the second (always skip) if they use the
- // (undocumented) -v nsec flag.
- if (first_timestamp) {
- found = !strcmp(input, first_timestamp);
- if (found) {
- ++count;
- GTEST_LOG_(INFO)
- << "input = first(" << first_timestamp << ")\n";
- }
- free(first_timestamp);
- first_timestamp = NULL;
- }
- if (second_timestamp) {
- found = found || !strcmp(input, second_timestamp);
- if (!found) {
- GTEST_LOG_(INFO) << "input(" << input << ") != second("
- << second_timestamp << ")\n";
- }
- free(second_timestamp);
- second_timestamp = NULL;
- }
- if (!strcmp(input, last_timestamp)) {
- last_timestamp_count = second_count;
- }
- }
- pclose(fp);
-
- EXPECT_TRUE(found);
- if (!found) {
- if (first_timestamp) {
- GTEST_LOG_(INFO) << "first = " << first_timestamp << "\n";
- }
- if (second_timestamp) {
- GTEST_LOG_(INFO) << "second = " << second_timestamp << "\n";
- }
- if (last_timestamp) {
- GTEST_LOG_(INFO) << "last = " << last_timestamp << "\n";
- }
- }
- free(last_timestamp);
- last_timestamp = NULL;
- free(first_timestamp);
- free(second_timestamp);
-
- EXPECT_TRUE(first_timestamp == NULL);
- EXPECT_TRUE(second_timestamp == NULL);
- EXPECT_LE(count, second_count);
- EXPECT_LE(count, last_timestamp_count);
-}
-
-TEST(logcat, tail_time) {
- do_tail_time(logcat_executable " -v long -v nsec -b all");
-}
-
-TEST(logcat, tail_time_epoch) {
- do_tail_time(logcat_executable " -v long -v nsec -v epoch -b all");
-}
-
-TEST(logcat, End_to_End) {
- pid_t pid = getpid();
-
- log_time ts(CLOCK_MONOTONIC);
-
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-
- FILE* fp;
- ASSERT_TRUE(NULL !=
- (fp = popen(logcat_executable " -v brief -b events -t 100 2>/dev/null", "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- int p;
- unsigned long long t;
-
- if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) ||
- (p != pid)) {
- continue;
- }
-
- log_time* tx = reinterpret_cast<log_time*>(&t);
- if (ts == *tx) {
- ++count;
- }
- }
-
- pclose(fp);
-
- ASSERT_EQ(1, count);
-}
-
-TEST(logcat, End_to_End_multitude) {
- pid_t pid = getpid();
-
- log_time ts(CLOCK_MONOTONIC);
-
- ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-
- FILE* fp[256]; // does this count as a multitude!
- memset(fp, 0, sizeof(fp));
- size_t num = 0;
- do {
- EXPECT_TRUE(NULL != (fp[num] = popen(logcat_executable " -v brief -b events -t 100", "r")));
- if (!fp[num]) {
- fprintf(stderr,
- "WARNING: limiting to %zu simultaneous logcat operations\n",
- num);
- break;
- }
- } while (++num < sizeof(fp) / sizeof(fp[0]));
-
- char buffer[BIG_BUFFER];
-
- size_t count = 0;
-
- for (size_t idx = 0; idx < sizeof(fp) / sizeof(fp[0]); ++idx) {
- if (!fp[idx]) break;
- while (fgets(buffer, sizeof(buffer), fp[idx])) {
- int p;
- unsigned long long t;
-
- if ((2 != sscanf(buffer, "I/[0] ( %d): %llu", &p, &t)) ||
- (p != pid)) {
- continue;
- }
-
- log_time* tx = reinterpret_cast<log_time*>(&t);
- if (ts == *tx) {
- ++count;
- }
- }
-
- pclose(fp[idx]);
- }
-
- ASSERT_EQ(num, count);
-}
-
-static int get_groups(const char* cmd) {
- FILE* fp;
-
- // NB: crash log only available in user space
- EXPECT_TRUE(NULL != (fp = popen(cmd, "r")));
-
- if (fp == NULL) {
- return 0;
- }
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- int size, consumed, max, payload;
- char size_mult[4], consumed_mult[4];
- long full_size, full_consumed;
-
- size = consumed = max = payload = 0;
- // NB: crash log can be very small, not hit a Kb of consumed space
- // doubly lucky we are not including it.
- EXPECT_EQ(6, sscanf(buffer,
- "%*s ring buffer is %d %3s (%d %3s consumed),"
- " max entry is %d B, max payload is %d B",
- &size, size_mult, &consumed, consumed_mult, &max, &payload))
- << "Parse error on: " << buffer;
- full_size = size;
- switch (size_mult[0]) {
- case 'G':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- default:
- ADD_FAILURE() << "Parse error on multiplier: " << size_mult;
- }
- full_consumed = consumed;
- switch (consumed_mult[0]) {
- case 'G':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- default:
- ADD_FAILURE() << "Parse error on multiplier: " << consumed_mult;
- }
- EXPECT_GT((full_size * 9) / 4, full_consumed);
- EXPECT_GT(full_size, max);
- EXPECT_GT(max, payload);
-
- if ((((full_size * 9) / 4) >= full_consumed) && (full_size > max) &&
- (max > payload)) {
- ++count;
- }
- }
-
- pclose(fp);
-
- return count;
-}
-
-TEST(logcat, get_size) {
- ASSERT_EQ(4, get_groups(logcat_executable
- " -v brief -b radio -b events -b system -b "
- "main -g 2>/dev/null"));
-}
-
-// duplicate test for get_size, but use comma-separated list of buffers
-TEST(logcat, multiple_buffer) {
- ASSERT_EQ(
- 4, get_groups(logcat_executable
- " -v brief -b radio,events,system,main -g 2>/dev/null"));
-}
-
-TEST(logcat, bad_buffer) {
- ASSERT_EQ(0,
- get_groups(
- logcat_executable
- " -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
-}
-
-#ifndef logcat
-static void caught_blocking(int signum) {
- unsigned long long v = 0xDEADBEEFA55A0000ULL;
-
- v += getpid() & 0xFFFF;
- if (signum == 0) ++v;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-TEST(logcat, blocking) {
- FILE* fp;
- unsigned long long v = 0xDEADBEEFA55F0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-
- v &= 0xFFFFFFFFFFFAFFFFULL;
-
- ASSERT_TRUE(
- NULL !=
- (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -v brief -b events 2>&1",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- int signals = 0;
-
- signal(SIGALRM, caught_blocking);
- alarm(2);
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, "DONE", 4)) {
- break;
- }
-
- ++count;
-
- int p;
- unsigned long long l;
-
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
- continue;
- }
-
- if (l == v) {
- ++signals;
- break;
- }
- }
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- // Generate SIGPIPE
- fclose(fp);
- caught_blocking(0);
-
- pclose(fp);
-
- EXPECT_GE(count, 2);
-
- EXPECT_EQ(signals, 1);
-}
-
-static void caught_blocking_tail(int signum) {
- unsigned long long v = 0xA55ADEADBEEF0000ULL;
-
- v += getpid() & 0xFFFF;
- if (signum == 0) ++v;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-TEST(logcat, blocking_tail) {
- FILE* fp;
- unsigned long long v = 0xA55FDEADBEEF0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-
- v &= 0xFFFAFFFFFFFFFFFFULL;
-
- ASSERT_TRUE(
- NULL !=
- (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -v brief -b events -T 5 2>&1",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
-
- int signals = 0;
-
- signal(SIGALRM, caught_blocking_tail);
- alarm(2);
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, "DONE", 4)) {
- break;
- }
-
- ++count;
-
- int p;
- unsigned long long l;
-
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
- continue;
- }
-
- if (l == v) {
- if (count >= 5) {
- ++signals;
- }
- break;
- }
- }
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- // Generate SIGPIPE
- fclose(fp);
- caught_blocking_tail(0);
-
- pclose(fp);
-
- EXPECT_GE(count, 2);
-
- EXPECT_EQ(signals, 1);
-}
-#endif
-
-// meant to be handed to ASSERT_FALSE / EXPECT_FALSE to expand the message
-static testing::AssertionResult IsFalse(int ret, const char* command) {
- return ret ? (testing::AssertionSuccess()
- << "ret=" << ret << " command=\"" << command << "\"")
- : testing::AssertionFailure();
-}
-
-TEST(logcat, logrotate) {
- static const char form[] = "/data/local/tmp/logcat.logrotate.XXXXXX";
- char buf[sizeof(form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(buf, form)));
-
- static const char comm[] = logcat_executable
- " -b radio -b events -b system -b main"
- " -d -f %s/log.txt -n 7 -r 1";
- char command[sizeof(buf) + sizeof(comm)];
- snprintf(command, sizeof(command), comm, buf);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (!ret) {
- snprintf(command, sizeof(command), "ls -s %s 2>/dev/null", buf);
-
- FILE* fp;
- EXPECT_TRUE(NULL != (fp = popen(command, "r")));
- if (fp) {
- char buffer[BIG_BUFFER];
- int count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- static const char total[] = "total ";
- int num;
- char c;
-
- if ((2 == sscanf(buffer, "%d log.tx%c", &num, &c)) &&
- (num <= 40)) {
- ++count;
- } else if (strncmp(buffer, total, sizeof(total) - 1)) {
- fprintf(stderr, "WARNING: Parse error: %s", buffer);
- }
- }
- pclose(fp);
- if ((count != 7) && (count != 8)) {
- fprintf(stderr, "count=%d\n", count);
- }
- EXPECT_TRUE(count == 7 || count == 8);
- }
- }
- snprintf(command, sizeof(command), "rm -rf %s", buf);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_suffix) {
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- char tmp_out_dir[sizeof(tmp_out_dir_form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- static const char logcat_cmd[] = logcat_executable
- " -b radio -b events -b system -b main"
- " -d -f %s/log.txt -n 10 -r 1";
- char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd)];
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (!ret) {
- snprintf(command, sizeof(command), "ls %s 2>/dev/null", tmp_out_dir);
-
- FILE* fp;
- EXPECT_TRUE(NULL != (fp = popen(command, "r")));
- char buffer[BIG_BUFFER];
- int log_file_count = 0;
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- static const char rotated_log_filename_prefix[] = "log.txt.";
- static const size_t rotated_log_filename_prefix_len =
- strlen(rotated_log_filename_prefix);
- static const char log_filename[] = "log.txt";
-
- if (!strncmp(buffer, rotated_log_filename_prefix,
- rotated_log_filename_prefix_len)) {
- // Rotated file should have form log.txt.##
- char* rotated_log_filename_suffix =
- buffer + rotated_log_filename_prefix_len;
- char* endptr;
- const long int suffix_value =
- strtol(rotated_log_filename_suffix, &endptr, 10);
- EXPECT_EQ(rotated_log_filename_suffix + 2, endptr);
- EXPECT_LE(suffix_value, 10);
- EXPECT_GT(suffix_value, 0);
- ++log_file_count;
- continue;
- }
-
- if (!strncmp(buffer, log_filename, strlen(log_filename))) {
- ++log_file_count;
- continue;
- }
-
- fprintf(stderr, "ERROR: Unexpected file: %s", buffer);
- ADD_FAILURE();
- }
- pclose(fp);
- EXPECT_EQ(log_file_count, 11);
- }
- snprintf(command, sizeof(command), "rm -rf %s", tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_continue) {
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- char tmp_out_dir[sizeof(tmp_out_dir_form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- static const char log_filename[] = "log.txt";
- static const char logcat_cmd[] =
- logcat_executable " -b all -v nsec -d -f %s/%s -n 256 -r 1024";
- static const char cleanup_cmd[] = "rm -rf %s";
- char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) + sizeof(log_filename)];
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- FILE* fp;
- snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, log_filename);
- EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
- if (!fp) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- char* line = NULL;
- char* last_line =
- NULL; // this line is allowed to stutter, one-line overlap
- char* second_last_line = NULL; // should never stutter
- char* first_line = NULL; // help diagnose failure?
- size_t len = 0;
- while (getline(&line, &len, fp) != -1) {
- if (!first_line) {
- first_line = line;
- line = NULL;
- continue;
- }
- free(second_last_line);
- second_last_line = last_line;
- last_line = line;
- line = NULL;
- }
- fclose(fp);
- free(line);
- if (second_last_line == NULL) {
- fprintf(stderr, "No second to last line, using last, test may fail\n");
- second_last_line = last_line;
- last_line = NULL;
- }
- free(last_line);
- EXPECT_TRUE(NULL != second_last_line);
- if (!second_last_line) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- free(first_line);
- return;
- }
- // re-run the command, it should only add a few lines more content if it
- // continues where it left off.
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- free(second_last_line);
- free(first_line);
- return;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- EXPECT_NE(nullptr, dir);
- if (!dir) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- free(second_last_line);
- free(first_line);
- return;
- }
- struct dirent* entry;
- unsigned count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- snprintf(command, sizeof(command), "%s/%s", tmp_out_dir, entry->d_name);
- EXPECT_TRUE(NULL != ((fp = fopen(command, "r"))));
- if (!fp) {
- fprintf(stderr, "%s ?\n", command);
- continue;
- }
- line = NULL;
- size_t number = 0;
- while (getline(&line, &len, fp) != -1) {
- ++number;
- if (!strcmp(line, second_last_line)) {
- EXPECT_TRUE(++count <= 1);
- fprintf(stderr, "%s(%zu):\n", entry->d_name, number);
- }
- }
- fclose(fp);
- free(line);
- unlink(command);
- }
- if (count > 1) {
- char* brk = strpbrk(second_last_line, "\r\n");
- if (!brk) brk = second_last_line + strlen(second_last_line);
- fprintf(stderr, "\"%.*s\" occurred %u times\n",
- (int)(brk - second_last_line), second_last_line, count);
- if (first_line) {
- brk = strpbrk(first_line, "\r\n");
- if (!brk) brk = first_line + strlen(first_line);
- fprintf(stderr, "\"%.*s\" was first line, fault?\n",
- (int)(brk - first_line), first_line);
- }
- }
- free(second_last_line);
- free(first_line);
-
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_clear) {
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- char tmp_out_dir[sizeof(tmp_out_dir_form)];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- static const char log_filename[] = "log.txt";
- static const unsigned num_val = 32;
- static const char logcat_cmd[] =
- logcat_executable " -b all -d -f %s/%s -n %d -r 1";
- static const char clear_cmd[] = " -c";
- static const char cleanup_cmd[] = "rm -rf %s";
- char command[sizeof(tmp_out_dir) + sizeof(logcat_cmd) +
- sizeof(log_filename) + sizeof(clear_cmd) + 32];
-
- // Run command with all data
- {
- snprintf(command, sizeof(command) - sizeof(clear_cmd), logcat_cmd,
- tmp_out_dir, log_filename, num_val);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- EXPECT_NE(nullptr, dir);
- if (!dir) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- struct dirent* entry;
- unsigned count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- ++count;
- }
- EXPECT_EQ(count, num_val + 1);
- }
-
- {
- // Now with -c option tacked onto the end
- strcat(command, clear_cmd);
-
- int ret;
- EXPECT_FALSE(IsFalse(ret = system(command), command));
- if (ret) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(system(command));
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- EXPECT_NE(nullptr, dir);
- if (!dir) {
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
- return;
- }
- struct dirent* entry;
- unsigned count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- fprintf(stderr, "Found %s/%s!!!\n", tmp_out_dir, entry->d_name);
- ++count;
- }
- EXPECT_EQ(count, 0U);
- }
-
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-static int logrotate_count_id(const char* logcat_cmd, const char* tmp_out_dir) {
- static const char log_filename[] = "log.txt";
- char command[strlen(tmp_out_dir) + strlen(logcat_cmd) +
- strlen(log_filename) + 32];
-
- snprintf(command, sizeof(command), logcat_cmd, tmp_out_dir, log_filename);
-
- int ret = system(command);
- if (ret) {
- fprintf(stderr, "system(\"%s\")=%d", command, ret);
- return -1;
- }
- std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(tmp_out_dir),
- closedir);
- if (!dir) {
- fprintf(stderr, "opendir(\"%s\") failed", tmp_out_dir);
- return -1;
- }
- struct dirent* entry;
- int count = 0;
- while ((entry = readdir(dir.get()))) {
- if (strncmp(entry->d_name, log_filename, sizeof(log_filename) - 1)) {
- continue;
- }
- ++count;
- }
- return count;
-}
-
-TEST(logcat, logrotate_id) {
- static const char logcat_cmd[] =
- logcat_executable " -b all -d -f %s/%s -n 32 -r 1 --id=test";
- static const char logcat_short_cmd[] =
- logcat_executable " -b all -t 10 -f %s/%s -n 32 -r 1 --id=test";
- static const char tmp_out_dir_form[] =
- "/data/local/tmp/logcat.logrotate.XXXXXX";
- static const char log_filename[] = "log.txt";
- char tmp_out_dir[strlen(tmp_out_dir_form) + 1];
- ASSERT_TRUE(NULL != mkdtemp(strcpy(tmp_out_dir, tmp_out_dir_form)));
-
- EXPECT_EQ(logrotate_count_id(logcat_cmd, tmp_out_dir), 34);
- EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
-
- char id_file[strlen(tmp_out_dir_form) + strlen(log_filename) + 5];
- snprintf(id_file, sizeof(id_file), "%s/%s.id", tmp_out_dir, log_filename);
- if (getuid() != 0) {
- chmod(id_file, 0);
- EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
- }
- unlink(id_file);
- EXPECT_EQ(logrotate_count_id(logcat_short_cmd, tmp_out_dir), 34);
-
- FILE* fp = fopen(id_file, "w");
- if (fp) {
- fprintf(fp, "not_a_test");
- fclose(fp);
- }
- if (getuid() != 0) {
- chmod(id_file,
- 0); // API to preserve content even with signature change
- ASSERT_EQ(34, logrotate_count_id(logcat_short_cmd, tmp_out_dir));
- chmod(id_file, 0600);
- }
-
- int new_signature;
- EXPECT_GE(
- (new_signature = logrotate_count_id(logcat_short_cmd, tmp_out_dir)), 2);
- EXPECT_LT(new_signature, 34);
-
- static const char cleanup_cmd[] = "rm -rf %s";
- char command[strlen(cleanup_cmd) + strlen(tmp_out_dir_form)];
- snprintf(command, sizeof(command), cleanup_cmd, tmp_out_dir);
- EXPECT_FALSE(IsFalse(system(command), command));
-}
-
-TEST(logcat, logrotate_nodir) {
- // expect logcat to error out on writing content and not exit(0) for nodir
- static const char command[] = logcat_executable
- " -b all -d"
- " -f /das/nein/gerfingerpoken/logcat/log.txt"
- " -n 256 -r 1024";
- EXPECT_FALSE(IsFalse(0 == system(command), command));
-}
-
-#ifndef logcat
-static void caught_blocking_clear(int signum) {
- unsigned long long v = 0xDEADBEEFA55C0000ULL;
-
- v += getpid() & 0xFFFF;
- if (signum == 0) ++v;
-
- LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
-}
-
-TEST(logcat, blocking_clear) {
- FILE* fp;
- unsigned long long v = 0xDEADBEEFA55C0000ULL;
-
- pid_t pid = getpid();
-
- v += pid & 0xFFFF;
-
- // This test is racey; an event occurs between clear and dump.
- // We accept that we will get a false positive, but never a false negative.
- ASSERT_TRUE(
- NULL !=
- (fp = popen("( trap exit HUP QUIT INT PIPE KILL ; sleep 6; echo DONE )&"
- " logcat -b events -c 2>&1 ;"
- " logcat -b events -g 2>&1 ;"
- " logcat -v brief -b events 2>&1",
- "r")));
-
- char buffer[BIG_BUFFER];
-
- int count = 0;
- int minus_g = 0;
-
- int signals = 0;
-
- signal(SIGALRM, caught_blocking_clear);
- alarm(2);
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(buffer, "clearLog: ", strlen("clearLog: "))) {
- fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
- count = signals = 1;
- break;
- }
- if (!strncmp(buffer, "failed to clear", strlen("failed to clear"))) {
- fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
- count = signals = 1;
- break;
- }
-
- if (!strncmp(buffer, "DONE", 4)) {
- break;
- }
-
- int size, consumed, max, payload;
- char size_mult[4], consumed_mult[4];
- size = consumed = max = payload = 0;
- if (6 == sscanf(buffer,
- "events: ring buffer is %d %3s (%d %3s consumed),"
- " max entry is %d B, max payload is %d B",
- &size, size_mult, &consumed, consumed_mult, &max, &payload)) {
- long full_size = size, full_consumed = consumed;
-
- switch (size_mult[0]) {
- case 'G':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_size *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- }
- switch (consumed_mult[0]) {
- case 'G':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'M':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'K':
- full_consumed *= 1024;
- FALLTHROUGH_INTENDED;
- case 'B':
- break;
- }
- EXPECT_GT(full_size, full_consumed);
- EXPECT_GT(full_size, max);
- EXPECT_GT(max, payload);
- EXPECT_GT(max, full_consumed);
-
- ++minus_g;
- continue;
- }
-
- ++count;
-
- int p;
- unsigned long long l;
-
- if ((2 != sscanf(buffer, "I/[0] ( %u): %lld", &p, &l)) || (p != pid)) {
- continue;
- }
-
- if (l == v) {
- if (count > 1) {
- fprintf(stderr, "WARNING: Possible false positive\n");
- }
- ++signals;
- break;
- }
- }
- alarm(0);
- signal(SIGALRM, SIG_DFL);
-
- // Generate SIGPIPE
- fclose(fp);
- caught_blocking_clear(0);
-
- pclose(fp);
-
- EXPECT_GE(count, 1);
- EXPECT_EQ(minus_g, 1);
-
- EXPECT_EQ(signals, 1);
-}
-#endif
-
-static bool get_prune_rules(char** list) {
- FILE* fp = popen(logcat_executable " -p 2>/dev/null", "r");
- if (fp == NULL) {
- fprintf(stderr, "ERROR: logcat -p 2>/dev/null\n");
- return false;
- }
-
- char buffer[BIG_BUFFER];
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- char* hold = *list;
- char* buf = buffer;
- while (isspace(*buf)) {
- ++buf;
- }
- char* end = buf + strlen(buf);
- while (isspace(*--end) && (end >= buf)) {
- *end = '\0';
- }
- if (end < buf) {
- continue;
- }
- if (hold) {
- asprintf(list, "%s %s", hold, buf);
- free(hold);
- } else {
- asprintf(list, "%s", buf);
- }
- }
- pclose(fp);
- return *list != NULL;
-}
-
-static bool set_prune_rules(const char* list) {
- char buffer[BIG_BUFFER];
- snprintf(buffer, sizeof(buffer), logcat_executable " -P '%s' 2>&1",
- list ? list : "");
- FILE* fp = popen(buffer, "r");
- if (fp == NULL) {
- fprintf(stderr, "ERROR: %s\n", buffer);
- return false;
- }
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- char* buf = buffer;
- while (isspace(*buf)) {
- ++buf;
- }
- char* end = buf + strlen(buf);
- while ((end > buf) && isspace(*--end)) {
- *end = '\0';
- }
- if (end <= buf) {
- continue;
- }
- fprintf(stderr, "%s\n", buf);
- pclose(fp);
- return false;
- }
- return pclose(fp) == 0;
-}
-
-TEST(logcat, prune_rules_adjust) {
- char* list = NULL;
- char* adjust = NULL;
-
- get_prune_rules(&list);
-
- static const char adjustment[] = "~! 300/20 300/25 2000 ~1000/5 ~1000/30";
- ASSERT_EQ(true, set_prune_rules(adjustment));
- ASSERT_EQ(true, get_prune_rules(&adjust));
- EXPECT_STREQ(adjustment, adjust);
- free(adjust);
- adjust = NULL;
-
- static const char adjustment2[] = "300/20 300/21 2000 ~1000";
- ASSERT_EQ(true, set_prune_rules(adjustment2));
- ASSERT_EQ(true, get_prune_rules(&adjust));
- EXPECT_STREQ(adjustment2, adjust);
- free(adjust);
- adjust = NULL;
-
- ASSERT_EQ(true, set_prune_rules(list));
- get_prune_rules(&adjust);
- EXPECT_STREQ(list ? list : "", adjust ? adjust : "");
- free(adjust);
- adjust = NULL;
-
- free(list);
- list = NULL;
-}
-
-TEST(logcat, regex) {
- FILE* fp;
- int count = 0;
-
- char buffer[BIG_BUFFER];
-#define logcat_regex_prefix logcat_executable "_test"
-
- snprintf(buffer, sizeof(buffer),
- logcat_executable " --pid %d -d -e " logcat_regex_prefix "_a+b",
- getpid());
-
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_ab"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_b"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_aaaab"));
- LOG_FAILURE_RETRY(__android_log_print(ANDROID_LOG_WARN, logcat_regex_prefix,
- logcat_regex_prefix "_aaaa"));
- // Let the logs settle
- rest();
-
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
-
- EXPECT_TRUE(strstr(buffer, logcat_regex_prefix "_") != NULL);
-
- count++;
- }
-
- pclose(fp);
-
- ASSERT_EQ(2, count);
-}
-
-TEST(logcat, maxcount) {
- FILE* fp;
- int count = 0;
-
- char buffer[BIG_BUFFER];
-
- snprintf(buffer, sizeof(buffer),
- logcat_executable " --pid %d -d --max-count 3", getpid());
-
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
- LOG_FAILURE_RETRY(
- __android_log_print(ANDROID_LOG_WARN, "logcat_test", "logcat_test"));
-
- rest();
-
- ASSERT_TRUE(NULL != (fp = popen(buffer, "r")));
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- if (!strncmp(begin, buffer, sizeof(begin) - 1)) {
- continue;
- }
-
- count++;
- }
-
- pclose(fp);
-
- ASSERT_EQ(3, count);
-}
-
-static bool End_to_End(const char* tag, const char* fmt, ...)
-#if defined(__GNUC__)
- __attribute__((__format__(printf, 2, 3)))
-#endif
- ;
-
-static bool End_to_End(const char* tag, const char* fmt, ...) {
- FILE* fp = popen(logcat_executable " -v brief -b events -v descriptive -t 100 2>/dev/null", "r");
- if (!fp) {
- fprintf(stderr, "End_to_End: popen failed");
- return false;
- }
-
- char buffer[BIG_BUFFER];
- va_list ap;
-
- va_start(ap, fmt);
- vsnprintf(buffer, sizeof(buffer), fmt, ap);
- va_end(ap);
-
- char* str = NULL;
- asprintf(&str, "I/%s ( %%d):%%c%s%%c", tag, buffer);
- std::string expect(str);
- free(str);
-
- int count = 0;
- pid_t pid = getpid();
- std::string lastMatch;
- int maxMatch = 1;
- while (fgets(buffer, sizeof(buffer), fp)) {
- char space;
- char newline;
- int p;
- int ret = sscanf(buffer, expect.c_str(), &p, &space, &newline);
- if ((ret == 3) && (p == pid) && (space == ' ') && (newline == '\n')) {
- ++count;
- } else if ((ret >= maxMatch) && (p == pid) && (count == 0)) {
- lastMatch = buffer;
- maxMatch = ret;
- }
- }
-
- pclose(fp);
-
- if ((count == 0) && (lastMatch.length() > 0)) {
- // Help us pinpoint where things went wrong ...
- fprintf(stderr, "Closest match for\n %s\n is\n %s",
- expect.c_str(), lastMatch.c_str());
- } else if (count > 3) {
- fprintf(stderr, "Too many matches (%d) for %s\n", count, expect.c_str());
- }
-
- // Three different known tests, we can see pollution from the others
- return count && (count <= 3);
-}
-
-TEST(logcat, descriptive) {
- struct tag {
- uint32_t tagNo;
- const char* tagStr;
- };
- int ret;
-
- {
- static const struct tag hhgtg = { 42, "answer" };
- android_log_event_list ctx(hhgtg.tagNo);
- static const char theAnswer[] = "what is five by seven";
- ctx << theAnswer;
- // crafted to rest at least once after, and rest between retries.
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(
- End_to_End(hhgtg.tagStr, "to life the universe etc=%s", theAnswer));
- }
-
- {
- static const struct tag sync = { 2720, "sync" };
- static const char id[] = logcat_executable ".descriptive-sync";
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << id << (int32_t)42 << (int32_t)-1 << (int32_t)0;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr,
- "[id=%s,event=42,source=-1,account=0]", id));
- }
-
- // Partial match to description
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << id << (int32_t)43 << (int64_t)-1 << (int32_t)0;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "[id=%s,event=43,-1,0]", id));
- }
-
- // Negative Test of End_to_End, ensure it is working
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << id << (int32_t)44 << (int32_t)-1 << (int64_t)0;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- fprintf(stderr, "Expect a \"Closest match\" message\n");
- EXPECT_FALSE(End_to_End(
- sync.tagStr, "[id=%s,event=44,source=-1,account=0]", id));
- }
- }
-
- {
- static const struct tag sync = { 2747, "contacts_aggregation" };
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint64_t)30 << (int32_t)2;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(
- End_to_End(sync.tagStr, "[aggregation time=30ms,count=2]"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint64_t)31570 << (int32_t)911;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(
- End_to_End(sync.tagStr, "[aggregation time=31.57s,count=911]"));
- }
- }
-
- {
- static const struct tag sync = { 75000, "sqlite_mem_alarm_current" };
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)512;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=512B"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)3072;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=3KB"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)2097152;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=2MB"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)2097153;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=2097153B"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)1073741824;
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=1GB"));
- }
-
- {
- android_log_event_list ctx(sync.tagNo);
- ctx << (uint32_t)3221225472; // 3MB, but on purpose overflowed
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, "current=-1GB"));
- }
- }
-
- {
- static const struct tag sync = { 27501, "notification_panel_hidden" };
- android_log_event_list ctx(sync.tagNo);
- for (ret = -EBUSY; ret == -EBUSY; rest()) ret = ctx.write();
- EXPECT_GE(ret, 0);
- EXPECT_TRUE(End_to_End(sync.tagStr, ""));
- }
-}
-
-static bool reportedSecurity(const char* command) {
- FILE* fp = popen(command, "r");
- if (!fp) return true;
-
- std::string ret;
- bool val = android::base::ReadFdToString(fileno(fp), &ret);
- pclose(fp);
-
- if (!val) return true;
- return std::string::npos != ret.find("'security'");
-}
-
-TEST(logcat, security) {
- EXPECT_FALSE(reportedSecurity(logcat_executable " -b all -g 2>&1"));
- EXPECT_TRUE(reportedSecurity(logcat_executable " -b security -g 2>&1"));
- EXPECT_TRUE(reportedSecurity(logcat_executable " -b security -c 2>&1"));
- EXPECT_TRUE(
- reportedSecurity(logcat_executable " -b security -G 256K 2>&1"));
-}
-
-static size_t commandOutputSize(const char* command) {
- FILE* fp = popen(command, "r");
- if (!fp) return 0;
-
- std::string ret;
- if (!android::base::ReadFdToString(fileno(fp), &ret)) return 0;
- if (pclose(fp) != 0) return 0;
-
- return ret.size();
-}
-
-TEST(logcat, help) {
- size_t logcatHelpTextSize = commandOutputSize(logcat_executable " -h 2>&1");
- EXPECT_GT(logcatHelpTextSize, 4096UL);
- size_t logcatLastHelpTextSize =
- commandOutputSize(logcat_executable " -L -h 2>&1");
-#ifdef USING_LOGCAT_EXECUTABLE_DEFAULT // logcat and liblogcat
- EXPECT_EQ(logcatHelpTextSize, logcatLastHelpTextSize);
-#else
- // logcatd -L -h prints the help twice, as designed.
- EXPECT_EQ(logcatHelpTextSize * 2, logcatLastHelpTextSize);
-#endif
-}
-
-TEST(logcat, invalid_buffer) {
- FILE* fp = popen("logcat -b foo 2>&1", "r");
- ASSERT_NE(nullptr, fp);
- std::string output;
- ASSERT_TRUE(android::base::ReadFdToString(fileno(fp), &output));
- pclose(fp);
-
- ASSERT_TRUE(android::base::StartsWith(output, "unknown buffer foo\n"));
-}
-
-static void SniffUid(const std::string& line, uid_t& uid) {
- auto uid_regex = std::regex{"\\S+\\s+\\S+\\s+(\\S+).*"};
-
- auto trimmed_line = android::base::Trim(line);
-
- std::smatch match_results;
- ASSERT_TRUE(std::regex_match(trimmed_line, match_results, uid_regex))
- << "Unable to find UID in line '" << trimmed_line << "'";
- auto uid_string = match_results[1];
- if (!android::base::ParseUint(uid_string, &uid)) {
- auto pwd = getpwnam(uid_string.str().c_str());
- ASSERT_NE(nullptr, pwd) << "uid '" << uid_string << "' in line '" << trimmed_line << "'";
- uid = pwd->pw_uid;
- }
-}
-
-static void UidsInLog(std::optional<std::vector<uid_t>> filter_uid, std::map<uid_t, size_t>& uids) {
- std::string command;
- if (filter_uid) {
- std::vector<std::string> uid_strings;
- for (const auto& uid : *filter_uid) {
- uid_strings.emplace_back(std::to_string(uid));
- }
- command = android::base::StringPrintf(logcat_executable
- " -v uid -b all -d 2>/dev/null --uid=%s",
- android::base::Join(uid_strings, ",").c_str());
- } else {
- command = logcat_executable " -v uid -b all -d 2>/dev/null";
- }
- auto fp = std::unique_ptr<FILE, decltype(&pclose)>(popen(command.c_str(), "r"), pclose);
- ASSERT_NE(nullptr, fp);
-
- char buffer[BIG_BUFFER];
- while (fgets(buffer, sizeof(buffer), fp.get())) {
- // Ignore dividers, e.g. '--------- beginning of radio'
- if (android::base::StartsWith(buffer, "---------")) {
- continue;
- }
- uid_t uid;
- SniffUid(buffer, uid);
- uids[uid]++;
- }
-}
-
-static std::vector<uid_t> TopTwoInMap(const std::map<uid_t, size_t>& uids) {
- std::pair<uid_t, size_t> top = {0, 0};
- std::pair<uid_t, size_t> second = {0, 0};
- for (const auto& [uid, count] : uids) {
- if (count > top.second) {
- top = second;
- top = {uid, count};
- } else if (count > second.second) {
- second = {uid, count};
- }
- }
- return {top.first, second.first};
-}
-
-TEST(logcat, uid_filter) {
- std::map<uid_t, size_t> uids;
- UidsInLog({}, uids);
-
- ASSERT_GT(uids.size(), 2U);
- auto top_uids = TopTwoInMap(uids);
-
- // Test filtering with --uid=<top uid>
- std::map<uid_t, size_t> uids_only_top;
- std::vector<uid_t> top_uid = {top_uids[0]};
- UidsInLog(top_uid, uids_only_top);
-
- EXPECT_EQ(1U, uids_only_top.size());
-
- // Test filtering with --uid=<top uid>,<2nd top uid>
- std::map<uid_t, size_t> uids_only_top2;
- std::vector<uid_t> top2_uids = {top_uids[0], top_uids[1]};
- UidsInLog(top2_uids, uids_only_top2);
-
- EXPECT_EQ(2U, uids_only_top2.size());
-}
diff --git a/logcat/tests/logcatd_test.cpp b/logcat/tests/logcatd_test.cpp
deleted file mode 100644
index bb7534e..0000000
--- a/logcat/tests/logcatd_test.cpp
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define logcat logcatd
-#define logcat_executable "logcatd"
-
-#include "logcat_test.cpp"
diff --git a/logd/.clang-format b/logd/.clang-format
deleted file mode 120000
index 1af4f51..0000000
--- a/logd/.clang-format
+++ /dev/null
@@ -1 +0,0 @@
-../.clang-format-4
\ No newline at end of file
diff --git a/logd/Android.bp b/logd/Android.bp
deleted file mode 100644
index 7f67ab0..0000000
--- a/logd/Android.bp
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright (C) 2017 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.
-
-// This is what we want to do:
-// event_logtags = $(shell
-// sed -n
-// "s/^\([0-9]*\)[ \t]*$1[ \t].*/-D`echo $1 | tr a-z A-Z`_LOG_TAG=\1/p"
-// $(LOCAL_PATH)/$2/event.logtags)
-// event_flag := $(call event_logtags,auditd)
-// event_flag += $(call event_logtags,logd)
-// event_flag += $(call event_logtags,tag_def)
-// so make sure we do not regret hard-coding it as follows:
-event_flag = [
- "-DAUDITD_LOG_TAG=1003",
- "-DCHATTY_LOG_TAG=1004",
- "-DTAG_DEF_LOG_TAG=1005",
- "-DLIBLOG_LOG_TAG=1006",
-]
-
-cc_defaults {
- name: "logd_defaults",
-
- shared_libs: [
- "libbase",
- "libz",
- ],
- static_libs: ["libzstd"],
- cflags: [
- "-Wextra",
- "-Wthread-safety",
- ] + event_flag,
-
- lto: {
- thin: true,
- },
- cpp_std: "experimental",
-}
-
-cc_library_static {
- name: "liblogd",
- defaults: ["logd_defaults"],
- host_supported: true,
- srcs: [
- "ChattyLogBuffer.cpp",
- "CompressionEngine.cpp",
- "LogReaderList.cpp",
- "LogReaderThread.cpp",
- "LogBufferElement.cpp",
- "LogSize.cpp",
- "LogStatistics.cpp",
- "LogTags.cpp",
- "PruneList.cpp",
- "SerializedFlushToState.cpp",
- "SerializedLogBuffer.cpp",
- "SerializedLogChunk.cpp",
- "SimpleLogBuffer.cpp",
- ],
- logtags: ["event.logtags"],
-
- export_include_dirs: ["."],
-}
-
-cc_binary {
- name: "logd",
- defaults: ["logd_defaults"],
- init_rc: ["logd.rc"],
-
- srcs: [
- "main.cpp",
- "LogPermissions.cpp",
- "CommandListener.cpp",
- "LogListener.cpp",
- "LogReader.cpp",
- "LogAudit.cpp",
- "LogKlog.cpp",
- "libaudit.cpp",
- ],
-
- static_libs: [
- "liblog",
- "liblogd",
- ],
-
- shared_libs: [
- "libsysutils",
- "libcutils",
- "libpackagelistparser",
- "libprocessgroup",
- "libcap",
- ],
-}
-
-cc_binary {
- name: "auditctl",
-
- srcs: [
- "auditctl.cpp",
- "libaudit.cpp",
- ],
-
- shared_libs: ["libbase"],
-
- cflags: [
- "-Wextra",
- ],
-}
-
-prebuilt_etc {
- name: "logtagd.rc",
- src: "logtagd.rc",
- sub_dir: "init",
-}
-
-// -----------------------------------------------------------------------------
-// Unit tests.
-// -----------------------------------------------------------------------------
-
-cc_defaults {
- name: "logd-unit-test-defaults",
-
- cflags: [
- "-fstack-protector-all",
- "-g",
- "-Wall",
- "-Wextra",
- "-Werror",
- "-fno-builtin",
- ] + event_flag,
-
- srcs: [
- "ChattyLogBufferTest.cpp",
- "logd_test.cpp",
- "LogBufferTest.cpp",
- "SerializedLogChunkTest.cpp",
- "SerializedFlushToStateTest.cpp",
- ],
-
- static_libs: [
- "libbase",
- "libcutils",
- "liblog",
- "liblogd",
- "libselinux",
- "libz",
- "libzstd",
- ],
-}
-
-// Build tests for the logger. Run with:
-// adb shell /data/nativetest/logd-unit-tests/logd-unit-tests
-cc_test {
- name: "logd-unit-tests",
- host_supported: true,
- defaults: ["logd-unit-test-defaults"],
-}
-
-cc_test {
- name: "CtsLogdTestCases",
- defaults: ["logd-unit-test-defaults"],
- multilib: {
- lib32: {
- suffix: "32",
- },
- lib64: {
- suffix: "64",
- },
- },
- test_suites: [
- "cts",
- "device-tests",
- "vts10",
- ],
-}
-
-cc_binary {
- name: "replay_messages",
- defaults: ["logd_defaults"],
- host_supported: true,
-
- srcs: [
- "ReplayMessages.cpp",
- ],
-
- static_libs: [
- "libbase",
- "libcutils",
- "liblog",
- "liblogd",
- "libselinux",
- "libz",
- "libzstd",
- ],
-}
diff --git a/logd/AndroidTest.xml b/logd/AndroidTest.xml
deleted file mode 100644
index a25dc44..0000000
--- a/logd/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for CTS Logging Daemon test cases">
- <option name="test-suite-tag" value="cts" />
- <option name="config-descriptor:metadata" key="component" value="systems" />
- <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
- <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
- <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
- <option name="cleanup" value="true" />
- <option name="push" value="CtsLogdTestCases->/data/local/tmp/CtsLogdTestCases" />
- <option name="append-bitness" value="true" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="CtsLogdTestCases" />
- <option name="runtime-hint" value="65s" />
- </test>
-</configuration>
diff --git a/logd/ChattyLogBuffer.cpp b/logd/ChattyLogBuffer.cpp
deleted file mode 100644
index fd183e4..0000000
--- a/logd/ChattyLogBuffer.cpp
+++ /dev/null
@@ -1,619 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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.
- */
-// for manual checking of stale entries during ChattyLogBuffer::erase()
-//#define DEBUG_CHECK_FOR_STALE_ENTRIES
-
-#include "ChattyLogBuffer.h"
-
-#include <ctype.h>
-#include <endian.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/cdefs.h>
-#include <sys/user.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <limits>
-#include <unordered_map>
-#include <utility>
-
-#include <private/android_logger.h>
-
-#include "LogUtils.h"
-
-#ifndef __predict_false
-#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
-#endif
-
-ChattyLogBuffer::ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
- LogStatistics* stats)
- : SimpleLogBuffer(reader_list, tags, stats), prune_(prune) {}
-
-ChattyLogBuffer::~ChattyLogBuffer() {}
-
-enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
-
-static enum match_type Identical(const LogBufferElement& elem, const LogBufferElement& last) {
- ssize_t lenl = elem.msg_len();
- if (lenl <= 0) return DIFFERENT; // value if this represents a chatty elem
- ssize_t lenr = last.msg_len();
- if (lenr <= 0) return DIFFERENT; // value if this represents a chatty elem
- if (elem.uid() != last.uid()) return DIFFERENT;
- if (elem.pid() != last.pid()) return DIFFERENT;
- if (elem.tid() != last.tid()) return DIFFERENT;
-
- // last is more than a minute old, stop squashing identical messages
- if (elem.realtime().nsec() > (last.realtime().nsec() + 60 * NS_PER_SEC)) return DIFFERENT;
-
- // Identical message
- const char* msgl = elem.msg();
- const char* msgr = last.msg();
- if (lenl == lenr) {
- if (!fastcmp<memcmp>(msgl, msgr, lenl)) return SAME;
- // liblog tagged messages (content gets summed)
- if (elem.log_id() == LOG_ID_EVENTS && lenl == sizeof(android_log_event_int_t) &&
- !fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_int_t) - sizeof(int32_t)) &&
- elem.GetTag() == LIBLOG_LOG_TAG) {
- return SAME_LIBLOG;
- }
- }
-
- // audit message (except sequence number) identical?
- if (IsBinary(last.log_id()) &&
- lenl > static_cast<ssize_t>(sizeof(android_log_event_string_t)) &&
- lenr > static_cast<ssize_t>(sizeof(android_log_event_string_t))) {
- if (fastcmp<memcmp>(msgl, msgr, sizeof(android_log_event_string_t) - sizeof(int32_t))) {
- return DIFFERENT;
- }
- msgl += sizeof(android_log_event_string_t);
- lenl -= sizeof(android_log_event_string_t);
- msgr += sizeof(android_log_event_string_t);
- lenr -= sizeof(android_log_event_string_t);
- }
- static const char avc[] = "): avc: ";
- const char* avcl = android::strnstr(msgl, lenl, avc);
- if (!avcl) return DIFFERENT;
- lenl -= avcl - msgl;
- const char* avcr = android::strnstr(msgr, lenr, avc);
- if (!avcr) return DIFFERENT;
- lenr -= avcr - msgr;
- if (lenl != lenr) return DIFFERENT;
- if (fastcmp<memcmp>(avcl + strlen(avc), avcr + strlen(avc), lenl - strlen(avc))) {
- return DIFFERENT;
- }
- return SAME;
-}
-
-void ChattyLogBuffer::LogInternal(LogBufferElement&& elem) {
- // b/137093665: don't coalesce security messages.
- if (elem.log_id() == LOG_ID_SECURITY) {
- SimpleLogBuffer::LogInternal(std::move(elem));
- return;
- }
- int log_id = elem.log_id();
-
- // Initialize last_logged_elements_ to a copy of elem if logging the first element for a log_id.
- if (!last_logged_elements_[log_id]) {
- last_logged_elements_[log_id].emplace(elem);
- SimpleLogBuffer::LogInternal(std::move(elem));
- return;
- }
-
- LogBufferElement& current_last = *last_logged_elements_[log_id];
- enum match_type match = Identical(elem, current_last);
-
- if (match == DIFFERENT) {
- if (duplicate_elements_[log_id]) {
- // If we previously had 3+ identical messages, log the chatty message.
- if (duplicate_elements_[log_id]->dropped_count() > 0) {
- SimpleLogBuffer::LogInternal(std::move(*duplicate_elements_[log_id]));
- }
- duplicate_elements_[log_id].reset();
- // Log the saved copy of the last identical message seen.
- SimpleLogBuffer::LogInternal(std::move(current_last));
- }
- last_logged_elements_[log_id].emplace(elem);
- SimpleLogBuffer::LogInternal(std::move(elem));
- return;
- }
-
- // 2 identical message: set duplicate_elements_ appropriately.
- if (!duplicate_elements_[log_id]) {
- duplicate_elements_[log_id].emplace(std::move(current_last));
- last_logged_elements_[log_id].emplace(std::move(elem));
- return;
- }
-
- // 3+ identical LIBLOG event messages: coalesce them into last_logged_elements_.
- if (match == SAME_LIBLOG) {
- const android_log_event_int_t* current_last_event =
- reinterpret_cast<const android_log_event_int_t*>(current_last.msg());
- int64_t current_last_count = current_last_event->payload.data;
- android_log_event_int_t* elem_event =
- reinterpret_cast<android_log_event_int_t*>(const_cast<char*>(elem.msg()));
- int64_t elem_count = elem_event->payload.data;
-
- int64_t total = current_last_count + elem_count;
- if (total > std::numeric_limits<int32_t>::max()) {
- SimpleLogBuffer::LogInternal(std::move(current_last));
- last_logged_elements_[log_id].emplace(std::move(elem));
- return;
- }
- stats()->AddTotal(current_last.log_id(), current_last.msg_len());
- elem_event->payload.data = total;
- last_logged_elements_[log_id].emplace(std::move(elem));
- return;
- }
-
- // 3+ identical messages (not LIBLOG) messages: increase the drop count.
- uint16_t dropped_count = duplicate_elements_[log_id]->dropped_count();
- if (dropped_count == std::numeric_limits<uint16_t>::max()) {
- SimpleLogBuffer::LogInternal(std::move(*duplicate_elements_[log_id]));
- dropped_count = 0;
- }
- // We're dropping the current_last log so add its stats to the total.
- stats()->AddTotal(current_last.log_id(), current_last.msg_len());
- // Use current_last for tracking the dropped count to always use the latest timestamp.
- current_last.SetDropped(dropped_count + 1);
- duplicate_elements_[log_id].emplace(std::move(current_last));
- last_logged_elements_[log_id].emplace(std::move(elem));
-}
-
-LogBufferElementCollection::iterator ChattyLogBuffer::Erase(LogBufferElementCollection::iterator it,
- bool coalesce) {
- LogBufferElement& element = *it;
- log_id_t id = element.log_id();
-
- // Remove iterator references in the various lists that will become stale
- // after the element is erased from the main logging list.
-
- { // start of scope for found iterator
- int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.GetTag() : element.uid();
- LogBufferIteratorMap::iterator found = mLastWorst[id].find(key);
- if ((found != mLastWorst[id].end()) && (it == found->second)) {
- mLastWorst[id].erase(found);
- }
- }
-
- { // start of scope for pid found iterator
- // element->uid() may not be AID_SYSTEM for next-best-watermark.
- // will not assume id != LOG_ID_EVENTS or LOG_ID_SECURITY for KISS and
- // long term code stability, find() check should be fast for those ids.
- LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(element.pid());
- if (found != mLastWorstPidOfSystem[id].end() && it == found->second) {
- mLastWorstPidOfSystem[id].erase(found);
- }
- }
-
-#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
- LogBufferElementCollection::iterator bad = it;
- int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element->GetTag() : element->uid();
-#endif
-
- if (coalesce) {
- stats()->Erase(element.ToLogStatisticsElement());
- } else {
- stats()->Subtract(element.ToLogStatisticsElement());
- }
-
- it = SimpleLogBuffer::Erase(it);
-
-#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
- log_id_for_each(i) {
- for (auto b : mLastWorst[i]) {
- if (bad == b.second) {
- LOG(ERROR) << StringPrintf("stale mLastWorst[%d] key=%d mykey=%d", i, b.first, key);
- }
- }
- for (auto b : mLastWorstPidOfSystem[i]) {
- if (bad == b.second) {
- LOG(ERROR) << StringPrintf("stale mLastWorstPidOfSystem[%d] pid=%d", i, b.first);
- }
- }
- }
-#endif
- return it;
-}
-
-// Define a temporary mechanism to report the last LogBufferElement pointer
-// for the specified uid, pid and tid. Used below to help merge-sort when
-// pruning for worst UID.
-class LogBufferElementLast {
- typedef std::unordered_map<uint64_t, LogBufferElement*> LogBufferElementMap;
- LogBufferElementMap map;
-
- public:
- bool coalesce(LogBufferElement* element, uint16_t dropped) {
- uint64_t key = LogBufferElementKey(element->uid(), element->pid(), element->tid());
- LogBufferElementMap::iterator it = map.find(key);
- if (it != map.end()) {
- LogBufferElement* found = it->second;
- uint16_t moreDropped = found->dropped_count();
- if ((dropped + moreDropped) > USHRT_MAX) {
- map.erase(it);
- } else {
- found->SetDropped(dropped + moreDropped);
- return true;
- }
- }
- return false;
- }
-
- void add(LogBufferElement* element) {
- uint64_t key = LogBufferElementKey(element->uid(), element->pid(), element->tid());
- map[key] = element;
- }
-
- void clear() { map.clear(); }
-
- void clear(LogBufferElement* element) {
- uint64_t current = element->realtime().nsec() - (EXPIRE_RATELIMIT * NS_PER_SEC);
- for (LogBufferElementMap::iterator it = map.begin(); it != map.end();) {
- LogBufferElement* mapElement = it->second;
- if (mapElement->dropped_count() >= EXPIRE_THRESHOLD &&
- current > mapElement->realtime().nsec()) {
- it = map.erase(it);
- } else {
- ++it;
- }
- }
- }
-
- private:
- uint64_t LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid) {
- return uint64_t(uid) << 32 | uint64_t(pid) << 16 | uint64_t(tid);
- }
-};
-
-// prune "pruneRows" of type "id" from the buffer.
-//
-// This garbage collection task is used to expire log entries. It is called to
-// remove all logs (clear), all UID logs (unprivileged clear), or every
-// 256 or 10% of the total logs (whichever is less) to prune the logs.
-//
-// First there is a prep phase where we discover the reader region lock that
-// acts as a backstop to any pruning activity to stop there and go no further.
-//
-// There are three major pruning loops that follow. All expire from the oldest
-// entries. Since there are multiple log buffers, the Android logging facility
-// will appear to drop entries 'in the middle' when looking at multiple log
-// sources and buffers. This effect is slightly more prominent when we prune
-// the worst offender by logging source. Thus the logs slowly loose content
-// and value as you move back in time. This is preferred since chatty sources
-// invariably move the logs value down faster as less chatty sources would be
-// expired in the noise.
-//
-// The first pass prunes elements that match 3 possible rules:
-// 1) A high priority prune rule, for example ~100/20, which indicates elements from UID 100 and PID
-// 20 should be pruned in this first pass.
-// 2) The default chatty pruning rule, ~!. This rule sums the total size spent on log messages for
-// each UID this log buffer. If the highest sum consumes more than 12.5% of the log buffer, then
-// these elements from that UID are pruned.
-// 3) The default AID_SYSTEM pruning rule, ~1000/!. This rule is a special case to 2), if
-// AID_SYSTEM is the top consumer of the log buffer, then this rule sums the total size spent on
-// log messages for each PID in AID_SYSTEM in this log buffer and prunes elements from the PID
-// with the highest sum.
-// This pass reevaluates the sums for rules 2) and 3) for every log message pruned. It creates
-// 'chatty' entries for the elements that it prunes and merges related chatty entries together. It
-// completes when one of three conditions have been met:
-// 1) The requested element count has been pruned.
-// 2) There are no elements that match any of these rules.
-// 3) A reader is referencing the oldest element that would match these rules.
-//
-// The second pass prunes elements starting from the beginning of the log. It skips elements that
-// match any low priority prune rules. It completes when one of three conditions have been met:
-// 1) The requested element count has been pruned.
-// 2) All elements except those mwatching low priority prune rules have been pruned.
-// 3) A reader is referencing the oldest element that would match these rules.
-//
-// The final pass only happens if there are any low priority prune rules and if the first two passes
-// were unable to prune the requested number of elements. It prunes elements all starting from the
-// beginning of the log, regardless of if they match any low priority prune rules.
-//
-// If the requested number of logs was unable to be pruned, KickReader() is called to mitigate the
-// situation before the next call to Prune() and the function returns false. Otherwise, if the
-// requested number of logs or all logs present in the buffer are pruned, in the case of Clear(),
-// it returns true.
-bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
- LogReaderThread* oldest = nullptr;
- bool clearAll = pruneRows == ULONG_MAX;
-
- auto reader_threads_lock = std::lock_guard{reader_list()->reader_threads_lock()};
-
- // Region locked?
- for (const auto& reader_thread : reader_list()->reader_threads()) {
- if (!reader_thread->IsWatching(id)) {
- continue;
- }
- if (!oldest || oldest->start() > reader_thread->start() ||
- (oldest->start() == reader_thread->start() &&
- reader_thread->deadline().time_since_epoch().count() != 0)) {
- oldest = reader_thread.get();
- }
- }
-
- LogBufferElementCollection::iterator it;
-
- if (__predict_false(caller_uid != AID_ROOT)) { // unlikely
- // Only here if clear all request from non system source, so chatty
- // filter logistics is not required.
- it = GetOldest(id);
- while (it != logs().end()) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id || element.uid() != caller_uid) {
- ++it;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- KickReader(oldest, id, pruneRows);
- return false;
- }
-
- it = Erase(it);
- if (--pruneRows == 0) {
- return true;
- }
- }
- return true;
- }
-
- // First prune pass.
- bool check_high_priority = id != LOG_ID_SECURITY && prune_->HasHighPriorityPruneRules();
- while (!clearAll && (pruneRows > 0)) {
- // recalculate the worst offender on every batched pass
- int worst = -1; // not valid for uid() or getKey()
- size_t worst_sizes = 0;
- size_t second_worst_sizes = 0;
- pid_t worstPid = 0; // POSIX guarantees PID != 0
-
- if (worstUidEnabledForLogid(id) && prune_->worst_uid_enabled()) {
- // Calculate threshold as 12.5% of available storage
- size_t threshold = max_size(id) / 8;
-
- if (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) {
- stats()->WorstTwoTags(threshold, &worst, &worst_sizes, &second_worst_sizes);
- // per-pid filter for AID_SYSTEM sources is too complex
- } else {
- stats()->WorstTwoUids(id, threshold, &worst, &worst_sizes, &second_worst_sizes);
-
- if (worst == AID_SYSTEM && prune_->worst_pid_of_system_enabled()) {
- stats()->WorstTwoSystemPids(id, worst_sizes, &worstPid, &second_worst_sizes);
- }
- }
- }
-
- // skip if we have neither a worst UID or high priority prune rules
- if (worst == -1 && !check_high_priority) {
- break;
- }
-
- bool kick = false;
- bool leading = true; // true if starting from the oldest log entry, false if starting from
- // a specific chatty entry.
- // Perform at least one mandatory garbage collection cycle in following
- // - clear leading chatty tags
- // - coalesce chatty tags
- // - check age-out of preserved logs
- bool gc = pruneRows <= 1;
- if (!gc && (worst != -1)) {
- { // begin scope for worst found iterator
- LogBufferIteratorMap::iterator found = mLastWorst[id].find(worst);
- if (found != mLastWorst[id].end() && found->second != logs().end()) {
- leading = false;
- it = found->second;
- }
- }
- if (worstPid) { // begin scope for pid worst found iterator
- // FYI: worstPid only set if !LOG_ID_EVENTS and
- // !LOG_ID_SECURITY, not going to make that assumption ...
- LogBufferPidIteratorMap::iterator found = mLastWorstPidOfSystem[id].find(worstPid);
- if (found != mLastWorstPidOfSystem[id].end() && found->second != logs().end()) {
- leading = false;
- it = found->second;
- }
- }
- }
- if (leading) {
- it = GetOldest(id);
- }
- static const log_time too_old{EXPIRE_HOUR_THRESHOLD * 60 * 60, 0};
- LogBufferElementCollection::iterator lastt;
- lastt = logs().end();
- --lastt;
- LogBufferElementLast last;
- while (it != logs().end()) {
- LogBufferElement& element = *it;
-
- if (oldest && oldest->start() <= element.sequence()) {
- // Do not let chatty eliding trigger any reader mitigation
- break;
- }
-
- if (element.log_id() != id) {
- ++it;
- continue;
- }
- // below this point element->log_id() == id
-
- uint16_t dropped = element.dropped_count();
-
- // remove any leading drops
- if (leading && dropped) {
- it = Erase(it);
- continue;
- }
-
- if (dropped && last.coalesce(&element, dropped)) {
- it = Erase(it, true);
- continue;
- }
-
- int key = (id == LOG_ID_EVENTS || id == LOG_ID_SECURITY) ? element.GetTag()
- : element.uid();
-
- if (check_high_priority && prune_->IsHighPriority(&element)) {
- last.clear(&element);
- it = Erase(it);
- if (dropped) {
- continue;
- }
-
- pruneRows--;
- if (pruneRows == 0) {
- break;
- }
-
- if (key == worst) {
- kick = true;
- if (worst_sizes < second_worst_sizes) {
- break;
- }
- worst_sizes -= element.msg_len();
- }
- continue;
- }
-
- if (element.realtime() < (lastt->realtime() - too_old) ||
- element.realtime() > lastt->realtime()) {
- break;
- }
-
- if (dropped) {
- last.add(&element);
- if (worstPid && ((!gc && element.pid() == worstPid) ||
- mLastWorstPidOfSystem[id].find(element.pid()) ==
- mLastWorstPidOfSystem[id].end())) {
- // element->uid() may not be AID_SYSTEM, next best
- // watermark if current one empty. id is not LOG_ID_EVENTS
- // or LOG_ID_SECURITY because of worstPid check.
- mLastWorstPidOfSystem[id][element.pid()] = it;
- }
- if ((!gc && !worstPid && (key == worst)) ||
- (mLastWorst[id].find(key) == mLastWorst[id].end())) {
- mLastWorst[id][key] = it;
- }
- ++it;
- continue;
- }
-
- if (key != worst || (worstPid && element.pid() != worstPid)) {
- leading = false;
- last.clear(&element);
- ++it;
- continue;
- }
- // key == worst below here
- // If worstPid set, then element->pid() == worstPid below here
-
- pruneRows--;
- if (pruneRows == 0) {
- break;
- }
-
- kick = true;
-
- uint16_t len = element.msg_len();
-
- // do not create any leading drops
- if (leading) {
- it = Erase(it);
- } else {
- stats()->Drop(element.ToLogStatisticsElement());
- element.SetDropped(1);
- if (last.coalesce(&element, 1)) {
- it = Erase(it, true);
- } else {
- last.add(&element);
- if (worstPid && (!gc || mLastWorstPidOfSystem[id].find(worstPid) ==
- mLastWorstPidOfSystem[id].end())) {
- // element->uid() may not be AID_SYSTEM, next best
- // watermark if current one empty. id is not
- // LOG_ID_EVENTS or LOG_ID_SECURITY because of worstPid.
- mLastWorstPidOfSystem[id][worstPid] = it;
- }
- if ((!gc && !worstPid) || mLastWorst[id].find(worst) == mLastWorst[id].end()) {
- mLastWorst[id][worst] = it;
- }
- ++it;
- }
- }
- if (worst_sizes < second_worst_sizes) {
- break;
- }
- worst_sizes -= len;
- }
- last.clear();
-
- if (!kick || !prune_->worst_uid_enabled()) {
- break; // the following loop will ask bad clients to skip/drop
- }
- }
-
- // Second prune pass.
- bool skipped_low_priority_prune = false;
- bool check_low_priority =
- id != LOG_ID_SECURITY && prune_->HasLowPriorityPruneRules() && !clearAll;
- it = GetOldest(id);
- while (pruneRows > 0 && it != logs().end()) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id) {
- it++;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- if (!skipped_low_priority_prune) KickReader(oldest, id, pruneRows);
- break;
- }
-
- if (check_low_priority && !element.dropped_count() && prune_->IsLowPriority(&element)) {
- skipped_low_priority_prune = true;
- it++;
- continue;
- }
-
- it = Erase(it);
- pruneRows--;
- }
-
- // Third prune pass.
- if (skipped_low_priority_prune && pruneRows > 0) {
- it = GetOldest(id);
- while (it != logs().end() && pruneRows > 0) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id) {
- ++it;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- KickReader(oldest, id, pruneRows);
- break;
- }
-
- it = Erase(it);
- pruneRows--;
- }
- }
-
- return pruneRows == 0 || it == logs().end();
-}
diff --git a/logd/ChattyLogBuffer.h b/logd/ChattyLogBuffer.h
deleted file mode 100644
index b4d3a2f..0000000
--- a/logd/ChattyLogBuffer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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.
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-#include <list>
-#include <optional>
-#include <string>
-
-#include <android-base/thread_annotations.h>
-#include <android/log.h>
-#include <private/android_filesystem_config.h>
-
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogReaderList.h"
-#include "LogReaderThread.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogWriter.h"
-#include "PruneList.h"
-#include "SimpleLogBuffer.h"
-#include "rwlock.h"
-
-typedef std::list<LogBufferElement> LogBufferElementCollection;
-
-class ChattyLogBuffer : public SimpleLogBuffer {
- // watermark of any worst/chatty uid processing
- typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator> LogBufferIteratorMap;
- LogBufferIteratorMap mLastWorst[LOG_ID_MAX] GUARDED_BY(lock_);
- // watermark of any worst/chatty pid of system processing
- typedef std::unordered_map<pid_t, LogBufferElementCollection::iterator> LogBufferPidIteratorMap;
- LogBufferPidIteratorMap mLastWorstPidOfSystem[LOG_ID_MAX] GUARDED_BY(lock_);
-
- public:
- ChattyLogBuffer(LogReaderList* reader_list, LogTags* tags, PruneList* prune,
- LogStatistics* stats);
- ~ChattyLogBuffer();
-
- protected:
- bool Prune(log_id_t id, unsigned long pruneRows, uid_t uid) REQUIRES(lock_) override;
- void LogInternal(LogBufferElement&& elem) REQUIRES(lock_) override;
-
- private:
- LogBufferElementCollection::iterator Erase(LogBufferElementCollection::iterator it,
- bool coalesce = false) REQUIRES(lock_);
-
- PruneList* prune_;
-
- // This always contains a copy of the last message logged, for deduplication.
- std::optional<LogBufferElement> last_logged_elements_[LOG_ID_MAX] GUARDED_BY(lock_);
- // This contains an element if duplicate messages are seen.
- // Its `dropped` count is `duplicates seen - 1`.
- std::optional<LogBufferElement> duplicate_elements_[LOG_ID_MAX] GUARDED_BY(lock_);
-};
diff --git a/logd/ChattyLogBufferTest.cpp b/logd/ChattyLogBufferTest.cpp
deleted file mode 100644
index 3d9005a..0000000
--- a/logd/ChattyLogBufferTest.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2020 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 "LogBufferTest.h"
-
-class ChattyLogBufferTest : public LogBufferTest {};
-
-TEST_P(ChattyLogBufferTest, deduplication_simple) {
- auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
- bool regex = false) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- // clang-format off
- std::vector<LogMessage> log_messages = {
- make_message(0, "test_tag", "duplicate"),
- make_message(1, "test_tag", "duplicate"),
- make_message(2, "test_tag", "not_same"),
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "duplicate"),
- make_message(5, "test_tag", "not_same"),
- make_message(6, "test_tag", "duplicate"),
- make_message(7, "test_tag", "duplicate"),
- make_message(8, "test_tag", "duplicate"),
- make_message(9, "test_tag", "not_same"),
- make_message(10, "test_tag", "duplicate"),
- make_message(11, "test_tag", "duplicate"),
- make_message(12, "test_tag", "duplicate"),
- make_message(13, "test_tag", "duplicate"),
- make_message(14, "test_tag", "duplicate"),
- make_message(15, "test_tag", "duplicate"),
- make_message(16, "test_tag", "not_same"),
- make_message(100, "test_tag", "duplicate"),
- make_message(200, "test_tag", "duplicate"),
- make_message(300, "test_tag", "duplicate"),
- };
- // clang-format on
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
- std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
-
- std::vector<LogMessage> expected_log_messages = {
- make_message(0, "test_tag", "duplicate"),
- make_message(1, "test_tag", "duplicate"),
- make_message(2, "test_tag", "not_same"),
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "duplicate"),
- make_message(5, "test_tag", "not_same"),
- // 3 duplicate logs together print the first, a 1 count chatty message, then the last.
- make_message(6, "test_tag", "duplicate"),
- make_message(7, "chatty", "uid=0\\([^\\)]+\\) [^ ]+ identical 1 line", true),
- make_message(8, "test_tag", "duplicate"),
- make_message(9, "test_tag", "not_same"),
- // 6 duplicate logs together print the first, a 4 count chatty message, then the last.
- make_message(10, "test_tag", "duplicate"),
- make_message(14, "chatty", "uid=0\\([^\\)]+\\) [^ ]+ identical 4 lines", true),
- make_message(15, "test_tag", "duplicate"),
- make_message(16, "test_tag", "not_same"),
- // duplicate logs > 1 minute apart are not deduplicated.
- make_message(100, "test_tag", "duplicate"),
- make_message(200, "test_tag", "duplicate"),
- make_message(300, "test_tag", "duplicate"),
- };
- FixupMessages(&expected_log_messages);
- CompareLogMessages(expected_log_messages, read_log_messages);
-};
-
-TEST_P(ChattyLogBufferTest, deduplication_overflow) {
- auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
- bool regex = false) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- uint32_t sec = 0;
- std::vector<LogMessage> log_messages = {
- make_message(sec++, "test_tag", "normal"),
- };
- size_t expired_per_chatty_message = std::numeric_limits<uint16_t>::max();
- for (size_t i = 0; i < expired_per_chatty_message + 3; ++i) {
- log_messages.emplace_back(make_message(sec++, "test_tag", "duplicate"));
- }
- log_messages.emplace_back(make_message(sec++, "test_tag", "normal"));
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
- std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
-
- std::vector<LogMessage> expected_log_messages = {
- make_message(0, "test_tag", "normal"),
- make_message(1, "test_tag", "duplicate"),
- make_message(expired_per_chatty_message + 1, "chatty",
- "uid=0\\([^\\)]+\\) [^ ]+ identical 65535 lines", true),
- make_message(expired_per_chatty_message + 2, "chatty",
- "uid=0\\([^\\)]+\\) [^ ]+ identical 1 line", true),
- make_message(expired_per_chatty_message + 3, "test_tag", "duplicate"),
- make_message(expired_per_chatty_message + 4, "test_tag", "normal"),
- };
- FixupMessages(&expected_log_messages);
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-TEST_P(ChattyLogBufferTest, deduplication_liblog) {
- auto make_message = [&](uint32_t sec, int32_t tag, int32_t count) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_EVENTS, .uid = 0};
- android_log_event_int_t liblog_event = {
- .header.tag = tag, .payload.type = EVENT_TYPE_INT, .payload.data = count};
- return {entry, std::string(reinterpret_cast<char*>(&liblog_event), sizeof(liblog_event)),
- false};
- };
-
- // LIBLOG_LOG_TAG
- std::vector<LogMessage> log_messages = {
- make_message(0, 1234, 1),
- make_message(1, LIBLOG_LOG_TAG, 3),
- make_message(2, 1234, 2),
- make_message(3, LIBLOG_LOG_TAG, 3),
- make_message(4, LIBLOG_LOG_TAG, 4),
- make_message(5, 1234, 223),
- make_message(6, LIBLOG_LOG_TAG, 2),
- make_message(7, LIBLOG_LOG_TAG, 3),
- make_message(8, LIBLOG_LOG_TAG, 4),
- make_message(9, 1234, 227),
- make_message(10, LIBLOG_LOG_TAG, 1),
- make_message(11, LIBLOG_LOG_TAG, 3),
- make_message(12, LIBLOG_LOG_TAG, 2),
- make_message(13, LIBLOG_LOG_TAG, 3),
- make_message(14, LIBLOG_LOG_TAG, 5),
- make_message(15, 1234, 227),
- make_message(16, LIBLOG_LOG_TAG, 2),
- make_message(17, LIBLOG_LOG_TAG, std::numeric_limits<int32_t>::max()),
- make_message(18, LIBLOG_LOG_TAG, 3),
- make_message(19, LIBLOG_LOG_TAG, 5),
- make_message(20, 1234, 227),
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
- std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
-
- std::vector<LogMessage> expected_log_messages = {
- make_message(0, 1234, 1),
- make_message(1, LIBLOG_LOG_TAG, 3),
- make_message(2, 1234, 2),
- make_message(3, LIBLOG_LOG_TAG, 3),
- make_message(4, LIBLOG_LOG_TAG, 4),
- make_message(5, 1234, 223),
- // More than 2 liblog events (3 here), sum their value into the third message.
- make_message(6, LIBLOG_LOG_TAG, 2),
- make_message(8, LIBLOG_LOG_TAG, 7),
- make_message(9, 1234, 227),
- // More than 2 liblog events (5 here), sum their value into the third message.
- make_message(10, LIBLOG_LOG_TAG, 1),
- make_message(14, LIBLOG_LOG_TAG, 13),
- make_message(15, 1234, 227),
- // int32_t max is the max for a chatty message, beyond that we must use new messages.
- make_message(16, LIBLOG_LOG_TAG, 2),
- make_message(17, LIBLOG_LOG_TAG, std::numeric_limits<int32_t>::max()),
- make_message(19, LIBLOG_LOG_TAG, 8),
- make_message(20, 1234, 227),
- };
- FixupMessages(&expected_log_messages);
- CompareLogMessages(expected_log_messages, read_log_messages);
-};
-
-TEST_P(ChattyLogBufferTest, no_leading_chatty_simple) {
- auto make_message = [&](uint32_t sec, int32_t pid, uint32_t uid, uint32_t lid, const char* tag,
- const char* msg, bool regex = false) -> LogMessage {
- logger_entry entry = {.pid = pid, .tid = 1, .sec = sec, .nsec = 1, .lid = lid, .uid = uid};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- // clang-format off
- std::vector<LogMessage> log_messages = {
- make_message(1, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(2, 2, 2, LOG_ID_SYSTEM, "test_tag", "duplicate2"),
- make_message(3, 2, 2, LOG_ID_SYSTEM, "test_tag", "duplicate2"),
- make_message(4, 2, 2, LOG_ID_SYSTEM, "test_tag", "duplicate2"),
- make_message(6, 2, 2, LOG_ID_SYSTEM, "test_tag", "not duplicate2"),
- make_message(7, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(8, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(9, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(10, 1, 1, LOG_ID_MAIN, "test_tag", "not duplicate1"),
- };
- // clang-format on
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- // After logging log_messages, the below is what should be in the buffer:
- // PID=1, LOG_ID_MAIN duplicate1
- // [1] PID=2, LOG_ID_SYSTEM duplicate2
- // PID=2, LOG_ID_SYSTEM chatty drop
- // PID=2, LOG_ID_SYSTEM duplicate2
- // PID=2, LOG_ID_SYSTEM not duplicate2
- // [2] PID=1, LOG_ID_MAIN chatty drop
- // [3] PID=1, LOG_ID_MAIN duplicate1
- // PID=1, LOG_ID_MAIN not duplicate1
-
- // We then read from the 2nd sequence number, starting from log message [1], but filtering out
- // everything but PID=1, which results in us starting with log message [2], which is a chatty
- // drop. Code prior to this test case would erroneously print it. The intended behavior that
- // this test checks prints logs starting from log message [3].
-
- // clang-format off
- std::vector<LogMessage> expected_log_messages = {
- make_message(9, 1, 1, LOG_ID_MAIN, "test_tag", "duplicate1"),
- make_message(10, 1, 1, LOG_ID_MAIN, "test_tag", "not duplicate1"),
- };
- FixupMessages(&expected_log_messages);
- // clang-format on
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, ~0, 1, {}, 2, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
-
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-TEST_P(ChattyLogBufferTest, no_leading_chatty_tail) {
- auto make_message = [&](uint32_t sec, const char* tag, const char* msg,
- bool regex = false) -> LogMessage {
- logger_entry entry = {
- .pid = 1, .tid = 1, .sec = sec, .nsec = 1, .lid = LOG_ID_MAIN, .uid = 0};
- std::string message;
- message.push_back(ANDROID_LOG_INFO);
- message.append(tag);
- message.push_back('\0');
- message.append(msg);
- message.push_back('\0');
- return {entry, message, regex};
- };
-
- // clang-format off
- std::vector<LogMessage> log_messages = {
- make_message(1, "test_tag", "duplicate"),
- make_message(2, "test_tag", "duplicate"),
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "not_duplicate"),
- };
- // clang-format on
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- // After logging log_messages, the below is what should be in the buffer:
- // "duplicate"
- // chatty
- // "duplicate"
- // "not duplicate"
-
- // We then read the tail 3 messages expecting there to not be a chatty message, meaning that we
- // should only see the last two messages.
-
- // clang-format off
- std::vector<LogMessage> expected_log_messages = {
- make_message(3, "test_tag", "duplicate"),
- make_message(4, "test_tag", "not_duplicate"),
- };
- FixupMessages(&expected_log_messages);
- // clang-format on
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 3, ~0, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
-
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-INSTANTIATE_TEST_CASE_P(ChattyLogBufferTests, ChattyLogBufferTest, testing::Values("chatty"));
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
deleted file mode 100644
index 0ba1621..0000000
--- a/logd/CommandListener.cpp
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 "CommandListener.h"
-
-#include <arpa/inet.h>
-#include <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <math.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <string>
-
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <cutils/sockets.h>
-#include <log/log_properties.h>
-#include <private/android_filesystem_config.h>
-#include <sysutils/SocketClient.h>
-
-#include "LogPermissions.h"
-
-CommandListener::CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune,
- LogStatistics* stats)
- : FrameworkListener(getLogSocket()), buf_(buf), tags_(tags), prune_(prune), stats_(stats) {
- registerCmd(new ClearCmd(this));
- registerCmd(new GetBufSizeCmd(this));
- registerCmd(new SetBufSizeCmd(this));
- registerCmd(new GetBufSizeReadableCmd(this));
- registerCmd(new GetBufSizeUsedCmd(this));
- registerCmd(new GetStatisticsCmd(this));
- registerCmd(new SetPruneListCmd(this));
- registerCmd(new GetPruneListCmd(this));
- registerCmd(new GetEventTagCmd(this));
- registerCmd(new ReinitCmd(this));
- registerCmd(new ExitCmd(this));
-}
-
-static void setname() {
- static bool name_set;
- if (!name_set) {
- prctl(PR_SET_NAME, "logd.control");
- name_set = true;
- }
-}
-
-template <typename F>
-static int LogIdCommand(SocketClient* cli, int argc, char** argv, F&& function) {
- setname();
- if (argc < 2) {
- cli->sendMsg("Missing Argument");
- return 0;
- }
-
- int log_id;
- if (!android::base::ParseInt(argv[1], &log_id, static_cast<int>(LOG_ID_MAIN),
- static_cast<int>(LOG_ID_KERNEL))) {
- cli->sendMsg("Range Error");
- return 0;
- }
-
- function(static_cast<log_id_t>(log_id));
- return 0;
-}
-
-int CommandListener::ClearCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- uid_t uid = cli->getUid();
- if (clientHasLogCredentials(cli)) {
- uid = AID_ROOT;
- }
-
- return LogIdCommand(cli, argc, argv, [&](log_id_t id) {
- cli->sendMsg(buf()->Clear(id, uid) ? "success" : "busy");
- });
-}
-
-template <typename F>
-static int LogSizeCommand(SocketClient* cli, int argc, char** argv, F&& size_function) {
- return LogIdCommand(cli, argc, argv, [&](log_id_t log_id) {
- cli->sendMsg(std::to_string(size_function(log_id)).c_str());
- });
-}
-
-int CommandListener::GetBufSizeCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- return LogSizeCommand(cli, argc, argv, [this](log_id_t id) { return buf()->GetSize(id); });
-}
-
-int CommandListener::GetBufSizeReadableCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- return LogSizeCommand(cli, argc, argv,
- [this](log_id_t id) { return stats()->SizeReadable(id); });
-}
-
-int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- return LogSizeCommand(cli, argc, argv, [this](log_id_t id) { return stats()->Sizes(id); });
-}
-
-int CommandListener::SetBufSizeCmd::runCommand(SocketClient* cli, int argc,
- char** argv) {
- if (!clientHasLogCredentials(cli)) {
- cli->sendMsg("Permission Denied");
- return 0;
- }
-
- if (argc < 3) {
- cli->sendMsg("Missing Argument");
- return 0;
- }
- size_t size = atol(argv[2]);
-
- return LogIdCommand(cli, argc, argv, [&](log_id_t log_id) {
- cli->sendMsg(buf()->SetSize(log_id, size) ? "success" : "busy");
- });
-}
-
-// This returns a string with a length prefix with the format <length>\n<data>\n\f. The length
-// prefix includes the length of the prefix itself.
-static std::string PackageString(const std::string& str) {
- size_t overhead_length = 3; // \n \n \f.
-
- // Number of digits needed to represent length(str + overhead_length).
- size_t str_size_digits = 1 + static_cast<size_t>(log10(str.size() + overhead_length));
- // Number of digits needed to represent the total size.
- size_t total_size_digits =
- 1 + static_cast<size_t>(log10(str.size() + overhead_length + str_size_digits));
-
- // If adding the size prefix causes a new digit to be required to represent the new total
- // size, add it to the 'overhead_length'. This can only happen once, since each new digit
- // allows for 10x the previous size to be recorded.
- if (total_size_digits != str_size_digits) {
- overhead_length++;
- }
-
- size_t total_size = str.size() + overhead_length + str_size_digits;
- return android::base::StringPrintf("%zu\n%s\n\f", total_size, str.c_str());
-}
-
-int CommandListener::GetStatisticsCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- setname();
- uid_t uid = cli->getUid();
- if (clientHasLogCredentials(cli)) {
- uid = AID_ROOT;
- }
-
- unsigned int logMask = -1;
- pid_t pid = 0;
- if (argc > 1) {
- logMask = 0;
- for (int i = 1; i < argc; ++i) {
- static const char _pid[] = "pid=";
- if (!strncmp(argv[i], _pid, sizeof(_pid) - 1)) {
- pid = atol(argv[i] + sizeof(_pid) - 1);
- if (pid == 0) {
- cli->sendMsg("PID Error");
- return 0;
- }
- continue;
- }
-
- int id = atoi(argv[i]);
- if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
- cli->sendMsg("Range Error");
- return 0;
- }
- logMask |= 1 << id;
- }
- }
-
- cli->sendMsg(PackageString(stats()->Format(uid, pid, logMask)).c_str());
- return 0;
-}
-
-int CommandListener::GetPruneListCmd::runCommand(SocketClient* cli, int, char**) {
- setname();
- cli->sendMsg(PackageString(prune()->Format()).c_str());
- return 0;
-}
-
-int CommandListener::SetPruneListCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- setname();
- if (!clientHasLogCredentials(cli)) {
- cli->sendMsg("Permission Denied");
- return 0;
- }
-
- std::string str;
- for (int i = 1; i < argc; ++i) {
- if (str.length()) {
- str += " ";
- }
- str += argv[i];
- }
-
- if (!prune()->Init(str.c_str())) {
- cli->sendMsg("Invalid");
- return 0;
- }
-
- cli->sendMsg("success");
- return 0;
-}
-
-int CommandListener::GetEventTagCmd::runCommand(SocketClient* cli, int argc, char** argv) {
- setname();
- uid_t uid = cli->getUid();
- if (clientHasLogCredentials(cli)) {
- uid = AID_ROOT;
- }
-
- const char* name = nullptr;
- const char* format = nullptr;
- const char* id = nullptr;
- for (int i = 1; i < argc; ++i) {
- static const char _name[] = "name=";
- if (!strncmp(argv[i], _name, strlen(_name))) {
- name = argv[i] + strlen(_name);
- continue;
- }
-
- static const char _format[] = "format=";
- if (!strncmp(argv[i], _format, strlen(_format))) {
- format = argv[i] + strlen(_format);
- continue;
- }
-
- static const char _id[] = "id=";
- if (!strncmp(argv[i], _id, strlen(_id))) {
- id = argv[i] + strlen(_id);
- continue;
- }
- }
-
- if (id) {
- if (format || name) {
- cli->sendMsg("can not mix id= with either format= or name=");
- return 0;
- }
- cli->sendMsg(PackageString(tags()->formatEntry(atoi(id), uid)).c_str());
- return 0;
- }
-
- cli->sendMsg(PackageString(tags()->formatGetEventTag(uid, name, format)).c_str());
-
- return 0;
-}
-
-int CommandListener::ReinitCmd::runCommand(SocketClient* cli, int, char**) {
- setname();
-
- LOG(INFO) << "logd reinit";
- buf()->Init();
- prune()->Init(nullptr);
-
- // This only works on userdebug and eng devices to re-read the
- // /data/misc/logd/event-log-tags file right after /data is mounted.
- // The operation is near to boot and should only happen once. There
- // are races associated with its use since it can trigger a Rebuild
- // of the file, but that is a can-not-happen since the file was not
- // read yet. More dangerous if called later, but if all is well it
- // should just skip over everything and not write any new entries.
- if (__android_log_is_debuggable()) {
- tags()->ReadFileEventLogTags(tags()->debug_event_log_tags);
- }
-
- cli->sendMsg("success");
-
- return 0;
-}
-
-int CommandListener::ExitCmd::runCommand(SocketClient* cli, int, char**) {
- setname();
-
- cli->sendMsg("success");
- parent_->release(cli);
-
- return 0;
-}
-
-int CommandListener::getLogSocket() {
- static const char socketName[] = "logd";
- int sock = android_get_control_socket(socketName);
-
- if (sock < 0) {
- sock = socket_local_server(
- socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
- }
-
- return sock;
-}
diff --git a/logd/CommandListener.h b/logd/CommandListener.h
deleted file mode 100644
index 8e12634..0000000
--- a/logd/CommandListener.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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.
- */
-
-#pragma once
-
-#include <sysutils/FrameworkCommand.h>
-#include <sysutils/FrameworkListener.h>
-
-#include "LogBuffer.h"
-#include "LogListener.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "PruneList.h"
-
-class CommandListener : public FrameworkListener {
- public:
- CommandListener(LogBuffer* buf, LogTags* tags, PruneList* prune, LogStatistics* log_statistics);
- virtual ~CommandListener() {}
-
- private:
- static int getLogSocket();
-
- LogBuffer* buf_;
- LogTags* tags_;
- PruneList* prune_;
- LogStatistics* stats_;
-
-#define LogCmd(name, command_string) \
- class name##Cmd : public FrameworkCommand { \
- public: \
- explicit name##Cmd(CommandListener* parent) \
- : FrameworkCommand(#command_string), parent_(parent) {} \
- virtual ~name##Cmd() {} \
- int runCommand(SocketClient* c, int argc, char** argv); \
- \
- private: \
- LogBuffer* buf() const { return parent_->buf_; } \
- LogTags* tags() const { return parent_->tags_; } \
- PruneList* prune() const { return parent_->prune_; } \
- LogStatistics* stats() const { return parent_->stats_; } \
- CommandListener* parent_; \
- }
-
- LogCmd(Clear, clear);
- LogCmd(GetBufSize, getLogSize);
- LogCmd(SetBufSize, setLogSize);
- LogCmd(GetBufSizeReadable, getLogSizeReadable);
- LogCmd(GetBufSizeUsed, getLogSizeUsed);
- LogCmd(GetStatistics, getStatistics);
- LogCmd(GetPruneList, getPruneList);
- LogCmd(SetPruneList, setPruneList);
- LogCmd(GetEventTag, getEventTag);
- LogCmd(Reinit, reinit);
- LogCmd(Exit, EXIT);
-#undef LogCmd
-};
diff --git a/logd/CompressionEngine.cpp b/logd/CompressionEngine.cpp
deleted file mode 100644
index da2628c..0000000
--- a/logd/CompressionEngine.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2020 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 "CompressionEngine.h"
-
-#include <limits>
-
-#include <android-base/logging.h>
-#include <zlib.h>
-#include <zstd.h>
-
-CompressionEngine& CompressionEngine::GetInstance() {
- static CompressionEngine* engine = new ZstdCompressionEngine();
- return *engine;
-}
-
-bool ZlibCompressionEngine::Compress(SerializedData& in, size_t data_length, SerializedData& out) {
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- int ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
- if (ret != Z_OK) {
- LOG(FATAL) << "deflateInit() failed";
- }
-
- CHECK_LE(data_length, in.size());
- CHECK_LE(in.size(), std::numeric_limits<uint32_t>::max());
- uint32_t deflate_bound = deflateBound(&strm, in.size());
-
- out.Resize(deflate_bound);
-
- strm.avail_in = data_length;
- strm.next_in = in.data();
- strm.avail_out = out.size();
- strm.next_out = out.data();
- ret = deflate(&strm, Z_FINISH);
- CHECK_EQ(ret, Z_STREAM_END);
-
- uint32_t compressed_size = strm.total_out;
- deflateEnd(&strm);
-
- out.Resize(compressed_size);
-
- return true;
-}
-
-bool ZlibCompressionEngine::Decompress(SerializedData& in, SerializedData& out) {
- z_stream strm;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
- strm.opaque = Z_NULL;
- strm.avail_in = in.size();
- strm.next_in = in.data();
- strm.avail_out = out.size();
- strm.next_out = out.data();
-
- inflateInit(&strm);
- int ret = inflate(&strm, Z_NO_FLUSH);
-
- CHECK_EQ(strm.avail_in, 0U);
- CHECK_EQ(strm.avail_out, 0U);
- CHECK_EQ(ret, Z_STREAM_END);
- inflateEnd(&strm);
-
- return true;
-}
-
-bool ZstdCompressionEngine::Compress(SerializedData& in, size_t data_length, SerializedData& out) {
- CHECK_LE(data_length, in.size());
-
- size_t compress_bound = ZSTD_compressBound(data_length);
- out.Resize(compress_bound);
-
- size_t out_size = ZSTD_compress(out.data(), out.size(), in.data(), data_length, 1);
- if (ZSTD_isError(out_size)) {
- LOG(FATAL) << "ZSTD_compress failed: " << ZSTD_getErrorName(out_size);
- }
- out.Resize(out_size);
-
- return true;
-}
-
-bool ZstdCompressionEngine::Decompress(SerializedData& in, SerializedData& out) {
- size_t result = ZSTD_decompress(out.data(), out.size(), in.data(), in.size());
- if (ZSTD_isError(result)) {
- LOG(FATAL) << "ZSTD_decompress failed: " << ZSTD_getErrorName(result);
- }
- CHECK_EQ(result, out.size());
- return true;
-}
diff --git a/logd/CompressionEngine.h b/logd/CompressionEngine.h
deleted file mode 100644
index 0f760ed..0000000
--- a/logd/CompressionEngine.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <memory>
-
-#include "SerializedData.h"
-
-class CompressionEngine {
- public:
- static CompressionEngine& GetInstance();
-
- virtual ~CompressionEngine(){};
-
- virtual bool Compress(SerializedData& in, size_t data_length, SerializedData& out) = 0;
- // Decompress the contents of `in` into `out`. `out.size()` must be set to the decompressed
- // size of the contents.
- virtual bool Decompress(SerializedData& in, SerializedData& out) = 0;
-};
-
-class ZlibCompressionEngine : public CompressionEngine {
- public:
- bool Compress(SerializedData& in, size_t data_length, SerializedData& out) override;
- bool Decompress(SerializedData& in, SerializedData& out) override;
-};
-
-class ZstdCompressionEngine : public CompressionEngine {
- public:
- bool Compress(SerializedData& in, size_t data_length, SerializedData& out) override;
- bool Decompress(SerializedData& in, SerializedData& out) override;
-};
\ No newline at end of file
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
deleted file mode 100644
index 0e17476..0000000
--- a/logd/LogAudit.cpp
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogAudit.h"
-
-#include <ctype.h>
-#include <endian.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/uio.h>
-#include <syslog.h>
-
-#include <fstream>
-#include <sstream>
-
-#include <android-base/macros.h>
-#include <android-base/properties.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogKlog.h"
-#include "LogUtils.h"
-#include "libaudit.h"
-
-using android::base::GetBoolProperty;
-
-#define KMSG_PRIORITY(PRI) \
- '<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \
- '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>'
-
-LogAudit::LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats)
- : SocketListener(getLogSocket(), false),
- logbuf(buf),
- fdDmesg(fdDmesg),
- main(GetBoolProperty("ro.logd.auditd.main", true)),
- events(GetBoolProperty("ro.logd.auditd.events", true)),
- initialized(false),
- stats_(stats) {
- static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
- 'l',
- 'o',
- 'g',
- 'd',
- '.',
- 'a',
- 'u',
- 'd',
- 'i',
- 't',
- 'd',
- ':',
- ' ',
- 's',
- 't',
- 'a',
- 'r',
- 't',
- '\n' };
- write(fdDmesg, auditd_message, sizeof(auditd_message));
-}
-
-bool LogAudit::onDataAvailable(SocketClient* cli) {
- if (!initialized) {
- prctl(PR_SET_NAME, "logd.auditd");
- initialized = true;
- }
-
- struct audit_message rep;
-
- rep.nlh.nlmsg_type = 0;
- rep.nlh.nlmsg_len = 0;
- rep.data[0] = '\0';
-
- if (audit_get_reply(cli->getSocket(), &rep, GET_REPLY_BLOCKING, 0) < 0) {
- SLOGE("Failed on audit_get_reply with error: %s", strerror(errno));
- return false;
- }
-
- logPrint("type=%d %.*s", rep.nlh.nlmsg_type, rep.nlh.nlmsg_len, rep.data);
-
- return true;
-}
-
-static inline bool hasMetadata(char* str, int str_len) {
- // need to check and see if str already contains bug metadata from
- // possibility of stuttering if log audit crashes and then reloads kernel
- // messages. Kernel denials that contain metadata will either end in
- // "b/[0-9]+$" or "b/[0-9]+ duplicate messages suppressed$" which will put
- // a '/' character at either 9 or 39 indices away from the end of the str.
- return str_len >= 39 &&
- (str[str_len - 9] == '/' || str[str_len - 39] == '/');
-}
-
-std::map<std::string, std::string> LogAudit::populateDenialMap() {
- std::ifstream bug_file("/vendor/etc/selinux/selinux_denial_metadata");
- std::string line;
- // allocate a map for the static map pointer in auditParse to keep track of,
- // this function only runs once
- std::map<std::string, std::string> denial_to_bug;
- if (bug_file.good()) {
- std::string scontext;
- std::string tcontext;
- std::string tclass;
- std::string bug_num;
- while (std::getline(bug_file, line)) {
- std::stringstream split_line(line);
- split_line >> scontext >> tcontext >> tclass >> bug_num;
- denial_to_bug.emplace(scontext + tcontext + tclass, bug_num);
- }
- }
- return denial_to_bug;
-}
-
-std::string LogAudit::denialParse(const std::string& denial, char terminator,
- const std::string& search_term) {
- size_t start_index = denial.find(search_term);
- if (start_index != std::string::npos) {
- start_index += search_term.length();
- return denial.substr(
- start_index, denial.find(terminator, start_index) - start_index);
- }
- return "";
-}
-
-void LogAudit::auditParse(const std::string& string, uid_t uid,
- std::string* bug_num) {
- static std::map<std::string, std::string> denial_to_bug =
- populateDenialMap();
- std::string scontext = denialParse(string, ':', "scontext=u:object_r:");
- std::string tcontext = denialParse(string, ':', "tcontext=u:object_r:");
- std::string tclass = denialParse(string, ' ', "tclass=");
- if (scontext.empty()) {
- scontext = denialParse(string, ':', "scontext=u:r:");
- }
- if (tcontext.empty()) {
- tcontext = denialParse(string, ':', "tcontext=u:r:");
- }
- auto search = denial_to_bug.find(scontext + tcontext + tclass);
- if (search != denial_to_bug.end()) {
- bug_num->assign(" " + search->second);
- } else {
- bug_num->assign("");
- }
-
- // Ensure the uid name is not null before passing it to the bug string.
- if (uid >= AID_APP_START && uid <= AID_APP_END) {
- char* uidname = android::uidToName(uid);
- if (uidname) {
- bug_num->append(" app=");
- bug_num->append(uidname);
- free(uidname);
- }
- }
-}
-
-int LogAudit::logPrint(const char* fmt, ...) {
- if (fmt == nullptr) {
- return -EINVAL;
- }
-
- va_list args;
-
- char* str = nullptr;
- va_start(args, fmt);
- int rc = vasprintf(&str, fmt, args);
- va_end(args);
-
- if (rc < 0) {
- return rc;
- }
- char* cp;
- // Work around kernels missing
- // https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
- // Such kernels improperly add newlines inside audit messages.
- while ((cp = strchr(str, '\n'))) {
- *cp = ' ';
- }
-
- while ((cp = strstr(str, " "))) {
- memmove(cp, cp + 1, strlen(cp + 1) + 1);
- }
- pid_t pid = getpid();
- pid_t tid = gettid();
- uid_t uid = AID_LOGD;
- static const char pid_str[] = " pid=";
- char* pidptr = strstr(str, pid_str);
- if (pidptr && isdigit(pidptr[sizeof(pid_str) - 1])) {
- cp = pidptr + sizeof(pid_str) - 1;
- pid = 0;
- while (isdigit(*cp)) {
- pid = (pid * 10) + (*cp - '0');
- ++cp;
- }
- tid = pid;
- uid = stats_->PidToUid(pid);
- memmove(pidptr, cp, strlen(cp) + 1);
- }
-
- bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded ");
- static std::string denial_metadata;
- if ((fdDmesg >= 0) && initialized) {
- struct iovec iov[4];
- static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
- static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
- static const char newline[] = "\n";
-
- auditParse(str, uid, &denial_metadata);
- iov[0].iov_base = info ? const_cast<char*>(log_info) : const_cast<char*>(log_warning);
- iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
- iov[1].iov_base = str;
- iov[1].iov_len = strlen(str);
- iov[2].iov_base = const_cast<char*>(denial_metadata.c_str());
- iov[2].iov_len = denial_metadata.length();
- iov[3].iov_base = const_cast<char*>(newline);
- iov[3].iov_len = strlen(newline);
-
- writev(fdDmesg, iov, arraysize(iov));
- }
-
- if (!main && !events) {
- free(str);
- return 0;
- }
-
- log_time now(log_time::EPOCH);
-
- static const char audit_str[] = " audit(";
- char* timeptr = strstr(str, audit_str);
- if (timeptr && ((cp = now.strptime(timeptr + sizeof(audit_str) - 1, "%s.%q"))) &&
- (*cp == ':')) {
- memcpy(timeptr + sizeof(audit_str) - 1, "0.0", 3);
- memmove(timeptr + sizeof(audit_str) - 1 + 3, cp, strlen(cp) + 1);
- } else {
- now = log_time(CLOCK_REALTIME);
- }
-
- // log to events
-
- size_t str_len = strnlen(str, LOGGER_ENTRY_MAX_PAYLOAD);
- if (((fdDmesg < 0) || !initialized) && !hasMetadata(str, str_len))
- auditParse(str, uid, &denial_metadata);
- str_len = (str_len + denial_metadata.length() <= LOGGER_ENTRY_MAX_PAYLOAD)
- ? str_len + denial_metadata.length()
- : LOGGER_ENTRY_MAX_PAYLOAD;
- size_t message_len = str_len + sizeof(android_log_event_string_t);
-
- unsigned int notify = 0;
-
- if (events) { // begin scope for event buffer
- uint32_t buffer[(message_len + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
-
- android_log_event_string_t* event =
- reinterpret_cast<android_log_event_string_t*>(buffer);
- event->header.tag = htole32(AUDITD_LOG_TAG);
- event->type = EVENT_TYPE_STRING;
- event->length = htole32(str_len);
- memcpy(event->data, str, str_len - denial_metadata.length());
- memcpy(event->data + str_len - denial_metadata.length(),
- denial_metadata.c_str(), denial_metadata.length());
-
- rc = logbuf->Log(LOG_ID_EVENTS, now, uid, pid, tid, reinterpret_cast<char*>(event),
- (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
- if (rc >= 0) {
- notify |= 1 << LOG_ID_EVENTS;
- }
- // end scope for event buffer
- }
-
- // log to main
-
- static const char comm_str[] = " comm=\"";
- const char* comm = strstr(str, comm_str);
- const char* estr = str + strlen(str);
- const char* commfree = nullptr;
- if (comm) {
- estr = comm;
- comm += sizeof(comm_str) - 1;
- } else if (pid == getpid()) {
- pid = tid;
- comm = "auditd";
- } else {
- comm = commfree = stats_->PidToName(pid);
- if (!comm) {
- comm = "unknown";
- }
- }
-
- const char* ecomm = strchr(comm, '"');
- if (ecomm) {
- ++ecomm;
- str_len = ecomm - comm;
- } else {
- str_len = strlen(comm) + 1;
- ecomm = "";
- }
- size_t prefix_len = estr - str;
- if (prefix_len > LOGGER_ENTRY_MAX_PAYLOAD) {
- prefix_len = LOGGER_ENTRY_MAX_PAYLOAD;
- }
- size_t suffix_len = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - prefix_len);
- message_len =
- str_len + prefix_len + suffix_len + denial_metadata.length() + 2;
-
- if (main) { // begin scope for main buffer
- char newstr[message_len];
-
- *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
- strlcpy(newstr + 1, comm, str_len);
- strncpy(newstr + 1 + str_len, str, prefix_len);
- strncpy(newstr + 1 + str_len + prefix_len, ecomm, suffix_len);
- strncpy(newstr + 1 + str_len + prefix_len + suffix_len,
- denial_metadata.c_str(), denial_metadata.length());
-
- rc = logbuf->Log(LOG_ID_MAIN, now, uid, pid, tid, newstr,
- (message_len <= UINT16_MAX) ? (uint16_t)message_len : UINT16_MAX);
-
- if (rc >= 0) {
- notify |= 1 << LOG_ID_MAIN;
- }
- // end scope for main buffer
- }
-
- free(const_cast<char*>(commfree));
- free(str);
-
- if (notify) {
- if (rc < 0) {
- rc = message_len;
- }
- }
-
- return rc;
-}
-
-int LogAudit::log(char* buf, size_t len) {
- char* audit = strstr(buf, " audit(");
- if (!audit || (audit >= &buf[len])) {
- return 0;
- }
-
- *audit = '\0';
-
- int rc;
- char* type = strstr(buf, "type=");
- if (type && (type < &buf[len])) {
- rc = logPrint("%s %s", type, audit + 1);
- } else {
- rc = logPrint("%s", audit + 1);
- }
- *audit = ' ';
- return rc;
-}
-
-int LogAudit::getLogSocket() {
- int fd = audit_open();
- if (fd < 0) {
- return fd;
- }
- if (audit_setup(fd, getpid()) < 0) {
- audit_close(fd);
- fd = -1;
- }
- return fd;
-}
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
deleted file mode 100644
index 181920e..0000000
--- a/logd/LogAudit.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#pragma once
-
-#include <map>
-
-#include <sysutils/SocketListener.h>
-
-#include "LogBuffer.h"
-#include "LogStatistics.h"
-
-class LogAudit : public SocketListener {
- LogBuffer* logbuf;
- int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
- bool main;
- bool events;
- bool initialized;
-
- public:
- LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats);
- int log(char* buf, size_t len);
-
- protected:
- virtual bool onDataAvailable(SocketClient* cli);
-
- private:
- static int getLogSocket();
- std::map<std::string, std::string> populateDenialMap();
- std::string denialParse(const std::string& denial, char terminator,
- const std::string& search_term);
- void auditParse(const std::string& string, uid_t uid, std::string* bug_num);
- int logPrint(const char* fmt, ...)
- __attribute__((__format__(__printf__, 2, 3)));
-
- LogStatistics* stats_;
-};
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
deleted file mode 100644
index a98c4b9..0000000
--- a/logd/LogBuffer.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-#include <functional>
-
-#include <log/log.h>
-#include <log/log_read.h>
-
-#include "LogWriter.h"
-
-// A mask to represent which log buffers a reader is watching, values are (1 << LOG_ID_MAIN), etc.
-using LogMask = uint32_t;
-constexpr uint32_t kLogMaskAll = 0xFFFFFFFF;
-
-// State that a LogBuffer may want to persist across calls to FlushTo().
-class FlushToState {
- public:
- FlushToState(uint64_t start, LogMask log_mask) : start_(start), log_mask_(log_mask) {}
- virtual ~FlushToState() {}
-
- uint64_t start() const { return start_; }
- void set_start(uint64_t start) { start_ = start; }
-
- LogMask log_mask() const { return log_mask_; }
-
- private:
- uint64_t start_;
- LogMask log_mask_;
-};
-
-// Enum for the return values of the `filter` function passed to FlushTo().
-enum class FilterResult {
- kSkip,
- kStop,
- kWrite,
-};
-
-class LogBuffer {
- public:
- virtual ~LogBuffer() {}
-
- virtual void Init() = 0;
-
- virtual int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len) = 0;
-
- virtual std::unique_ptr<FlushToState> CreateFlushToState(uint64_t start, LogMask log_mask) = 0;
- virtual bool FlushTo(
- LogWriter* writer, FlushToState& state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) = 0;
-
- virtual bool Clear(log_id_t id, uid_t uid) = 0;
- virtual size_t GetSize(log_id_t id) = 0;
- virtual bool SetSize(log_id_t id, size_t size) = 0;
-
- virtual uint64_t sequence() const = 0;
-};
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
deleted file mode 100644
index 26affa8..0000000
--- a/logd/LogBufferElement.cpp
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 "LogBufferElement.h"
-
-#include <ctype.h>
-#include <endian.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <log/log_read.h>
-#include <private/android_logger.h>
-
-#include "LogStatistics.h"
-#include "LogUtils.h"
-
-LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
- pid_t tid, uint64_t sequence, const char* msg, uint16_t len)
- : uid_(uid),
- pid_(pid),
- tid_(tid),
- sequence_(sequence),
- realtime_(realtime),
- msg_len_(len),
- log_id_(log_id),
- dropped_(false) {
- msg_ = new char[len];
- memcpy(msg_, msg, len);
-}
-
-LogBufferElement::LogBufferElement(const LogBufferElement& elem)
- : uid_(elem.uid_),
- pid_(elem.pid_),
- tid_(elem.tid_),
- sequence_(elem.sequence_),
- realtime_(elem.realtime_),
- msg_len_(elem.msg_len_),
- log_id_(elem.log_id_),
- dropped_(elem.dropped_) {
- if (dropped_) {
- tag_ = elem.GetTag();
- } else {
- msg_ = new char[msg_len_];
- memcpy(msg_, elem.msg_, msg_len_);
- }
-}
-
-LogBufferElement::LogBufferElement(LogBufferElement&& elem) noexcept
- : uid_(elem.uid_),
- pid_(elem.pid_),
- tid_(elem.tid_),
- sequence_(elem.sequence_),
- realtime_(elem.realtime_),
- msg_len_(elem.msg_len_),
- log_id_(elem.log_id_),
- dropped_(elem.dropped_) {
- if (dropped_) {
- tag_ = elem.GetTag();
- } else {
- msg_ = elem.msg_;
- elem.msg_ = nullptr;
- }
-}
-
-LogBufferElement::~LogBufferElement() {
- if (!dropped_) {
- delete[] msg_;
- }
-}
-
-uint32_t LogBufferElement::GetTag() const {
- // Binary buffers have no tag.
- if (!IsBinary(log_id())) {
- return 0;
- }
-
- // Dropped messages store the tag in place of msg_.
- if (dropped_) {
- return tag_;
- }
-
- return MsgToTag(msg(), msg_len());
-}
-
-LogStatisticsElement LogBufferElement::ToLogStatisticsElement() const {
- // Estimate the size of this element in the parent std::list<> by adding two void*'s
- // corresponding to the next/prev pointers and aligning to 64 bit.
- uint16_t element_in_list_size =
- (sizeof(*this) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) & -sizeof(uint64_t);
- return LogStatisticsElement{
- .uid = uid(),
- .pid = pid(),
- .tid = tid(),
- .tag = GetTag(),
- .realtime = realtime(),
- .msg = msg(),
- .msg_len = msg_len(),
- .dropped_count = dropped_count(),
- .log_id = log_id(),
- .total_len = static_cast<uint16_t>(element_in_list_size + msg_len()),
- };
-}
-
-uint16_t LogBufferElement::SetDropped(uint16_t value) {
- if (dropped_) {
- return dropped_count_ = value;
- }
-
- // The tag information is saved in msg_ data, which is in a union with tag_, used after dropped_
- // is set to true. Therefore we save the tag value aside, delete msg_, then set tag_ to the tag
- // value in its place.
- auto old_tag = GetTag();
- delete[] msg_;
- msg_ = nullptr;
-
- tag_ = old_tag;
- dropped_ = true;
- return dropped_count_ = value;
-}
-
-// caller must own and free character string
-char* android::tidToName(pid_t tid) {
- char* retval = nullptr;
- char buffer[256];
- snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);
- int fd = open(buffer, O_RDONLY | O_CLOEXEC);
- if (fd >= 0) {
- ssize_t ret = read(fd, buffer, sizeof(buffer));
- if (ret >= (ssize_t)sizeof(buffer)) {
- ret = sizeof(buffer) - 1;
- }
- while ((ret > 0) && isspace(buffer[ret - 1])) {
- --ret;
- }
- if (ret > 0) {
- buffer[ret] = '\0';
- retval = strdup(buffer);
- }
- close(fd);
- }
-
- // if nothing for comm, check out cmdline
- char* name = android::pidToName(tid);
- if (!retval) {
- retval = name;
- name = nullptr;
- }
-
- // check if comm is truncated, see if cmdline has full representation
- if (name) {
- // impossible for retval to be NULL if name not NULL
- size_t retval_len = strlen(retval);
- size_t name_len = strlen(name);
- // KISS: ToDo: Only checks prefix truncated, not suffix, or both
- if ((retval_len < name_len) &&
- !fastcmp<strcmp>(retval, name + name_len - retval_len)) {
- free(retval);
- retval = name;
- } else {
- free(name);
- }
- }
- return retval;
-}
-
-// assumption: msg_ == NULL
-size_t LogBufferElement::PopulateDroppedMessage(char*& buffer, LogStatistics* stats,
- bool lastSame) {
- static const char tag[] = "chatty";
-
- if (!__android_log_is_loggable_len(ANDROID_LOG_INFO, tag, strlen(tag),
- ANDROID_LOG_VERBOSE)) {
- return 0;
- }
-
- static const char format_uid[] = "uid=%u%s%s %s %u line%s";
- const char* name = stats->UidToName(uid_);
- const char* commName = android::tidToName(tid_);
- if (!commName && (tid_ != pid_)) {
- commName = android::tidToName(pid_);
- }
- if (!commName) {
- commName = stats->PidToName(pid_);
- }
- if (name && name[0] && commName && (name[0] == commName[0])) {
- size_t len = strlen(name + 1);
- if (!strncmp(name + 1, commName + 1, len)) {
- if (commName[len + 1] == '\0') {
- free(const_cast<char*>(commName));
- commName = nullptr;
- } else {
- free(const_cast<char*>(name));
- name = nullptr;
- }
- }
- }
- if (name) {
- char* buf = nullptr;
- int result = asprintf(&buf, "(%s)", name);
- if (result != -1) {
- free(const_cast<char*>(name));
- name = buf;
- }
- }
- if (commName) {
- char* buf = nullptr;
- int result = asprintf(&buf, " %s", commName);
- if (result != -1) {
- free(const_cast<char*>(commName));
- commName = buf;
- }
- }
- // identical to below to calculate the buffer size required
- const char* type = lastSame ? "identical" : "expire";
- size_t len = snprintf(nullptr, 0, format_uid, uid_, name ? name : "", commName ? commName : "",
- type, dropped_count(), (dropped_count() > 1) ? "s" : "");
-
- size_t hdrLen;
- if (IsBinary(log_id())) {
- hdrLen = sizeof(android_log_event_string_t);
- } else {
- hdrLen = 1 + sizeof(tag);
- }
-
- buffer = static_cast<char*>(calloc(1, hdrLen + len + 1));
- if (!buffer) {
- free(const_cast<char*>(name));
- free(const_cast<char*>(commName));
- return 0;
- }
-
- size_t retval = hdrLen + len;
- if (IsBinary(log_id())) {
- android_log_event_string_t* event =
- reinterpret_cast<android_log_event_string_t*>(buffer);
-
- event->header.tag = htole32(CHATTY_LOG_TAG);
- event->type = EVENT_TYPE_STRING;
- event->length = htole32(len);
- } else {
- ++retval;
- buffer[0] = ANDROID_LOG_INFO;
- strcpy(buffer + 1, tag);
- }
-
- snprintf(buffer + hdrLen, len + 1, format_uid, uid_, name ? name : "", commName ? commName : "",
- type, dropped_count(), (dropped_count() > 1) ? "s" : "");
- free(const_cast<char*>(name));
- free(const_cast<char*>(commName));
-
- return retval;
-}
-
-bool LogBufferElement::FlushTo(LogWriter* writer, LogStatistics* stats, bool lastSame) {
- struct logger_entry entry = {};
-
- entry.hdr_size = sizeof(struct logger_entry);
- entry.lid = log_id_;
- entry.pid = pid_;
- entry.tid = tid_;
- entry.uid = uid_;
- entry.sec = realtime_.tv_sec;
- entry.nsec = realtime_.tv_nsec;
-
- char* buffer = nullptr;
- const char* msg;
- if (dropped_) {
- entry.len = PopulateDroppedMessage(buffer, stats, lastSame);
- if (!entry.len) return true;
- msg = buffer;
- } else {
- msg = msg_;
- entry.len = msg_len_;
- }
-
- bool retval = writer->Write(entry, msg);
-
- if (buffer) free(buffer);
-
- return retval;
-}
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
deleted file mode 100644
index b263ca5..0000000
--- a/logd/LogBufferElement.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-
-#include "LogWriter.h"
-
-#include "LogStatistics.h"
-
-#define EXPIRE_HOUR_THRESHOLD 24 // Only expire chatty UID logs to preserve
- // non-chatty UIDs less than this age in hours
-#define EXPIRE_THRESHOLD 10 // A smaller expire count is considered too
- // chatty for the temporal expire messages
-#define EXPIRE_RATELIMIT 10 // maximum rate in seconds to report expiration
-
-class __attribute__((packed)) LogBufferElement {
- public:
- LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- uint64_t sequence, const char* msg, uint16_t len);
- LogBufferElement(const LogBufferElement& elem);
- LogBufferElement(LogBufferElement&& elem) noexcept;
- ~LogBufferElement();
-
- uint32_t GetTag() const;
- uint16_t SetDropped(uint16_t value);
-
- bool FlushTo(LogWriter* writer, LogStatistics* parent, bool lastSame);
-
- LogStatisticsElement ToLogStatisticsElement() const;
-
- log_id_t log_id() const { return static_cast<log_id_t>(log_id_); }
- uid_t uid() const { return uid_; }
- pid_t pid() const { return pid_; }
- pid_t tid() const { return tid_; }
- uint16_t msg_len() const { return dropped_ ? 0 : msg_len_; }
- const char* msg() const { return dropped_ ? nullptr : msg_; }
- uint64_t sequence() const { return sequence_; }
- log_time realtime() const { return realtime_; }
- uint16_t dropped_count() const { return dropped_ ? dropped_count_ : 0; }
-
- private:
- // assumption: mDropped == true
- size_t PopulateDroppedMessage(char*& buffer, LogStatistics* parent, bool lastSame);
-
- // sized to match reality of incoming log packets
- const uint32_t uid_;
- const uint32_t pid_;
- const uint32_t tid_;
- uint64_t sequence_;
- log_time realtime_;
- union {
- char* msg_; // mDropped == false
- int32_t tag_; // mDropped == true
- };
- union {
- const uint16_t msg_len_; // mDropped == false
- uint16_t dropped_count_; // mDropped == true
- };
- const uint8_t log_id_;
- bool dropped_;
-};
diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp
deleted file mode 100644
index 1911105..0000000
--- a/logd/LogBufferTest.cpp
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2020 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 "LogBufferTest.h"
-
-#include <unistd.h>
-
-#include <limits>
-#include <memory>
-#include <regex>
-#include <vector>
-
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include "LogBuffer.h"
-#include "LogReaderThread.h"
-#include "LogWriter.h"
-
-using android::base::Join;
-using android::base::Split;
-using android::base::StringPrintf;
-
-char* android::uidToName(uid_t) {
- return nullptr;
-}
-
-static std::vector<std::string> CompareLoggerEntries(const logger_entry& expected,
- const logger_entry& result, bool ignore_len) {
- std::vector<std::string> errors;
- if (!ignore_len && expected.len != result.len) {
- errors.emplace_back(
- StringPrintf("len: expected %" PRIu16 " vs %" PRIu16, expected.len, result.len));
- }
- if (expected.hdr_size != result.hdr_size) {
- errors.emplace_back(StringPrintf("hdr_size: %" PRIu16 " vs %" PRIu16, expected.hdr_size,
- result.hdr_size));
- }
- if (expected.pid != result.pid) {
- errors.emplace_back(
- StringPrintf("pid: expected %" PRIi32 " vs %" PRIi32, expected.pid, result.pid));
- }
- if (expected.tid != result.tid) {
- errors.emplace_back(
- StringPrintf("tid: expected %" PRIu32 " vs %" PRIu32, expected.tid, result.tid));
- }
- if (expected.sec != result.sec) {
- errors.emplace_back(
- StringPrintf("sec: expected %" PRIu32 " vs %" PRIu32, expected.sec, result.sec));
- }
- if (expected.nsec != result.nsec) {
- errors.emplace_back(
- StringPrintf("nsec: expected %" PRIu32 " vs %" PRIu32, expected.nsec, result.nsec));
- }
- if (expected.lid != result.lid) {
- errors.emplace_back(
- StringPrintf("lid: expected %" PRIu32 " vs %" PRIu32, expected.lid, result.lid));
- }
- if (expected.uid != result.uid) {
- errors.emplace_back(
- StringPrintf("uid: expected %" PRIu32 " vs %" PRIu32, expected.uid, result.uid));
- }
- return errors;
-}
-
-static std::string MakePrintable(std::string in) {
- if (in.size() > 80) {
- in = in.substr(0, 80) + "...";
- }
- std::string result;
- for (const char c : in) {
- if (isprint(c)) {
- result.push_back(c);
- } else {
- result.append(StringPrintf("\\%02x", static_cast<int>(c) & 0xFF));
- }
- }
- return result;
-}
-
-static std::string CompareMessages(const std::string& expected, const std::string& result) {
- if (expected == result) {
- return {};
- }
- size_t diff_index = 0;
- for (; diff_index < std::min(expected.size(), result.size()); ++diff_index) {
- if (expected[diff_index] != result[diff_index]) {
- break;
- }
- }
-
- if (diff_index < 80) {
- auto expected_short = MakePrintable(expected);
- auto result_short = MakePrintable(result);
- return StringPrintf("msg: expected '%s' vs '%s'", expected_short.c_str(),
- result_short.c_str());
- }
-
- auto expected_short = MakePrintable(expected.substr(diff_index));
- auto result_short = MakePrintable(result.substr(diff_index));
- return StringPrintf("msg: index %zu: expected '%s' vs '%s'", diff_index, expected_short.c_str(),
- result_short.c_str());
-}
-
-static std::string CompareRegexMessages(const std::string& expected, const std::string& result) {
- auto expected_pieces = Split(expected, std::string("\0", 1));
- auto result_pieces = Split(result, std::string("\0", 1));
-
- if (expected_pieces.size() != 3 || result_pieces.size() != 3) {
- return StringPrintf(
- "msg: should have 3 null delimited strings found %d in expected, %d in result: "
- "'%s' vs '%s'",
- static_cast<int>(expected_pieces.size()), static_cast<int>(result_pieces.size()),
- MakePrintable(expected).c_str(), MakePrintable(result).c_str());
- }
- if (expected_pieces[0] != result_pieces[0]) {
- return StringPrintf("msg: tag/priority mismatch expected '%s' vs '%s'",
- MakePrintable(expected_pieces[0]).c_str(),
- MakePrintable(result_pieces[0]).c_str());
- }
- std::regex expected_tag_regex(expected_pieces[1]);
- if (!std::regex_search(result_pieces[1], expected_tag_regex)) {
- return StringPrintf("msg: message regex mismatch expected '%s' vs '%s'",
- MakePrintable(expected_pieces[1]).c_str(),
- MakePrintable(result_pieces[1]).c_str());
- }
- if (expected_pieces[2] != result_pieces[2]) {
- return StringPrintf("msg: nothing expected after final null character '%s' vs '%s'",
- MakePrintable(expected_pieces[2]).c_str(),
- MakePrintable(result_pieces[2]).c_str());
- }
- return {};
-}
-
-void CompareLogMessages(const std::vector<LogMessage>& expected,
- const std::vector<LogMessage>& result) {
- EXPECT_EQ(expected.size(), result.size());
- size_t end = std::min(expected.size(), result.size());
- size_t num_errors = 0;
- for (size_t i = 0; i < end; ++i) {
- auto errors =
- CompareLoggerEntries(expected[i].entry, result[i].entry, expected[i].regex_compare);
- auto msg_error = expected[i].regex_compare
- ? CompareRegexMessages(expected[i].message, result[i].message)
- : CompareMessages(expected[i].message, result[i].message);
- if (!msg_error.empty()) {
- errors.emplace_back(msg_error);
- }
- if (!errors.empty()) {
- GTEST_LOG_(ERROR) << "Mismatch log message " << i << "\n" << Join(errors, "\n");
- ++num_errors;
- }
- }
- EXPECT_EQ(0U, num_errors);
-}
-
-void FixupMessages(std::vector<LogMessage>* messages) {
- for (auto& [entry, message, _] : *messages) {
- entry.hdr_size = sizeof(logger_entry);
- entry.len = message.size();
- }
-}
-
-TEST_P(LogBufferTest, smoke) {
- std::vector<LogMessage> log_messages = {
- {{
- .pid = 1,
- .tid = 1,
- .sec = 1234,
- .nsec = 323001,
- .lid = LOG_ID_MAIN,
- .uid = 0,
- },
- "smoke test"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, nullptr));
- std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
- EXPECT_EQ(2ULL, flush_to_state->start());
- CompareLogMessages(log_messages, read_log_messages);
-}
-
-TEST_P(LogBufferTest, smoke_with_reader_thread) {
- std::vector<LogMessage> log_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "first"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "second"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_KERNEL, .uid = 0},
- "third"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20004, .lid = LOG_ID_MAIN, .uid = 0},
- "fourth"},
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20005, .lid = LOG_ID_RADIO, .uid = 0},
- "fifth"},
- {{.pid = 2, .tid = 2, .sec = 10000, .nsec = 20006, .lid = LOG_ID_RADIO, .uid = 0},
- "sixth"},
- {{.pid = 3, .tid = 2, .sec = 10000, .nsec = 20007, .lid = LOG_ID_RADIO, .uid = 0},
- "seventh"},
- {{.pid = 4, .tid = 2, .sec = 10000, .nsec = 20008, .lid = LOG_ID_MAIN, .uid = 0},
- "eighth"},
- {{.pid = 5, .tid = 2, .sec = 10000, .nsec = 20009, .lid = LOG_ID_CRASH, .uid = 0},
- "nineth"},
- {{.pid = 6, .tid = 2, .sec = 10000, .nsec = 20011, .lid = LOG_ID_MAIN, .uid = 0},
- "tenth"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, kLogMaskAll, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
- CompareLogMessages(log_messages, read_log_messages);
-}
-
-// Generate random messages, set the 'sec' parameter explicit though, to be able to track the
-// expected order of messages.
-LogMessage GenerateRandomLogMessage(uint32_t sec) {
- auto rand_uint32 = [](int max) -> uint32_t { return rand() % max; };
- logger_entry entry = {
- .hdr_size = sizeof(logger_entry),
- .pid = rand() % 5000,
- .tid = rand_uint32(5000),
- .sec = sec,
- .nsec = rand_uint32(NS_PER_SEC),
- .lid = rand_uint32(LOG_ID_STATS),
- .uid = rand_uint32(100000),
- };
-
- // See comment in ChattyLogBuffer::Log() for why this is disallowed.
- if (entry.nsec % 1000 == 0) {
- ++entry.nsec;
- }
-
- if (entry.lid == LOG_ID_EVENTS) {
- entry.lid = LOG_ID_KERNEL;
- }
-
- std::string message;
- char priority = ANDROID_LOG_INFO + rand() % 2;
- message.push_back(priority);
-
- int tag_length = 2 + rand() % 10;
- for (int i = 0; i < tag_length; ++i) {
- message.push_back('a' + rand() % 26);
- }
- message.push_back('\0');
-
- int msg_length = 2 + rand() % 1000;
- for (int i = 0; i < msg_length; ++i) {
- message.push_back('a' + rand() % 26);
- }
- message.push_back('\0');
-
- entry.len = message.size();
-
- return {entry, message};
-}
-
-TEST_P(LogBufferTest, random_messages) {
- srand(1);
- std::vector<LogMessage> log_messages;
- for (size_t i = 0; i < 1000; ++i) {
- log_messages.emplace_back(GenerateRandomLogMessage(i));
- }
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, kLogMaskAll, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
- CompareLogMessages(log_messages, read_log_messages);
-}
-
-TEST_P(LogBufferTest, read_last_sequence) {
- std::vector<LogMessage> log_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "first"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "second"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
- "third"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
- 0, kLogMaskAll, 0, {}, 3, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
- std::vector<LogMessage> expected_log_messages = {log_messages.back()};
- CompareLogMessages(expected_log_messages, read_log_messages);
-}
-
-TEST_P(LogBufferTest, clear_logs) {
- // Log 3 initial logs.
- std::vector<LogMessage> log_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "first"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "second"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
- "third"},
- };
- FixupMessages(&log_messages);
- LogMessages(log_messages);
-
- std::vector<LogMessage> read_log_messages;
- bool released = false;
-
- // Connect a blocking reader.
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), false,
- 0, kLogMaskAll, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- // Wait up to 250ms for the reader to read the first 3 logs.
- constexpr int kMaxRetryCount = 50;
- int count = 0;
- for (; count < kMaxRetryCount; ++count) {
- usleep(5000);
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- if (reader_list_.reader_threads().back()->start() == 4) {
- break;
- }
- }
- ASSERT_LT(count, kMaxRetryCount);
-
- // Clear the log buffer.
- log_buffer_->Clear(LOG_ID_MAIN, 0);
-
- // Log 3 more logs.
- std::vector<LogMessage> after_clear_messages = {
- {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
- "4th"},
- {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
- "5th"},
- {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
- "6th"},
- };
- FixupMessages(&after_clear_messages);
- LogMessages(after_clear_messages);
-
- // Wait up to 250ms for the reader to read the 3 additional logs.
- for (count = 0; count < kMaxRetryCount; ++count) {
- usleep(5000);
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- if (reader_list_.reader_threads().back()->start() == 7) {
- break;
- }
- }
- ASSERT_LT(count, kMaxRetryCount);
-
- // Release the reader, wait for it to get the signal then check that it has been deleted.
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- reader_list_.reader_threads().back()->release_Locked();
- }
- while (!released) {
- usleep(5000);
- }
- {
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- EXPECT_EQ(0U, reader_list_.reader_threads().size());
- }
-
- // Check that we have read all 6 messages.
- std::vector<LogMessage> expected_log_messages = log_messages;
- expected_log_messages.insert(expected_log_messages.end(), after_clear_messages.begin(),
- after_clear_messages.end());
- CompareLogMessages(expected_log_messages, read_log_messages);
-
- // Finally, call FlushTo and ensure that only the 3 logs after the clear remain in the buffer.
- std::vector<LogMessage> read_log_messages_after_clear;
- std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages_after_clear, nullptr));
- std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
- EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
- EXPECT_EQ(7ULL, flush_to_state->start());
- CompareLogMessages(after_clear_messages, read_log_messages_after_clear);
-}
-
-INSTANTIATE_TEST_CASE_P(LogBufferTests, LogBufferTest,
- testing::Values("chatty", "serialized", "simple"));
diff --git a/logd/LogBufferTest.h b/logd/LogBufferTest.h
deleted file mode 100644
index eeeb980..0000000
--- a/logd/LogBufferTest.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <string>
-#include <vector>
-
-#include <gtest/gtest.h>
-
-#include "ChattyLogBuffer.h"
-#include "LogReaderList.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "PruneList.h"
-#include "SerializedLogBuffer.h"
-#include "SimpleLogBuffer.h"
-
-struct LogMessage {
- logger_entry entry;
- std::string message;
- bool regex_compare = false; // Only set for expected messages, when true 'message' should be
- // interpretted as a regex.
-};
-
-// Compares the ordered list of expected and result, causing a test failure with appropriate
-// information on failure.
-void CompareLogMessages(const std::vector<LogMessage>& expected,
- const std::vector<LogMessage>& result);
-// Sets hdr_size and len parameters appropriately.
-void FixupMessages(std::vector<LogMessage>* messages);
-
-class TestWriter : public LogWriter {
- public:
- TestWriter(std::vector<LogMessage>* msgs, bool* released)
- : LogWriter(0, true), msgs_(msgs), released_(released) {}
- bool Write(const logger_entry& entry, const char* message) override {
- msgs_->emplace_back(LogMessage{entry, std::string(message, entry.len), false});
- return true;
- }
-
- void Release() {
- if (released_) *released_ = true;
- }
-
- std::string name() const override { return "test_writer"; }
-
- private:
- std::vector<LogMessage>* msgs_;
- bool* released_;
-};
-
-class LogBufferTest : public testing::TestWithParam<std::string> {
- protected:
- void SetUp() override {
- if (GetParam() == "chatty") {
- log_buffer_.reset(new ChattyLogBuffer(&reader_list_, &tags_, &prune_, &stats_));
- } else if (GetParam() == "serialized") {
- log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, &stats_));
- } else if (GetParam() == "simple") {
- log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, &stats_));
- } else {
- FAIL() << "Unknown buffer type selected for test";
- }
-
- log_id_for_each(i) { log_buffer_->SetSize(i, 1024 * 1024); }
- }
-
- void LogMessages(const std::vector<LogMessage>& messages) {
- for (auto& [entry, message, _] : messages) {
- log_buffer_->Log(static_cast<log_id_t>(entry.lid), log_time(entry.sec, entry.nsec),
- entry.uid, entry.pid, entry.tid, message.c_str(), message.size());
- }
- }
-
- LogReaderList reader_list_;
- LogTags tags_;
- PruneList prune_;
- LogStatistics stats_{false, true};
- std::unique_ptr<LogBuffer> log_buffer_;
-};
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
deleted file mode 100644
index d6c7d25..0000000
--- a/logd/LogKlog.cpp
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogKlog.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/uio.h>
-#include <syslog.h>
-
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogBuffer.h"
-
-#define KMSG_PRIORITY(PRI) \
- '<', '0' + (LOG_SYSLOG | (PRI)) / 10, '0' + (LOG_SYSLOG | (PRI)) % 10, '>'
-
-static const char priority_message[] = { KMSG_PRIORITY(LOG_INFO), '\0' };
-
-// List of the _only_ needles we supply here to android::strnstr
-static const char suspendStr[] = "PM: suspend entry ";
-static const char resumeStr[] = "PM: suspend exit ";
-static const char suspendedStr[] = "Suspended for ";
-static const char healthdStr[] = "healthd";
-static const char batteryStr[] = ": battery ";
-static const char auditStr[] = " audit(";
-static const char klogdStr[] = "logd.klogd: ";
-
-// Parsing is hard
-
-// called if we see a '<', s is the next character, returns pointer after '>'
-static char* is_prio(char* s, ssize_t len) {
- if ((len <= 0) || !isdigit(*s++)) return nullptr;
- --len;
- static const size_t max_prio_len = (len < 4) ? len : 4;
- size_t priolen = 0;
- char c;
- while (((c = *s++)) && (++priolen <= max_prio_len)) {
- if (!isdigit(c)) return ((c == '>') && (*s == '[')) ? s : nullptr;
- }
- return nullptr;
-}
-
-// called if we see a '[', s is the next character, returns pointer after ']'
-static char* is_timestamp(char* s, ssize_t len) {
- while ((len > 0) && (*s == ' ')) {
- ++s;
- --len;
- }
- if ((len <= 0) || !isdigit(*s++)) return nullptr;
- --len;
- bool first_period = true;
- char c;
- while ((len > 0) && ((c = *s++))) {
- --len;
- if ((c == '.') && first_period) {
- first_period = false;
- } else if (!isdigit(c)) {
- return ((c == ']') && !first_period && (*s == ' ')) ? s : nullptr;
- }
- }
- return nullptr;
-}
-
-// Like strtok_r with "\r\n" except that we look for log signatures (regex)
-// \(\(<[0-9]\{1,4\}>\)\([[] *[0-9]+[.][0-9]+[]] \)\{0,1\}\|[[]
-// *[0-9]+[.][0-9]+[]] \)
-// and split if we see a second one without a newline.
-// We allow nuls in content, monitoring the overall length and sub-length of
-// the discovered tokens.
-
-#define SIGNATURE_MASK 0xF0
-// <digit> following ('0' to '9' masked with ~SIGNATURE_MASK) added to signature
-#define LESS_THAN_SIG SIGNATURE_MASK
-#define OPEN_BRACKET_SIG ((SIGNATURE_MASK << 1) & SIGNATURE_MASK)
-// space is one more than <digit> of 9
-#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
-
-char* android::log_strntok_r(char* s, ssize_t& len, char*& last,
- ssize_t& sublen) {
- sublen = 0;
- if (len <= 0) return nullptr;
- if (!s) {
- if (!(s = last)) return nullptr;
- // fixup for log signature split <,
- // LESS_THAN_SIG + <digit>
- if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) {
- *s = (*s & ~SIGNATURE_MASK) + '0';
- *--s = '<';
- ++len;
- }
- // fixup for log signature split [,
- // OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit>
- if ((*s & SIGNATURE_MASK) == OPEN_BRACKET_SIG) {
- *s = (*s == OPEN_BRACKET_SPACE) ? ' ' : (*s & ~SIGNATURE_MASK) + '0';
- *--s = '[';
- ++len;
- }
- }
-
- while ((len > 0) && ((*s == '\r') || (*s == '\n'))) {
- ++s;
- --len;
- }
-
- if (len <= 0) return last = nullptr;
- char *peek, *tok = s;
-
- for (;;) {
- if (len <= 0) {
- last = nullptr;
- return tok;
- }
- char c = *s++;
- --len;
- ssize_t adjust;
- switch (c) {
- case '\r':
- case '\n':
- s[-1] = '\0';
- last = s;
- return tok;
-
- case '<':
- peek = is_prio(s, len);
- if (!peek) break;
- if (s != (tok + 1)) { // not first?
- s[-1] = '\0';
- *s &= ~SIGNATURE_MASK;
- *s |= LESS_THAN_SIG; // signature for '<'
- last = s;
- return tok;
- }
- adjust = peek - s;
- if (adjust > len) {
- adjust = len;
- }
- sublen += adjust;
- len -= adjust;
- s = peek;
- if ((*s == '[') && ((peek = is_timestamp(s + 1, len - 1)))) {
- adjust = peek - s;
- if (adjust > len) {
- adjust = len;
- }
- sublen += adjust;
- len -= adjust;
- s = peek;
- }
- break;
-
- case '[':
- peek = is_timestamp(s, len);
- if (!peek) break;
- if (s != (tok + 1)) { // not first?
- s[-1] = '\0';
- if (*s == ' ') {
- *s = OPEN_BRACKET_SPACE;
- } else {
- *s &= ~SIGNATURE_MASK;
- *s |= OPEN_BRACKET_SIG; // signature for '['
- }
- last = s;
- return tok;
- }
- adjust = peek - s;
- if (adjust > len) {
- adjust = len;
- }
- sublen += adjust;
- len -= adjust;
- s = peek;
- break;
- }
- ++sublen;
- }
- // NOTREACHED
-}
-
-log_time LogKlog::correction = (log_time(CLOCK_REALTIME) < log_time(CLOCK_MONOTONIC))
- ? log_time(log_time::EPOCH)
- : (log_time(CLOCK_REALTIME) - log_time(CLOCK_MONOTONIC));
-
-LogKlog::LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats)
- : SocketListener(fdRead, false),
- logbuf(buf),
- signature(CLOCK_MONOTONIC),
- initialized(false),
- enableLogging(true),
- auditd(auditd),
- stats_(stats) {
- static const char klogd_message[] = "%s%s%" PRIu64 "\n";
- char buffer[strlen(priority_message) + strlen(klogdStr) +
- strlen(klogd_message) + 20];
- snprintf(buffer, sizeof(buffer), klogd_message, priority_message, klogdStr,
- signature.nsec());
- write(fdWrite, buffer, strlen(buffer));
-}
-
-bool LogKlog::onDataAvailable(SocketClient* cli) {
- if (!initialized) {
- prctl(PR_SET_NAME, "logd.klogd");
- initialized = true;
- enableLogging = false;
- }
-
- char buffer[LOGGER_ENTRY_MAX_PAYLOAD];
- ssize_t len = 0;
-
- for (;;) {
- ssize_t retval = 0;
- if (len < (ssize_t)(sizeof(buffer) - 1)) {
- retval =
- read(cli->getSocket(), buffer + len, sizeof(buffer) - 1 - len);
- }
- if ((retval == 0) && (len <= 0)) {
- break;
- }
- if (retval < 0) {
- return false;
- }
- len += retval;
- bool full = len == (sizeof(buffer) - 1);
- char* ep = buffer + len;
- *ep = '\0';
- ssize_t sublen;
- for (char *ptr = nullptr, *tok = buffer;
- !!(tok = android::log_strntok_r(tok, len, ptr, sublen));
- tok = nullptr) {
- if (((tok + sublen) >= ep) && (retval != 0) && full) {
- if (sublen > 0) memmove(buffer, tok, sublen);
- len = sublen;
- break;
- }
- if ((sublen > 0) && *tok) {
- log(tok, sublen);
- }
- }
- }
-
- return true;
-}
-
-void LogKlog::calculateCorrection(const log_time& monotonic,
- const char* real_string, ssize_t len) {
- static const char real_format[] = "%Y-%m-%d %H:%M:%S.%09q UTC";
- if (len < (ssize_t)(strlen(real_format) + 5)) return;
-
- log_time real(log_time::EPOCH);
- const char* ep = real.strptime(real_string, real_format);
- if (!ep || (ep > &real_string[len]) || (real > log_time(CLOCK_REALTIME))) {
- return;
- }
- // kernel report UTC, log_time::strptime is localtime from calendar.
- // Bionic and liblog strptime does not support %z or %Z to pick up
- // timezone so we are calculating our own correction.
- time_t now = real.tv_sec;
- struct tm tm;
- memset(&tm, 0, sizeof(tm));
- tm.tm_isdst = -1;
- localtime_r(&now, &tm);
- if ((tm.tm_gmtoff < 0) && ((-tm.tm_gmtoff) > (long)real.tv_sec)) {
- real = log_time(log_time::EPOCH);
- } else {
- real.tv_sec += tm.tm_gmtoff;
- }
- if (monotonic > real) {
- correction = log_time(log_time::EPOCH);
- } else {
- correction = real - monotonic;
- }
-}
-
-log_time LogKlog::sniffTime(const char*& buf, ssize_t len, bool reverse) {
- log_time now(log_time::EPOCH);
- if (len <= 0) return now;
-
- const char* cp = nullptr;
- if ((len > 10) && (*buf == '[')) {
- cp = now.strptime(buf, "[ %s.%q]"); // can index beyond buffer bounds
- if (cp && (cp > &buf[len - 1])) cp = nullptr;
- }
- if (cp) {
- len -= cp - buf;
- if ((len > 0) && isspace(*cp)) {
- ++cp;
- --len;
- }
- buf = cp;
-
- const char* b;
- if (((b = android::strnstr(cp, len, suspendStr))) &&
- (((b += strlen(suspendStr)) - cp) < len)) {
- len -= b - cp;
- calculateCorrection(now, b, len);
- } else if (((b = android::strnstr(cp, len, resumeStr))) &&
- (((b += strlen(resumeStr)) - cp) < len)) {
- len -= b - cp;
- calculateCorrection(now, b, len);
- } else if (((b = android::strnstr(cp, len, healthdStr))) &&
- (((b += strlen(healthdStr)) - cp) < len) &&
- ((b = android::strnstr(b, len -= b - cp, batteryStr))) &&
- (((b += strlen(batteryStr)) - cp) < len)) {
- // NB: healthd is roughly 150us late, so we use it instead to
- // trigger a check for ntp-induced or hardware clock drift.
- log_time real(CLOCK_REALTIME);
- log_time mono(CLOCK_MONOTONIC);
- correction = (real < mono) ? log_time(log_time::EPOCH) : (real - mono);
- } else if (((b = android::strnstr(cp, len, suspendedStr))) &&
- (((b += strlen(suspendStr)) - cp) < len)) {
- len -= b - cp;
- log_time real(log_time::EPOCH);
- char* endp;
- real.tv_sec = strtol(b, &endp, 10);
- if ((*endp == '.') && ((endp - b) < len)) {
- unsigned long multiplier = NS_PER_SEC;
- real.tv_nsec = 0;
- len -= endp - b;
- while (--len && isdigit(*++endp) && (multiplier /= 10)) {
- real.tv_nsec += (*endp - '0') * multiplier;
- }
- if (reverse) {
- if (real > correction) {
- correction = log_time(log_time::EPOCH);
- } else {
- correction -= real;
- }
- } else {
- correction += real;
- }
- }
- }
-
- convertMonotonicToReal(now);
- } else {
- now = log_time(CLOCK_REALTIME);
- }
- return now;
-}
-
-pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) {
- if (len <= 0) return 0;
-
- const char* cp = buf;
- // sscanf does a strlen, let's check if the string is not nul terminated.
- // pseudo out-of-bounds access since we always have an extra char on buffer.
- if (((ssize_t)strnlen(cp, len) == len) && cp[len]) {
- return 0;
- }
- // HTC kernels with modified printk "c0 1648 "
- if ((len > 9) && (cp[0] == 'c') && isdigit(cp[1]) &&
- (isdigit(cp[2]) || (cp[2] == ' ')) && (cp[3] == ' ')) {
- bool gotDigit = false;
- int i;
- for (i = 4; i < 9; ++i) {
- if (isdigit(cp[i])) {
- gotDigit = true;
- } else if (gotDigit || (cp[i] != ' ')) {
- break;
- }
- }
- if ((i == 9) && (cp[i] == ' ')) {
- int pid = 0;
- char placeholder;
- if (sscanf(cp + 4, "%d%c", &pid, &placeholder) == 2) {
- buf = cp + 10; // skip-it-all
- return pid;
- }
- }
- }
- while (len) {
- // Mediatek kernels with modified printk
- if (*cp == '[') {
- int pid = 0;
- char placeholder;
- if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &placeholder) == 2) {
- return pid;
- }
- break; // Only the first one
- }
- ++cp;
- --len;
- }
- return 0;
-}
-
-// kernel log prefix, convert to a kernel log priority number
-static int parseKernelPrio(const char*& buf, ssize_t len) {
- int pri = LOG_USER | LOG_INFO;
- const char* cp = buf;
- if ((len > 0) && (*cp == '<')) {
- pri = 0;
- while (--len && isdigit(*++cp)) {
- pri = (pri * 10) + *cp - '0';
- }
- if ((len > 0) && (*cp == '>')) {
- ++cp;
- } else {
- cp = buf;
- pri = LOG_USER | LOG_INFO;
- }
- buf = cp;
- }
- return pri;
-}
-
-// Convert kernel log priority number into an Android Logger priority number
-static int convertKernelPrioToAndroidPrio(int pri) {
- switch (pri & LOG_PRIMASK) {
- case LOG_EMERG:
- case LOG_ALERT:
- case LOG_CRIT:
- return ANDROID_LOG_FATAL;
-
- case LOG_ERR:
- return ANDROID_LOG_ERROR;
-
- case LOG_WARNING:
- return ANDROID_LOG_WARN;
-
- default:
- case LOG_NOTICE:
- case LOG_INFO:
- break;
-
- case LOG_DEBUG:
- return ANDROID_LOG_DEBUG;
- }
-
- return ANDROID_LOG_INFO;
-}
-
-static const char* strnrchr(const char* s, ssize_t len, char c) {
- const char* save = nullptr;
- for (; len > 0; ++s, len--) {
- if (*s == c) {
- save = s;
- }
- }
- return save;
-}
-
-//
-// log a message into the kernel log buffer
-//
-// Filter rules to parse <PRI> <TIME> <tag> and <message> in order for
-// them to appear correct in the logcat output:
-//
-// LOG_KERN (0):
-// <PRI>[<TIME>] <tag> ":" <message>
-// <PRI>[<TIME>] <tag> <tag> ":" <message>
-// <PRI>[<TIME>] <tag> <tag>_work ":" <message>
-// <PRI>[<TIME>] <tag> '<tag>.<num>' ":" <message>
-// <PRI>[<TIME>] <tag> '<tag><num>' ":" <message>
-// <PRI>[<TIME>] <tag>_host '<tag>.<num>' ":" <message>
-// (unimplemented) <PRI>[<TIME>] <tag> '<num>.<tag>' ":" <message>
-// <PRI>[<TIME>] "[INFO]"<tag> : <message>
-// <PRI>[<TIME>] "------------[ cut here ]------------" (?)
-// <PRI>[<TIME>] "---[ end trace 3225a3070ca3e4ac ]---" (?)
-// LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_SYSLOG, LOG_LPR, LOG_NEWS
-// LOG_UUCP, LOG_CRON, LOG_AUTHPRIV, LOG_FTP:
-// <PRI+TAG>[<TIME>] (see sys/syslog.h)
-// Observe:
-// Minimum tag length = 3 NB: drops things like r5:c00bbadf, but allow PM:
-// Maximum tag words = 2
-// Maximum tag length = 16 NB: we are thinking of how ugly logcat can get.
-// Not a Tag if there is no message content.
-// leading additional spaces means no tag, inherit last tag.
-// Not a Tag if <tag>: is "ERROR:", "WARNING:", "INFO:" or "CPU:"
-// Drop:
-// empty messages
-// messages with ' audit(' in them if auditd is running
-// logd.klogd:
-// return -1 if message logd.klogd: <signature>
-//
-int LogKlog::log(const char* buf, ssize_t len) {
- if (auditd && android::strnstr(buf, len, auditStr)) {
- return 0;
- }
-
- const char* p = buf;
- int pri = parseKernelPrio(p, len);
-
- log_time now = sniffTime(p, len - (p - buf), false);
-
- // sniff for start marker
- const char* start = android::strnstr(p, len - (p - buf), klogdStr);
- if (start) {
- uint64_t sig = strtoll(start + strlen(klogdStr), nullptr, 10);
- if (sig == signature.nsec()) {
- if (initialized) {
- enableLogging = true;
- } else {
- enableLogging = false;
- }
- return -1;
- }
- return 0;
- }
-
- if (!enableLogging) {
- return 0;
- }
-
- // Parse pid, tid and uid
- const pid_t pid = sniffPid(p, len - (p - buf));
- const pid_t tid = pid;
- uid_t uid = AID_ROOT;
- if (pid) {
- uid = stats_->PidToUid(pid);
- }
-
- // Parse (rules at top) to pull out a tag from the incoming kernel message.
- // Some may view the following as an ugly heuristic, the desire is to
- // beautify the kernel logs into an Android Logging format; the goal is
- // admirable but costly.
- while ((p < &buf[len]) && (isspace(*p) || !*p)) {
- ++p;
- }
- if (p >= &buf[len]) { // timestamp, no content
- return 0;
- }
- start = p;
- const char* tag = "";
- const char* etag = tag;
- ssize_t taglen = len - (p - buf);
- const char* bt = p;
-
- static const char infoBrace[] = "[INFO]";
- static const ssize_t infoBraceLen = strlen(infoBrace);
- if ((taglen >= infoBraceLen) &&
- !fastcmp<strncmp>(p, infoBrace, infoBraceLen)) {
- // <PRI>[<TIME>] "[INFO]"<tag> ":" message
- bt = p + infoBraceLen;
- taglen -= infoBraceLen;
- }
-
- const char* et;
- for (et = bt; (taglen > 0) && *et && (*et != ':') && !isspace(*et);
- ++et, --taglen) {
- // skip ':' within [ ... ]
- if (*et == '[') {
- while ((taglen > 0) && *et && *et != ']') {
- ++et;
- --taglen;
- }
- if (taglen <= 0) {
- break;
- }
- }
- }
- const char* cp;
- for (cp = et; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
- }
-
- // Validate tag
- ssize_t size = et - bt;
- if ((taglen > 0) && (size > 0)) {
- if (*cp == ':') {
- // ToDo: handle case insensitive colon separated logging stutter:
- // <tag> : <tag>: ...
-
- // One Word
- tag = bt;
- etag = et;
- p = cp + 1;
- } else if ((taglen > size) && (tolower(*bt) == tolower(*cp))) {
- // clean up any tag stutter
- if (!fastcmp<strncasecmp>(bt + 1, cp + 1, size - 1)) { // no match
- // <PRI>[<TIME>] <tag> <tag> : message
- // <PRI>[<TIME>] <tag> <tag>: message
- // <PRI>[<TIME>] <tag> '<tag>.<num>' : message
- // <PRI>[<TIME>] <tag> '<tag><num>' : message
- // <PRI>[<TIME>] <tag> '<tag><stuff>' : message
- const char* b = cp;
- cp += size;
- taglen -= size;
- while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) {
- }
- const char* e;
- for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
- }
- if ((taglen > 0) && (*cp == ':')) {
- tag = b;
- etag = e;
- p = cp + 1;
- }
- } else {
- // what about <PRI>[<TIME>] <tag>_host '<tag><stuff>' : message
- static const char host[] = "_host";
- static const ssize_t hostlen = strlen(host);
- if ((size > hostlen) &&
- !fastcmp<strncmp>(bt + size - hostlen, host, hostlen) &&
- !fastcmp<strncmp>(bt + 1, cp + 1, size - hostlen - 1)) {
- const char* b = cp;
- cp += size - hostlen;
- taglen -= size - hostlen;
- if (*cp == '.') {
- while ((--taglen > 0) && !isspace(*++cp) &&
- (*cp != ':')) {
- }
- const char* e;
- for (e = cp; (taglen > 0) && isspace(*cp);
- ++cp, --taglen) {
- }
- if ((taglen > 0) && (*cp == ':')) {
- tag = b;
- etag = e;
- p = cp + 1;
- }
- }
- } else {
- goto twoWord;
- }
- }
- } else {
- // <PRI>[<TIME>] <tag> <stuff>' : message
- twoWord:
- while ((--taglen > 0) && !isspace(*++cp) && (*cp != ':')) {
- }
- const char* e;
- for (e = cp; (taglen > 0) && isspace(*cp); ++cp, --taglen) {
- }
- // Two words
- if ((taglen > 0) && (*cp == ':')) {
- tag = bt;
- etag = e;
- p = cp + 1;
- }
- }
- } // else no tag
-
- static const char cpu[] = "CPU";
- static const ssize_t cpuLen = strlen(cpu);
- static const char warning[] = "WARNING";
- static const ssize_t warningLen = strlen(warning);
- static const char error[] = "ERROR";
- static const ssize_t errorLen = strlen(error);
- static const char info[] = "INFO";
- static const ssize_t infoLen = strlen(info);
-
- size = etag - tag;
- if ((size <= 1) ||
- // register names like x9
- ((size == 2) && (isdigit(tag[0]) || isdigit(tag[1]))) ||
- // register names like x18 but not driver names like en0
- ((size == 3) && (isdigit(tag[1]) && isdigit(tag[2]))) ||
- // ignore
- ((size == cpuLen) && !fastcmp<strncmp>(tag, cpu, cpuLen)) ||
- ((size == warningLen) && !fastcmp<strncasecmp>(tag, warning, warningLen)) ||
- ((size == errorLen) && !fastcmp<strncasecmp>(tag, error, errorLen)) ||
- ((size == infoLen) && !fastcmp<strncasecmp>(tag, info, infoLen))) {
- p = start;
- etag = tag = "";
- }
-
- // Suppress additional stutter in tag:
- // eg: [143:healthd]healthd -> [143:healthd]
- taglen = etag - tag;
- // Mediatek-special printk induced stutter
- const char* mp = strnrchr(tag, taglen, ']');
- if (mp && (++mp < etag)) {
- ssize_t s = etag - mp;
- if (((s + s) < taglen) && !fastcmp<memcmp>(mp, mp - 1 - s, s)) {
- taglen = mp - tag;
- }
- }
- // Deal with sloppy and simplistic harmless p = cp + 1 etc above.
- if (len < (p - buf)) {
- p = &buf[len];
- }
- // skip leading space
- while ((p < &buf[len]) && (isspace(*p) || !*p)) {
- ++p;
- }
- // truncate trailing space or nuls
- ssize_t b = len - (p - buf);
- while ((b > 0) && (isspace(p[b - 1]) || !p[b - 1])) {
- --b;
- }
- // trick ... allow tag with empty content to be logged. log() drops empty
- if ((b <= 0) && (taglen > 0)) {
- p = " ";
- b = 1;
- }
- // This shouldn't happen, but clamp the size if it does.
- if (b > LOGGER_ENTRY_MAX_PAYLOAD) {
- b = LOGGER_ENTRY_MAX_PAYLOAD;
- }
- if (taglen > LOGGER_ENTRY_MAX_PAYLOAD) {
- taglen = LOGGER_ENTRY_MAX_PAYLOAD;
- }
- // calculate buffer copy requirements
- ssize_t n = 1 + taglen + 1 + b + 1;
- // Extra checks for likely impossible cases.
- if ((taglen > n) || (b > n) || (n > (ssize_t)USHRT_MAX) || (n <= 0)) {
- return -EINVAL;
- }
-
- // Careful.
- // We are using the stack to house the log buffer for speed reasons.
- // If we malloc'd this buffer, we could get away without n's USHRT_MAX
- // test above, but we would then required a max(n, USHRT_MAX) as
- // truncating length argument to logbuf->log() below. Gain is protection
- // against stack corruption and speedup, loss is truncated long-line content.
- char newstr[n];
- char* np = newstr;
-
- // Convert priority into single-byte Android logger priority
- *np = convertKernelPrioToAndroidPrio(pri);
- ++np;
-
- // Copy parsed tag following priority
- memcpy(np, tag, taglen);
- np += taglen;
- *np = '\0';
- ++np;
-
- // Copy main message to the remainder
- memcpy(np, p, b);
- np[b] = '\0';
-
- {
- // Watch out for singular race conditions with timezone causing near
- // integer quarter-hour jumps in the time and compensate accordingly.
- // Entries will be temporal within near_seconds * 2. b/21868540
- static uint32_t vote_time[3];
- vote_time[2] = vote_time[1];
- vote_time[1] = vote_time[0];
- vote_time[0] = now.tv_sec;
-
- if (vote_time[1] && vote_time[2]) {
- static const unsigned near_seconds = 10;
- static const unsigned timezones_seconds = 900;
- int diff0 = (vote_time[0] - vote_time[1]) / near_seconds;
- unsigned abs0 = (diff0 < 0) ? -diff0 : diff0;
- int diff1 = (vote_time[1] - vote_time[2]) / near_seconds;
- unsigned abs1 = (diff1 < 0) ? -diff1 : diff1;
- if ((abs1 <= 1) && // last two were in agreement on timezone
- ((abs0 + 1) % (timezones_seconds / near_seconds)) <= 2) {
- abs0 = (abs0 + 1) / (timezones_seconds / near_seconds) *
- timezones_seconds;
- now.tv_sec -= (diff0 < 0) ? -abs0 : abs0;
- }
- }
- }
-
- // Log message
- int rc = logbuf->Log(LOG_ID_KERNEL, now, uid, pid, tid, newstr, (uint16_t)n);
-
- return rc;
-}
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
deleted file mode 100644
index 56e0452..0000000
--- a/logd/LogKlog.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#pragma once
-
-#include <private/android_logger.h>
-#include <sysutils/SocketListener.h>
-
-#include "LogBuffer.h"
-#include "LogStatistics.h"
-
-class LogKlog : public SocketListener {
- LogBuffer* logbuf;
- const log_time signature;
- // Set once thread is started, separates KLOG_ACTION_READ_ALL
- // and KLOG_ACTION_READ phases.
- bool initialized;
- // Used during each of the above phases to control logging.
- bool enableLogging;
- // set if we are also running auditd, to filter out audit reports from
- // our copy of the kernel log
- bool auditd;
-
- static log_time correction;
-
- public:
- LogKlog(LogBuffer* buf, int fdWrite, int fdRead, bool auditd, LogStatistics* stats);
- int log(const char* buf, ssize_t len);
-
- static void convertMonotonicToReal(log_time& real) { real += correction; }
-
- protected:
- log_time sniffTime(const char*& buf, ssize_t len, bool reverse);
- pid_t sniffPid(const char*& buf, ssize_t len);
- void calculateCorrection(const log_time& monotonic, const char* real_string, ssize_t len);
- virtual bool onDataAvailable(SocketClient* cli);
-
- private:
- LogStatistics* stats_;
-};
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
deleted file mode 100644
index a6ab50b..0000000
--- a/logd/LogListener.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 <limits.h>
-#include <sys/cdefs.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/un.h>
-#include <unistd.h>
-
-#include <thread>
-
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogBuffer.h"
-#include "LogListener.h"
-#include "LogPermissions.h"
-
-LogListener::LogListener(LogBuffer* buf) : socket_(GetLogSocket()), logbuf_(buf) {}
-
-bool LogListener::StartListener() {
- if (socket_ <= 0) {
- return false;
- }
- auto thread = std::thread(&LogListener::ThreadFunction, this);
- thread.detach();
- return true;
-}
-
-void LogListener::ThreadFunction() {
- prctl(PR_SET_NAME, "logd.writer");
-
- while (true) {
- HandleData();
- }
-}
-
-void LogListener::HandleData() {
- // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
- __attribute__((uninitialized)) char
- buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
- struct iovec iov = {buffer, sizeof(buffer) - 1};
-
- alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
- struct msghdr hdr = {
- nullptr, 0, &iov, 1, control, sizeof(control), 0,
- };
-
- // To clear the entire buffer is secure/safe, but this contributes to 1.68%
- // overhead under logging load. We are safe because we check counts, but
- // still need to clear null terminator
- // memset(buffer, 0, sizeof(buffer));
- ssize_t n = recvmsg(socket_, &hdr, 0);
- if (n <= (ssize_t)(sizeof(android_log_header_t))) {
- return;
- }
-
- buffer[n] = 0;
-
- struct ucred* cred = nullptr;
-
- struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
- while (cmsg != nullptr) {
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS) {
- cred = (struct ucred*)CMSG_DATA(cmsg);
- break;
- }
- cmsg = CMSG_NXTHDR(&hdr, cmsg);
- }
-
- if (cred == nullptr) {
- return;
- }
-
- if (cred->uid == AID_LOGD) {
- // ignore log messages we send to ourself.
- // Such log messages are often generated by libraries we depend on
- // which use standard Android logging.
- return;
- }
-
- android_log_header_t* header =
- reinterpret_cast<android_log_header_t*>(buffer);
- log_id_t logId = static_cast<log_id_t>(header->id);
- if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
- logId == LOG_ID_KERNEL) {
- return;
- }
-
- if ((logId == LOG_ID_SECURITY) &&
- (!__android_log_security() ||
- !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
- return;
- }
-
- char* msg = ((char*)buffer) + sizeof(android_log_header_t);
- n -= sizeof(android_log_header_t);
-
- // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
- // truncated message to the logs.
-
- logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
- ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
-}
-
-int LogListener::GetLogSocket() {
- static const char socketName[] = "logdw";
- int sock = android_get_control_socket(socketName);
-
- if (sock < 0) { // logd started up in init.sh
- sock = socket_local_server(
- socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);
-
- int on = 1;
- if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
- return -1;
- }
- }
- return sock;
-}
diff --git a/logd/LogListener.h b/logd/LogListener.h
deleted file mode 100644
index 566af5b..0000000
--- a/logd/LogListener.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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.
- */
-
-#pragma once
-
-#include "LogBuffer.h"
-
-class LogListener {
- public:
- explicit LogListener(LogBuffer* buf);
- bool StartListener();
-
- private:
- void ThreadFunction();
- void HandleData();
- static int GetLogSocket();
-
- int socket_;
- LogBuffer* logbuf_;
-};
diff --git a/logd/LogPermissions.cpp b/logd/LogPermissions.cpp
deleted file mode 100644
index 3fd0ea1..0000000
--- a/logd/LogPermissions.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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 "LogPermissions.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <private/android_filesystem_config.h>
-
-// gets a list of supplementary group IDs associated with
-// the socket peer. This is implemented by opening
-// /proc/PID/status and look for the "Group:" line.
-//
-// This function introduces races especially since status
-// can change 'shape' while reading, the net result is err
-// on lack of permission.
-//
-// Race-free alternative is to introduce pairs of sockets
-// and threads for each command and reading, one each that
-// has open permissions, and one that has restricted
-// permissions.
-
-static bool groupIsLog(char* buf) {
- char* ptr;
- static const char ws[] = " \n";
-
- for (buf = strtok_r(buf, ws, &ptr); buf; buf = strtok_r(nullptr, ws, &ptr)) {
- errno = 0;
- gid_t Gid = strtol(buf, nullptr, 10);
- if (errno != 0) {
- return false;
- }
- if (Gid == AID_LOG) {
- return true;
- }
- }
- return false;
-}
-
-bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
- if ((uid == AID_ROOT) || (uid == AID_SYSTEM) || (uid == AID_LOG)) {
- return true;
- }
-
- if ((gid == AID_ROOT) || (gid == AID_SYSTEM) || (gid == AID_LOG)) {
- return true;
- }
-
- // FYI We will typically be here for 'adb logcat'
- char filename[256];
- snprintf(filename, sizeof(filename), "/proc/%u/status", pid);
-
- bool ret;
- bool foundLog = false;
- bool foundGid = false;
- bool foundUid = false;
-
- //
- // Reading /proc/<pid>/status is rife with race conditions. All of /proc
- // suffers from this and its use should be minimized. However, we have no
- // choice.
- //
- // Notably the content from one 4KB page to the next 4KB page can be from a
- // change in shape even if we are gracious enough to attempt to read
- // atomically. getline can not even guarantee a page read is not split up
- // and in effect can read from different vintages of the content.
- //
- // We are finding out in the field that a 'logcat -c' via adb occasionally
- // is returned with permission denied when we did only one pass and thus
- // breaking scripts. For security we still err on denying access if in
- // doubt, but we expect the falses should be reduced significantly as
- // three times is a charm.
- //
- for (int retry = 3; !(ret = foundGid && foundUid && foundLog) && retry;
- --retry) {
- FILE* file = fopen(filename, "re");
- if (!file) {
- continue;
- }
-
- char* line = nullptr;
- size_t len = 0;
- while (getline(&line, &len, file) > 0) {
- static const char groups_string[] = "Groups:\t";
- static const char uid_string[] = "Uid:\t";
- static const char gid_string[] = "Gid:\t";
-
- if (strncmp(groups_string, line, sizeof(groups_string) - 1) == 0) {
- if (groupIsLog(line + sizeof(groups_string) - 1)) {
- foundLog = true;
- }
- } else if (strncmp(uid_string, line, sizeof(uid_string) - 1) == 0) {
- uid_t u[4] = { (uid_t)-1, (uid_t)-1, (uid_t)-1, (uid_t)-1 };
-
- sscanf(line + sizeof(uid_string) - 1, "%u\t%u\t%u\t%u", &u[0],
- &u[1], &u[2], &u[3]);
-
- // Protect against PID reuse by checking that UID is the same
- if ((uid == u[0]) && (uid == u[1]) && (uid == u[2]) &&
- (uid == u[3])) {
- foundUid = true;
- }
- } else if (strncmp(gid_string, line, sizeof(gid_string) - 1) == 0) {
- gid_t g[4] = { (gid_t)-1, (gid_t)-1, (gid_t)-1, (gid_t)-1 };
-
- sscanf(line + sizeof(gid_string) - 1, "%u\t%u\t%u\t%u", &g[0],
- &g[1], &g[2], &g[3]);
-
- // Protect against PID reuse by checking that GID is the same
- if ((gid == g[0]) && (gid == g[1]) && (gid == g[2]) &&
- (gid == g[3])) {
- foundGid = true;
- }
- }
- }
- free(line);
- fclose(file);
- }
-
- return ret;
-}
-
-bool clientHasLogCredentials(SocketClient* cli) {
- return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid());
-}
diff --git a/logd/LogPermissions.h b/logd/LogPermissions.h
deleted file mode 100644
index 3130db5..0000000
--- a/logd/LogPermissions.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2012-2014 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.
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-#include <sysutils/SocketClient.h>
-
-bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
-bool clientHasLogCredentials(SocketClient* cli);
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
deleted file mode 100644
index 6c97693..0000000
--- a/logd/LogReader.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 <ctype.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <chrono>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogPermissions.h"
-#include "LogReader.h"
-#include "LogUtils.h"
-#include "LogWriter.h"
-
-static bool CanReadSecurityLogs(SocketClient* client) {
- return client->getUid() == AID_SYSTEM || client->getGid() == AID_SYSTEM;
-}
-
-static std::string SocketClientToName(SocketClient* client) {
- return android::base::StringPrintf("pid %d, fd %d", client->getPid(), client->getSocket());
-}
-
-class SocketLogWriter : public LogWriter {
- public:
- SocketLogWriter(LogReader* reader, SocketClient* client, bool privileged)
- : LogWriter(client->getUid(), privileged), reader_(reader), client_(client) {}
-
- bool Write(const logger_entry& entry, const char* msg) override {
- struct iovec iovec[2];
- iovec[0].iov_base = const_cast<logger_entry*>(&entry);
- iovec[0].iov_len = entry.hdr_size;
- iovec[1].iov_base = const_cast<char*>(msg);
- iovec[1].iov_len = entry.len;
-
- return client_->sendDatav(iovec, 1 + (entry.len != 0)) == 0;
- }
-
- void Release() override {
- reader_->release(client_);
- client_->decRef();
- }
-
- void Shutdown() override { shutdown(client_->getSocket(), SHUT_RDWR); }
-
- std::string name() const override { return SocketClientToName(client_); }
-
- private:
- LogReader* reader_;
- SocketClient* client_;
-};
-
-LogReader::LogReader(LogBuffer* logbuf, LogReaderList* reader_list)
- : SocketListener(getLogSocket(), true), log_buffer_(logbuf), reader_list_(reader_list) {}
-
-// Note returning false will release the SocketClient instance.
-bool LogReader::onDataAvailable(SocketClient* cli) {
- static bool name_set;
- if (!name_set) {
- prctl(PR_SET_NAME, "logd.reader");
- name_set = true;
- }
-
- char buffer[255];
-
- int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
- if (len <= 0) {
- DoSocketDelete(cli);
- return false;
- }
- buffer[len] = '\0';
-
- // Clients are only allowed to send one command, disconnect them if they send another.
- if (DoSocketDelete(cli)) {
- return false;
- }
-
- unsigned long tail = 0;
- static const char _tail[] = " tail=";
- char* cp = strstr(buffer, _tail);
- if (cp) {
- tail = atol(cp + sizeof(_tail) - 1);
- }
-
- log_time start(log_time::EPOCH);
- static const char _start[] = " start=";
- cp = strstr(buffer, _start);
- if (cp) {
- // Parse errors will result in current time
- start.strptime(cp + sizeof(_start) - 1, "%s.%q");
- }
-
- std::chrono::steady_clock::time_point deadline = {};
- static const char _timeout[] = " timeout=";
- cp = strstr(buffer, _timeout);
- if (cp) {
- long timeout_seconds = atol(cp + sizeof(_timeout) - 1);
- deadline = std::chrono::steady_clock::now() + std::chrono::seconds(timeout_seconds);
- }
-
- unsigned int logMask = -1;
- static const char _logIds[] = " lids=";
- cp = strstr(buffer, _logIds);
- if (cp) {
- logMask = 0;
- cp += sizeof(_logIds) - 1;
- while (*cp != '\0') {
- int val = 0;
- while (isdigit(*cp)) {
- val = val * 10 + *cp - '0';
- ++cp;
- }
- logMask |= 1 << val;
- if (*cp != ',') {
- break;
- }
- ++cp;
- }
- }
-
- pid_t pid = 0;
- static const char _pid[] = " pid=";
- cp = strstr(buffer, _pid);
- if (cp) {
- pid = atol(cp + sizeof(_pid) - 1);
- }
-
- bool nonBlock = false;
- if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
- // Allow writer to get some cycles, and wait for pending notifications
- sched_yield();
- reader_list_->reader_threads_lock().lock();
- reader_list_->reader_threads_lock().unlock();
- sched_yield();
- nonBlock = true;
- }
-
- bool privileged = clientHasLogCredentials(cli);
- bool can_read_security = CanReadSecurityLogs(cli);
- if (!can_read_security) {
- logMask &= ~(1 << LOG_ID_SECURITY);
- }
-
- std::unique_ptr<LogWriter> socket_log_writer(new SocketLogWriter(this, cli, privileged));
-
- uint64_t sequence = 1;
- // Convert realtime to sequence number
- if (start != log_time::EPOCH) {
- bool start_time_set = false;
- uint64_t last = sequence;
- auto log_find_start = [pid, start, &sequence, &start_time_set, &last](
- log_id_t, pid_t element_pid, uint64_t element_sequence,
- log_time element_realtime) -> FilterResult {
- if (pid && pid != element_pid) {
- return FilterResult::kSkip;
- }
- if (start == element_realtime) {
- sequence = element_sequence;
- start_time_set = true;
- return FilterResult::kStop;
- } else {
- if (start < element_realtime) {
- sequence = last;
- start_time_set = true;
- return FilterResult::kStop;
- }
- last = element_sequence;
- }
- return FilterResult::kSkip;
- };
- auto flush_to_state = log_buffer_->CreateFlushToState(sequence, logMask);
- log_buffer_->FlushTo(socket_log_writer.get(), *flush_to_state, log_find_start);
-
- if (!start_time_set) {
- if (nonBlock) {
- return false;
- }
- sequence = log_buffer_->sequence();
- }
- }
-
- LOG(INFO) << android::base::StringPrintf(
- "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
- "start=%" PRIu64 "ns deadline=%" PRIi64 "ns",
- cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail, logMask,
- (int)pid, start.nsec(), static_cast<int64_t>(deadline.time_since_epoch().count()));
-
- if (start == log_time::EPOCH) {
- deadline = {};
- }
-
- auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
- auto entry = std::make_unique<LogReaderThread>(log_buffer_, reader_list_,
- std::move(socket_log_writer), nonBlock, tail,
- logMask, pid, start, sequence, deadline);
- // release client and entry reference counts once done
- cli->incRef();
- reader_list_->reader_threads().emplace_front(std::move(entry));
-
- // Set acceptable upper limit to wait for slow reader processing b/27242723
- struct timeval t = { LOGD_SNDTIMEO, 0 };
- setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
- sizeof(t));
-
- return true;
-}
-
-bool LogReader::DoSocketDelete(SocketClient* cli) {
- auto cli_name = SocketClientToName(cli);
- auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
- for (const auto& reader : reader_list_->reader_threads()) {
- if (reader->name() == cli_name) {
- reader->release_Locked();
- return true;
- }
- }
- return false;
-}
-
-int LogReader::getLogSocket() {
- static const char socketName[] = "logdr";
- int sock = android_get_control_socket(socketName);
-
- if (sock < 0) {
- sock = socket_local_server(
- socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET);
- }
-
- return sock;
-}
diff --git a/logd/LogReader.h b/logd/LogReader.h
deleted file mode 100644
index a4e52c4..0000000
--- a/logd/LogReader.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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.
- */
-
-#pragma once
-
-#include <sysutils/SocketListener.h>
-
-#include "LogBuffer.h"
-#include "LogReaderList.h"
-#include "LogReaderThread.h"
-
-class LogReader : public SocketListener {
- public:
- explicit LogReader(LogBuffer* logbuf, LogReaderList* reader_list);
-
- protected:
- virtual bool onDataAvailable(SocketClient* cli);
-
- private:
- static int getLogSocket();
-
- bool DoSocketDelete(SocketClient* cli);
-
- LogBuffer* log_buffer_;
- LogReaderList* reader_list_;
-};
diff --git a/logd/LogReaderList.cpp b/logd/LogReaderList.cpp
deleted file mode 100644
index 32ba291..0000000
--- a/logd/LogReaderList.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2020 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 "LogReaderList.h"
-
-// When we are notified a new log entry is available, inform
-// listening sockets who are watching this entry's log id.
-void LogReaderList::NotifyNewLog(LogMask log_mask) const {
- auto lock = std::lock_guard{reader_threads_lock_};
-
- for (const auto& entry : reader_threads_) {
- if (!entry->IsWatchingMultiple(log_mask)) {
- continue;
- }
- if (entry->deadline().time_since_epoch().count() != 0) {
- continue;
- }
- entry->triggerReader_Locked();
- }
-}
diff --git a/logd/LogReaderList.h b/logd/LogReaderList.h
deleted file mode 100644
index 594716a..0000000
--- a/logd/LogReaderList.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <list>
-#include <memory>
-#include <mutex>
-
-#include "LogBuffer.h"
-#include "LogReaderThread.h"
-
-class LogReaderList {
- public:
- void NotifyNewLog(LogMask log_mask) const;
-
- std::list<std::unique_ptr<LogReaderThread>>& reader_threads() { return reader_threads_; }
- std::mutex& reader_threads_lock() { return reader_threads_lock_; }
-
- private:
- std::list<std::unique_ptr<LogReaderThread>> reader_threads_;
- mutable std::mutex reader_threads_lock_;
-};
\ No newline at end of file
diff --git a/logd/LogReaderThread.cpp b/logd/LogReaderThread.cpp
deleted file mode 100644
index 4a8be01..0000000
--- a/logd/LogReaderThread.cpp
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogReaderThread.h"
-
-#include <errno.h>
-#include <string.h>
-#include <sys/prctl.h>
-
-#include <thread>
-
-#include "LogBuffer.h"
-#include "LogReaderList.h"
-
-LogReaderThread::LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
- std::unique_ptr<LogWriter> writer, bool non_block,
- unsigned long tail, LogMask log_mask, pid_t pid,
- log_time start_time, uint64_t start,
- std::chrono::steady_clock::time_point deadline)
- : log_buffer_(log_buffer),
- reader_list_(reader_list),
- writer_(std::move(writer)),
- pid_(pid),
- tail_(tail),
- count_(0),
- index_(0),
- start_time_(start_time),
- deadline_(deadline),
- non_block_(non_block) {
- cleanSkip_Locked();
- flush_to_state_ = log_buffer_->CreateFlushToState(start, log_mask);
- auto thread = std::thread{&LogReaderThread::ThreadFunction, this};
- thread.detach();
-}
-
-void LogReaderThread::ThreadFunction() {
- prctl(PR_SET_NAME, "logd.reader.per");
-
- auto lock = std::unique_lock{reader_list_->reader_threads_lock()};
-
- while (!release_) {
- if (deadline_.time_since_epoch().count() != 0) {
- if (thread_triggered_condition_.wait_until(lock, deadline_) ==
- std::cv_status::timeout) {
- deadline_ = {};
- }
- if (release_) {
- break;
- }
- }
-
- lock.unlock();
-
- if (tail_) {
- auto first_pass_state = log_buffer_->CreateFlushToState(flush_to_state_->start(),
- flush_to_state_->log_mask());
- log_buffer_->FlushTo(
- writer_.get(), *first_pass_state,
- [this](log_id_t log_id, pid_t pid, uint64_t sequence, log_time realtime) {
- return FilterFirstPass(log_id, pid, sequence, realtime);
- });
- }
- bool flush_success = log_buffer_->FlushTo(
- writer_.get(), *flush_to_state_,
- [this](log_id_t log_id, pid_t pid, uint64_t sequence, log_time realtime) {
- return FilterSecondPass(log_id, pid, sequence, realtime);
- });
-
- // We only ignore entries before the original start time for the first flushTo(), if we
- // get entries after this first flush before the original start time, then the client
- // wouldn't have seen them.
- // Note: this is still racy and may skip out of order events that came in since the last
- // time the client disconnected and then reconnected with the new start time. The long term
- // solution here is that clients must request events since a specific sequence number.
- start_time_.tv_sec = 0;
- start_time_.tv_nsec = 0;
-
- lock.lock();
-
- if (!flush_success) {
- break;
- }
-
- if (non_block_ || release_) {
- break;
- }
-
- cleanSkip_Locked();
-
- if (deadline_.time_since_epoch().count() == 0) {
- thread_triggered_condition_.wait(lock);
- }
- }
-
- writer_->Release();
-
- auto& log_reader_threads = reader_list_->reader_threads();
- auto it = std::find_if(log_reader_threads.begin(), log_reader_threads.end(),
- [this](const auto& other) { return other.get() == this; });
-
- if (it != log_reader_threads.end()) {
- log_reader_threads.erase(it);
- }
-}
-
-// A first pass to count the number of elements
-FilterResult LogReaderThread::FilterFirstPass(log_id_t, pid_t pid, uint64_t, log_time realtime) {
- auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
-
- if ((!pid_ || pid_ == pid) && (start_time_ == log_time::EPOCH || start_time_ <= realtime)) {
- ++count_;
- }
-
- return FilterResult::kSkip;
-}
-
-// A second pass to send the selected elements
-FilterResult LogReaderThread::FilterSecondPass(log_id_t log_id, pid_t pid, uint64_t,
- log_time realtime) {
- auto lock = std::lock_guard{reader_list_->reader_threads_lock()};
-
- if (skip_ahead_[log_id]) {
- skip_ahead_[log_id]--;
- return FilterResult::kSkip;
- }
-
- // Truncate to close race between first and second pass
- if (non_block_ && tail_ && index_ >= count_) {
- return FilterResult::kStop;
- }
-
- if (pid_ && pid_ != pid) {
- return FilterResult::kSkip;
- }
-
- if (start_time_ != log_time::EPOCH && realtime <= start_time_) {
- return FilterResult::kSkip;
- }
-
- if (release_) {
- return FilterResult::kStop;
- }
-
- if (!tail_) {
- goto ok;
- }
-
- ++index_;
-
- if (count_ > tail_ && index_ <= (count_ - tail_)) {
- return FilterResult::kSkip;
- }
-
- if (!non_block_) {
- tail_ = 0;
- }
-
-ok:
- if (!skip_ahead_[log_id]) {
- return FilterResult::kWrite;
- }
- return FilterResult::kSkip;
-}
-
-void LogReaderThread::cleanSkip_Locked(void) {
- memset(skip_ahead_, 0, sizeof(skip_ahead_));
-}
diff --git a/logd/LogReaderThread.h b/logd/LogReaderThread.h
deleted file mode 100644
index 20624f2..0000000
--- a/logd/LogReaderThread.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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.
- */
-
-#pragma once
-
-#include <pthread.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <time.h>
-
-#include <chrono>
-#include <condition_variable>
-#include <list>
-#include <memory>
-
-#include <log/log.h>
-
-#include "LogBuffer.h"
-#include "LogWriter.h"
-
-class LogReaderList;
-
-class LogReaderThread {
- public:
- LogReaderThread(LogBuffer* log_buffer, LogReaderList* reader_list,
- std::unique_ptr<LogWriter> writer, bool non_block, unsigned long tail,
- LogMask log_mask, pid_t pid, log_time start_time, uint64_t sequence,
- std::chrono::steady_clock::time_point deadline);
- void triggerReader_Locked() { thread_triggered_condition_.notify_all(); }
-
- void triggerSkip_Locked(log_id_t id, unsigned int skip) { skip_ahead_[id] = skip; }
- void cleanSkip_Locked();
-
- void release_Locked() {
- // gracefully shut down the socket.
- writer_->Shutdown();
- release_ = true;
- thread_triggered_condition_.notify_all();
- }
-
- bool IsWatching(log_id_t id) const { return flush_to_state_->log_mask() & (1 << id); }
- bool IsWatchingMultiple(LogMask log_mask) const {
- return flush_to_state_->log_mask() & log_mask;
- }
-
- std::string name() const { return writer_->name(); }
- uint64_t start() const { return flush_to_state_->start(); }
- std::chrono::steady_clock::time_point deadline() const { return deadline_; }
- FlushToState& flush_to_state() { return *flush_to_state_; }
-
- private:
- void ThreadFunction();
- // flushTo filter callbacks
- FilterResult FilterFirstPass(log_id_t log_id, pid_t pid, uint64_t sequence, log_time realtime);
- FilterResult FilterSecondPass(log_id_t log_id, pid_t pid, uint64_t sequence, log_time realtime);
-
- std::condition_variable thread_triggered_condition_;
- LogBuffer* log_buffer_;
- LogReaderList* reader_list_;
- std::unique_ptr<LogWriter> writer_;
-
- // Set to true to cause the thread to end and the LogReaderThread to delete itself.
- bool release_ = false;
-
- // If set to non-zero, only pids equal to this are read by the reader.
- const pid_t pid_;
- // When a reader is referencing (via start_) old elements in the log buffer, and the log
- // buffer's size grows past its memory limit, the log buffer may request the reader to skip
- // ahead a specified number of logs.
- unsigned int skip_ahead_[LOG_ID_MAX];
- // LogBuffer::FlushTo() needs to store state across subsequent calls.
- std::unique_ptr<FlushToState> flush_to_state_;
-
- // These next three variables are used for reading only the most recent lines aka `adb logcat
- // -t` / `adb logcat -T`.
- // tail_ is the number of most recent lines to print.
- unsigned long tail_;
- // count_ is the result of a first pass through the log buffer to determine how many total
- // messages there are.
- unsigned long count_;
- // index_ is used along with count_ to only start sending lines once index_ > (count_ - tail_)
- // and to disconnect the reader (if it is dumpAndClose, `adb logcat -t`), when index_ >= count_.
- unsigned long index_;
-
- // When a reader requests logs starting from a given timestamp, its stored here for the first
- // pass, such that logs before this time stamp that are accumulated in the buffer are ignored.
- log_time start_time_;
- // CLOCK_MONOTONIC based deadline used for log wrapping. If this deadline expires before logs
- // wrap, then wake up and send the logs to the reader anyway.
- std::chrono::steady_clock::time_point deadline_;
- // If this reader is 'dumpAndClose' and will disconnect once it has read its intended logs.
- const bool non_block_;
-};
diff --git a/logd/LogSize.cpp b/logd/LogSize.cpp
deleted file mode 100644
index fe829ba..0000000
--- a/logd/LogSize.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2020 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 <LogSize.h>
-
-#include <array>
-#include <optional>
-#include <string>
-
-#include <android-base/parseint.h>
-#include <android-base/properties.h>
-
-bool IsValidBufferSize(size_t value) {
- return kLogBufferMinSize <= value && value <= kLogBufferMaxSize;
-}
-
-static std::optional<size_t> GetBufferSizeProperty(const std::string& key) {
- std::string value = android::base::GetProperty(key, "");
- if (value.empty()) {
- return {};
- }
-
- uint32_t size;
- if (!android::base::ParseByteCount(value, &size)) {
- return {};
- }
-
- if (!IsValidBufferSize(size)) {
- return {};
- }
-
- return size;
-}
-
-size_t GetBufferSizeFromProperties(log_id_t log_id) {
- std::string buffer_name = android_log_id_to_name(log_id);
- std::array<std::string, 4> properties = {
- "persist.logd.size." + buffer_name,
- "ro.logd.size." + buffer_name,
- "persist.logd.size",
- "ro.logd.size",
- };
-
- for (const auto& property : properties) {
- if (auto size = GetBufferSizeProperty(property)) {
- return *size;
- }
- }
-
- if (android::base::GetBoolProperty("ro.config.low_ram", false)) {
- return kLogBufferMinSize;
- }
-
- return kDefaultLogBufferSize;
-}
diff --git a/logd/LogSize.h b/logd/LogSize.h
deleted file mode 100644
index d5716ff..0000000
--- a/logd/LogSize.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright 2020 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.
- */
-
-#pragma once
-
-#include <stddef.h>
-
-#include <log/log.h>
-
-static constexpr size_t kDefaultLogBufferSize = 256 * 1024;
-static constexpr size_t kLogBufferMinSize = 64 * 1024;
-static constexpr size_t kLogBufferMaxSize = 256 * 1024 * 1024;
-
-bool IsValidBufferSize(size_t value);
-
-// This returns the buffer size as set in system properties for use in LogBuffer::Init().
-// Note that `logcat -G` calls LogBuffer::SetSize(), which configures log buffer sizes without
-// setting these properties, so this function should never be used except for LogBuffer::Init().
-// LogBuffer::GetSize() should be used instead within logd. Other processes can use
-// android_logger_get_log_size() or `logcat -g` to query the actual allotted buffer size.
-size_t GetBufferSizeFromProperties(log_id_t log_id);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
deleted file mode 100644
index 87069b3..0000000
--- a/logd/LogStatistics.cpp
+++ /dev/null
@@ -1,1071 +0,0 @@
-/*
- * Copyright (C) 2014 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 "LogStatistics.h"
-
-#include <ctype.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <list>
-#include <vector>
-
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <private/android_logger.h>
-
-#include "LogBufferElement.h"
-
-static const uint64_t hourSec = 60 * 60;
-static const uint64_t monthSec = 31 * 24 * hourSec;
-
-std::atomic<size_t> LogStatistics::SizesTotal;
-
-static std::string TagNameKey(const LogStatisticsElement& element) {
- if (IsBinary(element.log_id)) {
- uint32_t tag = element.tag;
- if (tag) {
- const char* cp = android::tagToName(tag);
- if (cp) {
- return std::string(cp);
- }
- }
- return android::base::StringPrintf("[%" PRIu32 "]", tag);
- }
- const char* msg = element.msg;
- if (!msg) {
- return "chatty";
- }
- ++msg;
- uint16_t len = element.msg_len;
- len = (len <= 1) ? 0 : strnlen(msg, len - 1);
- if (!len) {
- return "<NULL>";
- }
- return std::string(msg, len);
-}
-
-LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size,
- std::optional<log_time> start_time)
- : enable(enable_statistics), track_total_size_(track_total_size) {
- log_time now(CLOCK_REALTIME);
- log_id_for_each(id) {
- mSizes[id] = 0;
- mElements[id] = 0;
- mDroppedElements[id] = 0;
- mSizesTotal[id] = 0;
- mElementsTotal[id] = 0;
- if (start_time) {
- mOldest[id] = *start_time;
- mNewest[id] = *start_time;
- } else {
- mOldest[id] = now;
- mNewest[id] = now;
- }
- mNewestDropped[id] = now;
- }
-}
-
-namespace android {
-
-size_t sizesTotal() {
- return LogStatistics::sizesTotal();
-}
-
-// caller must own and free character string
-char* pidToName(pid_t pid) {
- char* retval = nullptr;
- if (pid == 0) { // special case from auditd/klogd for kernel
- retval = strdup("logd");
- } else {
- char buffer[512];
- snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
- int fd = open(buffer, O_RDONLY | O_CLOEXEC);
- if (fd >= 0) {
- ssize_t ret = read(fd, buffer, sizeof(buffer));
- if (ret > 0) {
- buffer[sizeof(buffer) - 1] = '\0';
- // frameworks intermediate state
- if (fastcmp<strcmp>(buffer, "<pre-initialized>")) {
- retval = strdup(buffer);
- }
- }
- close(fd);
- }
- }
- return retval;
-}
-}
-
-void LogStatistics::AddTotal(log_id_t log_id, uint16_t size) {
- auto lock = std::lock_guard{lock_};
-
- mSizesTotal[log_id] += size;
- SizesTotal += size;
- ++mElementsTotal[log_id];
-}
-
-void LogStatistics::Add(LogStatisticsElement element) {
- auto lock = std::lock_guard{lock_};
-
- if (!track_total_size_) {
- element.total_len = element.msg_len;
- }
-
- log_id_t log_id = element.log_id;
- uint16_t size = element.total_len;
- mSizes[log_id] += size;
- ++mElements[log_id];
-
- // When caller adding a chatty entry, they will have already
- // called add() and subtract() for each entry as they are
- // evaluated and trimmed, thus recording size and number of
- // elements, but we must recognize the manufactured dropped
- // entry as not contributing to the lifetime totals.
- if (element.dropped_count) {
- ++mDroppedElements[log_id];
- } else {
- mSizesTotal[log_id] += size;
- SizesTotal += size;
- ++mElementsTotal[log_id];
- }
-
- log_time stamp(element.realtime);
- if (mNewest[log_id] < stamp) {
- // A major time update invalidates the statistics :-(
- log_time diff = stamp - mNewest[log_id];
- mNewest[log_id] = stamp;
-
- if (diff.tv_sec > hourSec) {
- // approximate Do-Your-Best fixup
- diff += mOldest[log_id];
- if ((diff > stamp) && ((diff - stamp).tv_sec < hourSec)) {
- diff = stamp;
- }
- if (diff <= stamp) {
- mOldest[log_id] = diff;
- if (mNewestDropped[log_id] < diff) {
- mNewestDropped[log_id] = diff;
- }
- }
- }
- }
-
- if (log_id == LOG_ID_KERNEL) {
- return;
- }
-
- uidTable[log_id].Add(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Add(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Add(element.pid, element);
- tidTable.Add(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Add(tag, element);
- } else {
- tagTable.Add(tag, element);
- }
- }
-
- if (!element.dropped_count) {
- tagNameTable.Add(TagNameKey(element), element);
- }
-}
-
-void LogStatistics::Subtract(LogStatisticsElement element) {
- auto lock = std::lock_guard{lock_};
-
- if (!track_total_size_) {
- element.total_len = element.msg_len;
- }
-
- log_id_t log_id = element.log_id;
- uint16_t size = element.total_len;
- mSizes[log_id] -= size;
- --mElements[log_id];
- if (element.dropped_count) {
- --mDroppedElements[log_id];
- }
-
- if (mOldest[log_id] < element.realtime) {
- mOldest[log_id] = element.realtime;
- }
-
- if (log_id == LOG_ID_KERNEL) {
- return;
- }
-
- uidTable[log_id].Subtract(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Subtract(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Subtract(element.pid, element);
- tidTable.Subtract(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Subtract(tag, element);
- } else {
- tagTable.Subtract(tag, element);
- }
- }
-
- if (!element.dropped_count) {
- tagNameTable.Subtract(TagNameKey(element), element);
- }
-}
-
-// Atomically set an entry to drop
-// entry->setDropped(1) must follow this call, caller should do this explicitly.
-void LogStatistics::Drop(LogStatisticsElement element) {
- CHECK_EQ(element.dropped_count, 0U);
-
- auto lock = std::lock_guard{lock_};
- log_id_t log_id = element.log_id;
- uint16_t size = element.msg_len;
- mSizes[log_id] -= size;
- ++mDroppedElements[log_id];
-
- if (mNewestDropped[log_id] < element.realtime) {
- mNewestDropped[log_id] = element.realtime;
- }
-
- uidTable[log_id].Drop(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Drop(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Drop(element.pid, element);
- tidTable.Drop(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Drop(tag, element);
- } else {
- tagTable.Drop(tag, element);
- }
- }
-
- tagNameTable.Subtract(TagNameKey(element), element);
-}
-
-void LogStatistics::Erase(LogStatisticsElement element) {
- CHECK_GT(element.dropped_count, 0U);
- CHECK_EQ(element.msg_len, 0U);
-
- auto lock = std::lock_guard{lock_};
-
- if (!track_total_size_) {
- element.total_len = 0;
- }
-
- log_id_t log_id = element.log_id;
- --mElements[log_id];
- --mDroppedElements[log_id];
- mSizes[log_id] -= element.total_len;
-
- uidTable[log_id].Erase(element.uid, element);
- if (element.uid == AID_SYSTEM) {
- pidSystemTable[log_id].Erase(element.pid, element);
- }
-
- if (!enable) {
- return;
- }
-
- pidTable.Erase(element.pid, element);
- tidTable.Erase(element.tid, element);
-
- uint32_t tag = element.tag;
- if (tag) {
- if (log_id == LOG_ID_SECURITY) {
- securityTagTable.Erase(tag, element);
- } else {
- tagTable.Erase(tag, element);
- }
- }
-}
-
-const char* LogStatistics::UidToName(uid_t uid) const {
- auto lock = std::lock_guard{lock_};
- return UidToNameLocked(uid);
-}
-
-// caller must own and free character string
-const char* LogStatistics::UidToNameLocked(uid_t uid) const {
- // Local hard coded favourites
- if (uid == AID_LOGD) {
- return strdup("auditd");
- }
-
- // Android system
- if (uid < AID_APP) {
- // in bionic, thread safe as long as we copy the results
- struct passwd* pwd = getpwuid(uid);
- if (pwd) {
- return strdup(pwd->pw_name);
- }
- }
-
- // Parse /data/system/packages.list
- uid_t userId = uid % AID_USER_OFFSET;
- const char* name = android::uidToName(userId);
- if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
- name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
- }
- if (name) {
- return name;
- }
-
- // Android application
- if (uid >= AID_APP) {
- struct passwd* pwd = getpwuid(uid);
- if (pwd) {
- return strdup(pwd->pw_name);
- }
- }
-
- // report uid -> pid(s) -> pidToName if unique
- for (pidTable_t::const_iterator it = pidTable.begin(); it != pidTable.end();
- ++it) {
- const PidEntry& entry = it->second;
-
- if (entry.uid() == uid) {
- const char* nameTmp = entry.name();
-
- if (nameTmp) {
- if (!name) {
- name = strdup(nameTmp);
- } else if (fastcmp<strcmp>(name, nameTmp)) {
- free(const_cast<char*>(name));
- name = nullptr;
- break;
- }
- }
- }
- }
-
- // No one
- return name;
-}
-
-template <typename TKey, typename TEntry>
-void LogStatistics::WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
- int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const {
- std::array<const TKey*, 2> max_keys;
- std::array<const TEntry*, 2> max_entries;
- table.MaxEntries(AID_ROOT, 0, max_keys, max_entries);
- if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
- return;
- }
- *worst_sizes = max_entries[0]->getSizes();
- // b/24782000: Allow time horizon to extend roughly tenfold, assume average entry length is
- // 100 characters.
- if (*worst_sizes > threshold && *worst_sizes > (10 * max_entries[0]->dropped_count())) {
- *worst = *max_keys[0];
- *second_worst_sizes = max_entries[1]->getSizes();
- if (*second_worst_sizes < threshold) {
- *second_worst_sizes = threshold;
- }
- }
-}
-
-void LogStatistics::WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const {
- auto lock = std::lock_guard{lock_};
- WorstTwoWithThreshold(uidTable[id], threshold, worst, worst_sizes, second_worst_sizes);
-}
-
-void LogStatistics::WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const {
- auto lock = std::lock_guard{lock_};
- WorstTwoWithThreshold(tagTable, threshold, worst, worst_sizes, second_worst_sizes);
-}
-
-void LogStatistics::WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
- size_t* second_worst_sizes) const {
- auto lock = std::lock_guard{lock_};
- std::array<const pid_t*, 2> max_keys;
- std::array<const PidEntry*, 2> max_entries;
- pidSystemTable[id].MaxEntries(AID_SYSTEM, 0, max_keys, max_entries);
- if (max_entries[0] == nullptr || max_entries[1] == nullptr) {
- return;
- }
-
- *worst = *max_keys[0];
- *second_worst_sizes = worst_uid_sizes - max_entries[0]->getSizes() + max_entries[1]->getSizes();
-}
-
-// Prune at most 10% of the log entries or maxPrune, whichever is less.
-bool LogStatistics::ShouldPrune(log_id id, unsigned long max_size,
- unsigned long* prune_rows) const {
- static constexpr size_t kMinPrune = 4;
- static constexpr size_t kMaxPrune = 256;
-
- auto lock = std::lock_guard{lock_};
- size_t sizes = mSizes[id];
- if (sizes <= max_size) {
- return false;
- }
- size_t size_over = sizes - ((max_size * 9) / 10);
- size_t elements = mElements[id] - mDroppedElements[id];
- size_t min_elements = elements / 100;
- if (min_elements < kMinPrune) {
- min_elements = kMinPrune;
- }
- *prune_rows = elements * size_over / sizes;
- if (*prune_rows < min_elements) {
- *prune_rows = min_elements;
- }
- if (*prune_rows > kMaxPrune) {
- *prune_rows = kMaxPrune;
- }
-
- return true;
-}
-
-std::string UidEntry::formatHeader(const std::string& name, log_id_t id) const {
- bool isprune = worstUidEnabledForLogid(id);
- return formatLine(android::base::StringPrintf(name.c_str(),
- android_log_id_to_name(id)),
- std::string("Size"),
- std::string(isprune ? "+/- Pruned" : "")) +
- formatLine(std::string("UID PACKAGE"), std::string("BYTES"),
- std::string(isprune ? "NUM" : ""));
-}
-
-// Helper to truncate name, if too long, and add name dressings
-void LogStatistics::FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
- size_t nameLen) const {
- const char* allocNameTmp = nullptr;
- if (!nameTmp) nameTmp = allocNameTmp = UidToNameLocked(uid);
- if (nameTmp) {
- size_t lenSpace = std::max(nameLen - name.length(), (size_t)1);
- size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
- lenSpace - 2;
- size_t lenNameTmp = strlen(nameTmp);
- while ((len < lenNameTmp) && (lenSpace > 1)) {
- ++len;
- --lenSpace;
- }
- name += android::base::StringPrintf("%*s", (int)lenSpace, "");
- if (len < lenNameTmp) {
- name += "...";
- nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
- }
- name += nameTmp;
- free(const_cast<char*>(allocNameTmp));
- }
-}
-
-std::string UidEntry::format(const LogStatistics& stat, log_id_t id, uid_t uid) const
- REQUIRES(stat.lock_) {
- std::string name = android::base::StringPrintf("%u", uid);
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- stat.FormatTmp(nullptr, uid, name, size, 6);
-
- std::string pruned = "";
- if (worstUidEnabledForLogid(id)) {
- size_t totalDropped = 0;
- for (LogStatistics::uidTable_t::const_iterator it =
- stat.uidTable[id].begin();
- it != stat.uidTable[id].end(); ++it) {
- totalDropped += it->second.dropped_count();
- }
- size_t sizes = stat.mSizes[id];
- size_t totalSize = stat.mSizesTotal[id];
- size_t totalElements = stat.mElementsTotal[id];
- float totalVirtualSize =
- (float)sizes + (float)totalDropped * totalSize / totalElements;
- size_t entrySize = getSizes();
- float virtualEntrySize = entrySize;
- int realPermille = virtualEntrySize * 1000.0 / sizes;
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- virtualEntrySize += (float)dropped * totalSize / totalElements;
- }
- int virtualPermille = virtualEntrySize * 1000.0 / totalVirtualSize;
- int permille =
- (realPermille - virtualPermille) * 1000L / (virtualPermille ?: 1);
- if ((permille < -1) || (1 < permille)) {
- std::string change;
- const char* units = "%";
- const char* prefix = (permille > 0) ? "+" : "";
-
- if (permille > 999) {
- permille = (permille + 1000) / 100; // Now tenths fold
- units = "X";
- prefix = "";
- }
- if ((-99 < permille) && (permille < 99)) {
- change = android::base::StringPrintf(
- "%s%d.%u%s", prefix, permille / 10,
- ((permille < 0) ? (-permille % 10) : (permille % 10)),
- units);
- } else {
- change = android::base::StringPrintf(
- "%s%d%s", prefix, (permille + 5) / 10, units);
- }
- ssize_t spaces = EntryBase::PRUNED_LEN - 2 - pruned.length() - change.length();
- if ((spaces <= 0) && pruned.length()) {
- spaces = 1;
- }
- if (spaces > 0) {
- change += android::base::StringPrintf("%*s", (int)spaces, "");
- }
- pruned = change + pruned;
- }
- }
-
- std::string output = formatLine(name, size, pruned);
-
- if (uid != AID_SYSTEM) {
- return output;
- }
-
- static const size_t maximum_sorted_entries = 32;
- std::array<const pid_t*, maximum_sorted_entries> sorted_pids;
- std::array<const PidEntry*, maximum_sorted_entries> sorted_entries;
- stat.pidSystemTable[id].MaxEntries(uid, 0, sorted_pids, sorted_entries);
-
- std::string byPid;
- size_t index;
- bool hasDropped = false;
- for (index = 0; index < maximum_sorted_entries; ++index) {
- const PidEntry* entry = sorted_entries[index];
- if (!entry) {
- break;
- }
- if (entry->getSizes() <= (getSizes() / 100)) {
- break;
- }
- if (entry->dropped_count()) {
- hasDropped = true;
- }
- byPid += entry->format(stat, id, *sorted_pids[index]);
- }
- if (index > 1) { // print this only if interesting
- std::string ditto("\" ");
- output += formatLine(std::string(" PID/UID COMMAND LINE"), ditto,
- hasDropped ? ditto : std::string(""));
- output += byPid;
- }
-
- return output;
-}
-
-std::string PidEntry::formatHeader(const std::string& name,
- log_id_t /* id */) const {
- return formatLine(name, std::string("Size"), std::string("Pruned")) +
- formatLine(std::string(" PID/UID COMMAND LINE"),
- std::string("BYTES"), std::string("NUM"));
-}
-
-std::string PidEntry::format(const LogStatistics& stat, log_id_t, pid_t pid) const
- REQUIRES(stat.lock_) {
- std::string name = android::base::StringPrintf("%5u/%u", pid, uid_);
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- stat.FormatTmp(name_, uid_, name, size, 12);
-
- std::string pruned = "";
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- }
-
- return formatLine(name, size, pruned);
-}
-
-std::string TidEntry::formatHeader(const std::string& name,
- log_id_t /* id */) const {
- return formatLine(name, std::string("Size"), std::string("Pruned")) +
- formatLine(std::string(" TID/UID COMM"), std::string("BYTES"),
- std::string("NUM"));
-}
-
-std::string TidEntry::format(const LogStatistics& stat, log_id_t, pid_t tid) const
- REQUIRES(stat.lock_) {
- std::string name = android::base::StringPrintf("%5u/%u", tid, uid_);
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- stat.FormatTmp(name_, uid_, name, size, 12);
-
- std::string pruned = "";
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- }
-
- return formatLine(name, size, pruned);
-}
-
-std::string TagEntry::formatHeader(const std::string& name, log_id_t id) const {
- bool isprune = worstUidEnabledForLogid(id);
- return formatLine(name, std::string("Size"),
- std::string(isprune ? "Prune" : "")) +
- formatLine(std::string(" TAG/UID TAGNAME"),
- std::string("BYTES"), std::string(isprune ? "NUM" : ""));
-}
-
-std::string TagEntry::format(const LogStatistics&, log_id_t, uint32_t) const {
- std::string name;
- if (uid_ == (uid_t)-1) {
- name = android::base::StringPrintf("%7u", key());
- } else {
- name = android::base::StringPrintf("%7u/%u", key(), uid_);
- }
- const char* nameTmp = this->name();
- if (nameTmp) {
- name += android::base::StringPrintf(
- "%*s%s", (int)std::max(14 - name.length(), (size_t)1), "", nameTmp);
- }
-
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- std::string pruned = "";
- size_t dropped = dropped_count();
- if (dropped) {
- pruned = android::base::StringPrintf("%zu", dropped);
- }
-
- return formatLine(name, size, pruned);
-}
-
-std::string TagNameEntry::formatHeader(const std::string& name,
- log_id_t /* id */) const {
- return formatLine(name, std::string("Size"), std::string("")) +
- formatLine(std::string(" TID/PID/UID LOG_TAG NAME"),
- std::string("BYTES"), std::string(""));
-}
-
-std::string TagNameEntry::format(const LogStatistics&, log_id_t,
- const std::string& key_name) const {
- std::string name;
- std::string pidstr;
- if (pid_ != (pid_t)-1) {
- pidstr = android::base::StringPrintf("%u", pid_);
- if (tid_ != (pid_t)-1 && tid_ != pid_) pidstr = "/" + pidstr;
- }
- int len = 9 - pidstr.length();
- if (len < 0) len = 0;
- if (tid_ == (pid_t)-1 || tid_ == pid_) {
- name = android::base::StringPrintf("%*s", len, "");
- } else {
- name = android::base::StringPrintf("%*u", len, tid_);
- }
- name += pidstr;
- if (uid_ != (uid_t)-1) {
- name += android::base::StringPrintf("/%u", uid_);
- }
-
- std::string size = android::base::StringPrintf("%zu", getSizes());
-
- const char* nameTmp = key_name.data();
- if (nameTmp) {
- size_t lenSpace = std::max(16 - name.length(), (size_t)1);
- size_t len = EntryBase::TOTAL_LEN - EntryBase::PRUNED_LEN - size.length() - name.length() -
- lenSpace - 2;
- size_t lenNameTmp = strlen(nameTmp);
- while ((len < lenNameTmp) && (lenSpace > 1)) {
- ++len;
- --lenSpace;
- }
- name += android::base::StringPrintf("%*s", (int)lenSpace, "");
- if (len < lenNameTmp) {
- name += "...";
- nameTmp += lenNameTmp - std::max(len - 3, (size_t)1);
- }
- name += nameTmp;
- }
-
- std::string pruned = "";
-
- return formatLine(name, size, pruned);
-}
-
-static std::string formatMsec(uint64_t val) {
- static const unsigned subsecDigits = 3;
- static const uint64_t sec = MS_PER_SEC;
-
- static const uint64_t minute = 60 * sec;
- static const uint64_t hour = 60 * minute;
- static const uint64_t day = 24 * hour;
-
- std::string output;
- if (val < sec) return output;
-
- if (val >= day) {
- output = android::base::StringPrintf("%" PRIu64 "d ", val / day);
- val = (val % day) + day;
- }
- if (val >= minute) {
- if (val >= hour) {
- output += android::base::StringPrintf("%" PRIu64 ":",
- (val / hour) % (day / hour));
- }
- output += android::base::StringPrintf(
- (val >= hour) ? "%02" PRIu64 ":" : "%" PRIu64 ":",
- (val / minute) % (hour / minute));
- }
- output +=
- android::base::StringPrintf((val >= minute) ? "%02" PRIu64 : "%" PRIu64,
- (val / sec) % (minute / sec));
- val %= sec;
- unsigned digits = subsecDigits;
- while (digits && ((val % 10) == 0)) {
- val /= 10;
- --digits;
- }
- if (digits) {
- output += android::base::StringPrintf(".%0*" PRIu64, digits, val);
- }
- return output;
-}
-
-template <typename TKey, typename TEntry>
-std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid,
- pid_t pid, const std::string& name, log_id_t id) const
- REQUIRES(lock_) {
- static const size_t maximum_sorted_entries = 32;
- std::string output;
- std::array<const TKey*, maximum_sorted_entries> sorted_keys;
- std::array<const TEntry*, maximum_sorted_entries> sorted_entries;
- table.MaxEntries(uid, pid, sorted_keys, sorted_entries);
- bool header_printed = false;
- for (size_t index = 0; index < maximum_sorted_entries; ++index) {
- const TEntry* entry = sorted_entries[index];
- if (!entry) {
- break;
- }
- if (entry->getSizes() <= (sorted_entries[0]->getSizes() / 100)) {
- break;
- }
- if (!header_printed) {
- output += "\n\n";
- output += entry->formatHeader(name, id);
- header_printed = true;
- }
- output += entry->format(*this, id, *sorted_keys[index]);
- }
- return output;
-}
-
-std::string LogStatistics::ReportInteresting() const {
- auto lock = std::lock_guard{lock_};
-
- std::vector<std::string> items;
-
- log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); }
-
- log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); }
-
- log_id_for_each(i) {
- items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i]));
- }
-
- log_id_for_each(i) {
- uint64_t oldest = mOldest[i].msec() / 1000;
- uint64_t newest = mNewest[i].msec() / 1000;
-
- int span = newest - oldest;
-
- items.emplace_back(std::to_string(span));
- }
-
- return android::base::Join(items, ",");
-}
-
-std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const {
- auto lock = std::lock_guard{lock_};
-
- static const uint16_t spaces_total = 19;
-
- // Report on total logging, current and for all time
-
- std::string output = "size/num";
- size_t oldLength;
- int16_t spaces = 1;
-
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%s", spaces, "",
- android_log_id_to_name(id));
- spaces += spaces_total + oldLength - output.length();
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*sTotal", spaces, "");
-
- static const char TotalStr[] = "\nTotal";
- spaces = 10 - strlen(TotalStr);
- output += TotalStr;
-
- size_t totalSize = 0;
- size_t totalEls = 0;
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- size_t szs = mSizesTotal[id];
- totalSize += szs;
- size_t els = mElementsTotal[id];
- totalEls += els;
- output +=
- android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
- spaces += spaces_total + oldLength - output.length();
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
- totalEls);
-
- static const char NowStr[] = "\nNow";
- spaces = 10 - strlen(NowStr);
- output += NowStr;
-
- totalSize = 0;
- totalEls = 0;
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- size_t els = mElements[id];
- if (els) {
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- size_t szs = mSizes[id];
- totalSize += szs;
- totalEls += els;
- output +=
- android::base::StringPrintf("%*s%zu/%zu", spaces, "", szs, els);
- spaces -= output.length() - oldLength;
- }
- spaces += spaces_total;
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu/%zu", spaces, "", totalSize,
- totalEls);
-
- static const char SpanStr[] = "\nLogspan";
- spaces = 10 - strlen(SpanStr);
- output += SpanStr;
-
- // Total reports the greater of the individual maximum time span, or the
- // validated minimum start and maximum end time span if it makes sense.
- uint64_t minTime = UINT64_MAX;
- uint64_t maxTime = 0;
- uint64_t maxSpan = 0;
- totalSize = 0;
-
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- // validity checking
- uint64_t oldest = mOldest[id].msec();
- uint64_t newest = mNewest[id].msec();
- if (newest <= oldest) {
- spaces += spaces_total;
- continue;
- }
-
- uint64_t span = newest - oldest;
- if (span > (monthSec * MS_PER_SEC)) {
- spaces += spaces_total;
- continue;
- }
-
- // total span
- if (minTime > oldest) minTime = oldest;
- if (maxTime < newest) maxTime = newest;
- if (span > maxSpan) maxSpan = span;
- totalSize += span;
-
- uint64_t dropped = mNewestDropped[id].msec();
- if (dropped < oldest) dropped = oldest;
- if (dropped > newest) dropped = newest;
-
- oldLength = output.length();
- output += android::base::StringPrintf("%*s%s", spaces, "",
- formatMsec(span).c_str());
- unsigned permille = ((newest - dropped) * 1000 + (span / 2)) / span;
- if ((permille > 1) && (permille < 999)) {
- output += android::base::StringPrintf("(%u", permille / 10);
- permille %= 10;
- if (permille) {
- output += android::base::StringPrintf(".%u", permille);
- }
- output += android::base::StringPrintf("%%)");
- }
- spaces -= output.length() - oldLength;
- spaces += spaces_total;
- }
- if ((maxTime > minTime) && ((maxTime -= minTime) < totalSize) &&
- (maxTime > maxSpan)) {
- maxSpan = maxTime;
- }
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%s", spaces, "",
- formatMsec(maxSpan).c_str());
-
- static const char OverheadStr[] = "\nOverhead";
- spaces = 10 - strlen(OverheadStr);
- output += OverheadStr;
-
- totalSize = 0;
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- size_t els = mElements[id];
- if (els) {
- oldLength = output.length();
- if (spaces < 0) spaces = 0;
- size_t szs = 0;
- if (overhead_[id]) {
- szs = *overhead_[id];
- } else if (track_total_size_) {
- szs = mSizes[id];
- } else {
- // Legacy fallback for Chatty without track_total_size_
- // Estimate the size of this element in the parent std::list<> by adding two void*'s
- // corresponding to the next/prev pointers and aligning to 64 bit.
- static const size_t overhead =
- (sizeof(LogBufferElement) + 2 * sizeof(void*) + sizeof(uint64_t) - 1) &
- -sizeof(uint64_t);
- szs = mSizes[id] + els * overhead;
- }
- totalSize += szs;
- output += android::base::StringPrintf("%*s%zu", spaces, "", szs);
- spaces -= output.length() - oldLength;
- }
- spaces += spaces_total;
- }
- totalSize += sizeOf();
- if (spaces < 0) spaces = 0;
- output += android::base::StringPrintf("%*s%zu", spaces, "", totalSize);
-
- // Report on Chattiest
-
- std::string name;
-
- // Chattiest by application (UID)
- log_id_for_each(id) {
- if (!(logMask & (1 << id))) continue;
-
- name = (uid == AID_ROOT) ? "Chattiest UIDs in %s log buffer:"
- : "Logging for your UID in %s log buffer:";
- output += FormatTable(uidTable[id], uid, pid, name, id);
- }
-
- if (enable) {
- name = ((uid == AID_ROOT) && !pid) ? "Chattiest PIDs:"
- : "Logging for this PID:";
- output += FormatTable(pidTable, uid, pid, name);
- name = "Chattiest TIDs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(tidTable, uid, pid, name);
- }
-
- if (enable && (logMask & (1 << LOG_ID_EVENTS))) {
- name = "Chattiest events log buffer TAGs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(tagTable, uid, pid, name, LOG_ID_EVENTS);
- }
-
- if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
- name = "Chattiest security log buffer TAGs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(securityTagTable, uid, pid, name, LOG_ID_SECURITY);
- }
-
- if (enable) {
- name = "Chattiest TAGs";
- if (pid) name += android::base::StringPrintf(" for PID %d", pid);
- name += ":";
- output += FormatTable(tagNameTable, uid, pid, name);
- }
-
- return output;
-}
-
-namespace android {
-
-uid_t pidToUid(pid_t pid) {
- char buffer[512];
- snprintf(buffer, sizeof(buffer), "/proc/%u/status", pid);
- FILE* fp = fopen(buffer, "re");
- if (fp) {
- while (fgets(buffer, sizeof(buffer), fp)) {
- int uid = AID_LOGD;
- char space = 0;
- if ((sscanf(buffer, "Uid: %d%c", &uid, &space) == 2) &&
- isspace(space)) {
- fclose(fp);
- return uid;
- }
- }
- fclose(fp);
- }
- return AID_LOGD; // associate this with the logger
-}
-}
-
-uid_t LogStatistics::PidToUid(pid_t pid) {
- auto lock = std::lock_guard{lock_};
- return pidTable.Add(pid)->second.uid();
-}
-
-// caller must free character string
-const char* LogStatistics::PidToName(pid_t pid) const {
- auto lock = std::lock_guard{lock_};
- // An inconvenient truth ... getName() can alter the object
- pidTable_t& writablePidTable = const_cast<pidTable_t&>(pidTable);
- const char* name = writablePidTable.Add(pid)->second.name();
- if (!name) {
- return nullptr;
- }
- return strdup(name);
-}
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
deleted file mode 100644
index faf9283..0000000
--- a/logd/LogStatistics.h
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#pragma once
-
-#include <ctype.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <algorithm> // std::max
-#include <array>
-#include <memory>
-#include <mutex>
-#include <string>
-#include <string_view>
-#include <unordered_map>
-
-#include <android-base/stringprintf.h>
-#include <android-base/thread_annotations.h>
-#include <android/log.h>
-#include <log/log_time.h>
-#include <private/android_filesystem_config.h>
-#include <utils/FastStrcmp.h>
-
-#include "LogUtils.h"
-
-#define log_id_for_each(i) \
- for (log_id_t i = LOG_ID_MIN; (i) < LOG_ID_MAX; (i) = (log_id_t)((i) + 1))
-
-class LogStatistics;
-class UidEntry;
-class PidEntry;
-
-struct LogStatisticsElement {
- uid_t uid;
- pid_t pid;
- pid_t tid;
- uint32_t tag;
- log_time realtime;
- const char* msg;
- uint16_t msg_len;
- uint16_t dropped_count;
- log_id_t log_id;
- uint16_t total_len;
-};
-
-template <typename TKey, typename TEntry>
-class LogHashtable {
- std::unordered_map<TKey, TEntry> map;
-
- size_t bucket_size() const {
- size_t count = 0;
- for (size_t idx = 0; idx < map.bucket_count(); ++idx) {
- size_t bucket_size = map.bucket_size(idx);
- if (bucket_size == 0) bucket_size = 1;
- count += bucket_size;
- }
- float load_factor = map.max_load_factor();
- if (load_factor < 1.0) return count;
- return count * load_factor;
- }
-
- static const size_t unordered_map_per_entry_overhead = sizeof(void*);
- static const size_t unordered_map_bucket_overhead = sizeof(void*);
-
- public:
- size_t size() const {
- return map.size();
- }
-
- // Estimate unordered_map memory usage.
- size_t sizeOf() const {
- return sizeof(*this) +
- (size() * (sizeof(TEntry) + unordered_map_per_entry_overhead)) +
- (bucket_size() * sizeof(size_t) + unordered_map_bucket_overhead);
- }
-
- typedef typename std::unordered_map<TKey, TEntry>::iterator iterator;
- typedef
- typename std::unordered_map<TKey, TEntry>::const_iterator const_iterator;
-
- // Returns a sorted array of up to len highest entries sorted by size. If fewer than len
- // entries are found, their positions are set to nullptr.
- template <size_t len>
- void MaxEntries(uid_t uid, pid_t pid, std::array<const TKey*, len>& out_keys,
- std::array<const TEntry*, len>& out_entries) const {
- out_keys.fill(nullptr);
- out_entries.fill(nullptr);
- for (const auto& [key, entry] : map) {
- uid_t entry_uid = 0;
- if constexpr (std::is_same_v<TEntry, UidEntry>) {
- entry_uid = key;
- } else {
- entry_uid = entry.uid();
- }
- if (uid != AID_ROOT && uid != entry_uid) {
- continue;
- }
- pid_t entry_pid = 0;
- if constexpr (std::is_same_v<TEntry, PidEntry>) {
- entry_pid = key;
- } else {
- entry_pid = entry.pid();
- }
- if (pid && entry_pid && pid != entry_pid) {
- continue;
- }
-
- size_t sizes = entry.getSizes();
- ssize_t index = len - 1;
- while ((!out_entries[index] || sizes > out_entries[index]->getSizes()) && --index >= 0)
- ;
- if (++index < (ssize_t)len) {
- size_t num = len - index - 1;
- if (num) {
- memmove(&out_keys[index + 1], &out_keys[index], num * sizeof(const TKey*));
- memmove(&out_entries[index + 1], &out_entries[index],
- num * sizeof(const TEntry*));
- }
- out_keys[index] = &key;
- out_entries[index] = &entry;
- }
- }
- }
-
- iterator Add(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it == map.end()) {
- it = map.insert(std::make_pair(key, TEntry(element))).first;
- } else {
- it->second.Add(element);
- }
- return it;
- }
-
- iterator Add(const TKey& key) {
- iterator it = map.find(key);
- if (it == map.end()) {
- it = map.insert(std::make_pair(key, TEntry(key))).first;
- } else {
- it->second.Add(key);
- }
- return it;
- }
-
- void Subtract(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it != map.end() && it->second.Subtract(element)) {
- map.erase(it);
- }
- }
-
- void Drop(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it != map.end()) {
- it->second.Drop(element);
- }
- }
-
- void Erase(const TKey& key, const LogStatisticsElement& element) {
- iterator it = map.find(key);
- if (it != map.end()) {
- it->second.Erase(element);
- }
- }
-
- iterator begin() { return map.begin(); }
- const_iterator begin() const { return map.begin(); }
- iterator end() { return map.end(); }
- const_iterator end() const { return map.end(); }
-};
-
-class EntryBase {
- public:
- EntryBase() : size_(0) {}
- explicit EntryBase(const LogStatisticsElement& element) : size_(element.total_len) {}
-
- size_t getSizes() const { return size_; }
-
- void Add(const LogStatisticsElement& element) { size_ += element.total_len; }
- bool Subtract(const LogStatisticsElement& element) {
- size_ -= element.total_len;
- return size_ == 0;
- }
- void Drop(const LogStatisticsElement& element) { size_ -= element.msg_len; }
- void Erase(const LogStatisticsElement& element) { size_ -= element.total_len; }
-
- static constexpr size_t PRUNED_LEN = 14;
- static constexpr size_t TOTAL_LEN = 80;
-
- static std::string formatLine(const std::string& name,
- const std::string& size,
- const std::string& pruned) {
- ssize_t drop_len = std::max(pruned.length() + 1, PRUNED_LEN);
- ssize_t size_len = std::max(size.length() + 1, TOTAL_LEN - name.length() - drop_len - 1);
-
- std::string ret = android::base::StringPrintf(
- "%s%*s%*s", name.c_str(), (int)size_len, size.c_str(),
- (int)drop_len, pruned.c_str());
- // remove any trailing spaces
- size_t pos = ret.size();
- size_t len = 0;
- while (pos && isspace(ret[--pos])) ++len;
- if (len) ret.erase(pos + 1, len);
- return ret + "\n";
- }
-
- private:
- size_t size_;
-};
-
-class EntryBaseDropped : public EntryBase {
- public:
- EntryBaseDropped() : dropped_(0) {}
- explicit EntryBaseDropped(const LogStatisticsElement& element)
- : EntryBase(element), dropped_(element.dropped_count) {}
-
- size_t dropped_count() const { return dropped_; }
-
- void Add(const LogStatisticsElement& element) {
- dropped_ += element.dropped_count;
- EntryBase::Add(element);
- }
- bool Subtract(const LogStatisticsElement& element) {
- dropped_ -= element.dropped_count;
- return EntryBase::Subtract(element) && dropped_ == 0;
- }
- void Drop(const LogStatisticsElement& element) {
- dropped_ += 1;
- EntryBase::Drop(element);
- }
-
- private:
- size_t dropped_;
-};
-
-class UidEntry : public EntryBaseDropped {
- public:
- explicit UidEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element), pid_(element.pid) {}
-
- pid_t pid() const { return pid_; }
-
- void Add(const LogStatisticsElement& element) {
- if (pid_ != element.pid) {
- pid_ = -1;
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, uid_t uid) const;
-
- private:
- pid_t pid_;
-};
-
-namespace android {
-uid_t pidToUid(pid_t pid);
-}
-
-class PidEntry : public EntryBaseDropped {
- public:
- explicit PidEntry(pid_t pid)
- : EntryBaseDropped(),
- uid_(android::pidToUid(pid)),
- name_(android::pidToName(pid)) {}
- explicit PidEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element), uid_(element.uid), name_(android::pidToName(element.pid)) {}
- PidEntry(const PidEntry& element)
- : EntryBaseDropped(element),
- uid_(element.uid_),
- name_(element.name_ ? strdup(element.name_) : nullptr) {}
- ~PidEntry() { free(name_); }
-
- uid_t uid() const { return uid_; }
- const char* name() const { return name_; }
-
- void Add(pid_t new_pid) {
- if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
- free(name_);
- name_ = nullptr;
- }
- if (!name_) {
- name_ = android::pidToName(new_pid);
- }
- }
-
- void Add(const LogStatisticsElement& element) {
- uid_t incoming_uid = element.uid;
- if (uid() != incoming_uid) {
- uid_ = incoming_uid;
- free(name_);
- name_ = android::pidToName(element.pid);
- } else {
- Add(element.pid);
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
-
- private:
- uid_t uid_;
- char* name_;
-};
-
-class TidEntry : public EntryBaseDropped {
- public:
- TidEntry(pid_t tid, pid_t pid)
- : EntryBaseDropped(),
- pid_(pid),
- uid_(android::pidToUid(tid)),
- name_(android::tidToName(tid)) {}
- explicit TidEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element),
- pid_(element.pid),
- uid_(element.uid),
- name_(android::tidToName(element.tid)) {}
- TidEntry(const TidEntry& element)
- : EntryBaseDropped(element),
- pid_(element.pid_),
- uid_(element.uid_),
- name_(element.name_ ? strdup(element.name_) : nullptr) {}
- ~TidEntry() { free(name_); }
-
- pid_t pid() const { return pid_; }
- uid_t uid() const { return uid_; }
- const char* name() const { return name_; }
-
- void Add(pid_t incomingTid) {
- if (name_ && !fastcmp<strncmp>(name_, "zygote", 6)) {
- free(name_);
- name_ = nullptr;
- }
- if (!name_) {
- name_ = android::tidToName(incomingTid);
- }
- }
-
- void Add(const LogStatisticsElement& element) {
- uid_t incoming_uid = element.uid;
- pid_t incoming_pid = element.pid;
- if (uid() != incoming_uid || pid() != incoming_pid) {
- uid_ = incoming_uid;
- pid_ = incoming_pid;
- free(name_);
- name_ = android::tidToName(element.tid);
- } else {
- Add(element.tid);
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, pid_t pid) const;
-
- private:
- pid_t pid_;
- uid_t uid_;
- char* name_;
-};
-
-class TagEntry : public EntryBaseDropped {
- public:
- explicit TagEntry(const LogStatisticsElement& element)
- : EntryBaseDropped(element), tag_(element.tag), pid_(element.pid), uid_(element.uid) {}
-
- uint32_t key() const { return tag_; }
- pid_t pid() const { return pid_; }
- uid_t uid() const { return uid_; }
- const char* name() const { return android::tagToName(tag_); }
-
- void Add(const LogStatisticsElement& element) {
- if (uid_ != element.uid) {
- uid_ = -1;
- }
- if (pid_ != element.pid) {
- pid_ = -1;
- }
- EntryBaseDropped::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, uint32_t) const;
-
- private:
- const uint32_t tag_;
- pid_t pid_;
- uid_t uid_;
-};
-
-class TagNameEntry : public EntryBase {
- public:
- explicit TagNameEntry(const LogStatisticsElement& element)
- : EntryBase(element), tid_(element.tid), pid_(element.pid), uid_(element.uid) {}
-
- pid_t tid() const { return tid_; }
- pid_t pid() const { return pid_; }
- uid_t uid() const { return uid_; }
-
- void Add(const LogStatisticsElement& element) {
- if (uid_ != element.uid) {
- uid_ = -1;
- }
- if (pid_ != element.pid) {
- pid_ = -1;
- }
- if (tid_ != element.tid) {
- tid_ = -1;
- }
- EntryBase::Add(element);
- }
-
- std::string formatHeader(const std::string& name, log_id_t id) const;
- std::string format(const LogStatistics& stat, log_id_t id, const std::string& key_name) const;
-
- private:
- pid_t tid_;
- pid_t pid_;
- uid_t uid_;
-};
-
-class LogStatistics {
- friend UidEntry;
- friend PidEntry;
- friend TidEntry;
-
- size_t mSizes[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mElements[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mDroppedElements[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mSizesTotal[LOG_ID_MAX] GUARDED_BY(lock_);
- size_t mElementsTotal[LOG_ID_MAX] GUARDED_BY(lock_);
- log_time mOldest[LOG_ID_MAX] GUARDED_BY(lock_);
- log_time mNewest[LOG_ID_MAX] GUARDED_BY(lock_);
- log_time mNewestDropped[LOG_ID_MAX] GUARDED_BY(lock_);
- static std::atomic<size_t> SizesTotal;
- bool enable;
-
- // uid to size list
- typedef LogHashtable<uid_t, UidEntry> uidTable_t;
- uidTable_t uidTable[LOG_ID_MAX] GUARDED_BY(lock_);
-
- // pid of system to size list
- typedef LogHashtable<pid_t, PidEntry> pidSystemTable_t;
- pidSystemTable_t pidSystemTable[LOG_ID_MAX] GUARDED_BY(lock_);
-
- // pid to uid list
- typedef LogHashtable<pid_t, PidEntry> pidTable_t;
- pidTable_t pidTable GUARDED_BY(lock_);
-
- // tid to uid list
- typedef LogHashtable<pid_t, TidEntry> tidTable_t;
- tidTable_t tidTable GUARDED_BY(lock_);
-
- // tag list
- typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
- tagTable_t tagTable GUARDED_BY(lock_);
-
- // security tag list
- tagTable_t securityTagTable GUARDED_BY(lock_);
-
- // global tag list
- typedef LogHashtable<std::string, TagNameEntry> tagNameTable_t;
- tagNameTable_t tagNameTable;
-
- size_t sizeOf() const REQUIRES(lock_) {
- size_t size = sizeof(*this) + pidTable.sizeOf() + tidTable.sizeOf() +
- tagTable.sizeOf() + securityTagTable.sizeOf() +
- tagNameTable.sizeOf() +
- (pidTable.size() * sizeof(pidTable_t::iterator)) +
- (tagTable.size() * sizeof(tagTable_t::iterator));
- for (const auto& it : pidTable) {
- const char* name = it.second.name();
- if (name) size += strlen(name) + 1;
- }
- for (const auto& it : tidTable) {
- const char* name = it.second.name();
- if (name) size += strlen(name) + 1;
- }
- for (const auto& it : tagNameTable) {
- size += sizeof(std::string);
- size_t len = it.first.size();
- // Account for short string optimization: if the string's length is <= 22 bytes for 64
- // bit or <= 10 bytes for 32 bit, then there is no additional allocation.
- if ((sizeof(std::string) == 24 && len > 22) ||
- (sizeof(std::string) != 24 && len > 10)) {
- size += len;
- }
- }
- log_id_for_each(id) {
- size += uidTable[id].sizeOf();
- size += uidTable[id].size() * sizeof(uidTable_t::iterator);
- size += pidSystemTable[id].sizeOf();
- size += pidSystemTable[id].size() * sizeof(pidSystemTable_t::iterator);
- }
- return size;
- }
-
- public:
- LogStatistics(bool enable_statistics, bool track_total_size,
- std::optional<log_time> start_time = {});
-
- void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_);
-
- // Add is for adding an element to the log buffer. It may be a chatty element in the case of
- // log deduplication. Add the total size of the element to statistics.
- void Add(LogStatisticsElement entry) EXCLUDES(lock_);
- // Subtract is for removing an element from the log buffer. It may be a chatty element.
- // Subtract the total size of the element from statistics.
- void Subtract(LogStatisticsElement entry) EXCLUDES(lock_);
- // Drop is for converting a normal element into a chatty element. entry->setDropped(1) must
- // follow this call. Subtract only msg_len from statistics, since a chatty element will remain.
- void Drop(LogStatisticsElement entry) EXCLUDES(lock_);
- // Erase is for coalescing two chatty elements into one. Erase() is called on the element that
- // is removed from the log buffer. Subtract the total size of the element, which is by
- // definition only the size of the LogBufferElement + list overhead for chatty elements.
- void Erase(LogStatisticsElement element) EXCLUDES(lock_);
-
- void WorstTwoUids(log_id id, size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const EXCLUDES(lock_);
- void WorstTwoTags(size_t threshold, int* worst, size_t* worst_sizes,
- size_t* second_worst_sizes) const EXCLUDES(lock_);
- void WorstTwoSystemPids(log_id id, size_t worst_uid_sizes, int* worst,
- size_t* second_worst_sizes) const EXCLUDES(lock_);
-
- bool ShouldPrune(log_id id, unsigned long max_size, unsigned long* prune_rows) const
- EXCLUDES(lock_);
-
- // Return the consumed size of the given buffer.
- size_t Sizes(log_id_t id) const EXCLUDES(lock_) {
- auto lock = std::lock_guard{lock_};
- if (overhead_[id]) {
- return *overhead_[id];
- }
- return mSizes[id];
- }
-
- // Return the uncompressed size of the contents of the given buffer.
- size_t SizeReadable(log_id_t id) const EXCLUDES(lock_) {
- auto lock = std::lock_guard{lock_};
- return mSizes[id];
- }
-
- // TODO: Get rid of this entirely.
- static size_t sizesTotal() {
- return SizesTotal;
- }
-
- std::string ReportInteresting() const EXCLUDES(lock_);
- std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_);
-
- const char* PidToName(pid_t pid) const EXCLUDES(lock_);
- uid_t PidToUid(pid_t pid) EXCLUDES(lock_);
- const char* UidToName(uid_t uid) const EXCLUDES(lock_);
-
- void set_overhead(log_id_t id, size_t size) {
- auto lock = std::lock_guard{lock_};
- overhead_[id] = size;
- }
-
- private:
- template <typename TKey, typename TEntry>
- void WorstTwoWithThreshold(const LogHashtable<TKey, TEntry>& table, size_t threshold,
- int* worst, size_t* worst_sizes, size_t* second_worst_sizes) const;
- template <typename TKey, typename TEntry>
- std::string FormatTable(const LogHashtable<TKey, TEntry>& table, uid_t uid, pid_t pid,
- const std::string& name = std::string(""),
- log_id_t id = LOG_ID_MAX) const REQUIRES(lock_);
- void FormatTmp(const char* nameTmp, uid_t uid, std::string& name, std::string& size,
- size_t nameLen) const REQUIRES(lock_);
- const char* UidToNameLocked(uid_t uid) const REQUIRES(lock_);
-
- mutable std::mutex lock_;
- bool track_total_size_;
-
- std::optional<size_t> overhead_[LOG_ID_MAX] GUARDED_BY(lock_);
-};
diff --git a/logd/LogTags.cpp b/logd/LogTags.cpp
deleted file mode 100644
index 6ab3b48..0000000
--- a/logd/LogTags.cpp
+++ /dev/null
@@ -1,889 +0,0 @@
-/*
- * Copyright (C) 2017 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 <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/scopeguard.h>
-#include <android-base/stringprintf.h>
-#include <android-base/threads.h>
-#include <log/log_event_list.h>
-#include <log/log_properties.h>
-#include <log/log_read.h>
-#include <private/android_filesystem_config.h>
-
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogUtils.h"
-
-using android::base::make_scope_guard;
-
-static LogTags* logtags;
-
-const char LogTags::system_event_log_tags[] = "/system/etc/event-log-tags";
-const char LogTags::dynamic_event_log_tags[] = "/dev/event-log-tags";
-// Only for debug
-const char LogTags::debug_event_log_tags[] = "/data/misc/logd/event-log-tags";
-
-// Sniff for first uid=%d in utf8z comment string
-static uid_t sniffUid(const char* comment, const char* endp) {
- if (!comment) return AID_ROOT;
-
- if (*comment == '#') ++comment;
- while ((comment < endp) && (*comment != '\n') && isspace(*comment))
- ++comment;
- static const char uid_str[] = "uid=";
- if (((comment + strlen(uid_str)) >= endp) ||
- fastcmp<strncmp>(comment, uid_str, strlen(uid_str)) ||
- !isdigit(comment[strlen(uid_str)]))
- return AID_ROOT;
- char* cp;
- unsigned long Uid = strtoul(comment + 4, &cp, 10);
- if ((cp > endp) || (Uid >= INT_MAX)) return AID_ROOT;
-
- return Uid;
-}
-
-// Checks for file corruption, and report false if there was no need
-// to rebuild the referenced file. Failure to rebuild is only logged,
-// does not cause a return value of false.
-bool LogTags::RebuildFileEventLogTags(const char* filename, bool warn) {
- int fd;
-
- {
- android::RWLock::AutoRLock readLock(rwlock);
-
- if (tag2total.begin() == tag2total.end()) {
- return false;
- }
-
- file2watermark_const_iterator iwater = file2watermark.find(filename);
- if (iwater == file2watermark.end()) {
- return false;
- }
-
- struct stat sb;
- if (!stat(filename, &sb) && ((size_t)sb.st_size >= iwater->second)) {
- return false;
- }
-
- // dump what we already know back into the file?
- fd = TEMP_FAILURE_RETRY(open(
- filename, O_WRONLY | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
- if (fd >= 0) {
- time_t now = time(nullptr);
- struct tm tm;
- localtime_r(&now, &tm);
- char timebuf[20];
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%d %H:%M:%S", &tm);
- android::base::WriteStringToFd(
- android::base::StringPrintf(
- "# Rebuilt %.20s, content owned by logd\n", timebuf),
- fd);
- for (const auto& it : tag2total) {
- android::base::WriteStringToFd(
- formatEntry_locked(it.first, AID_ROOT), fd);
- }
- close(fd);
- }
- }
-
- if (warn) {
- if (fd < 0) {
- LOG(ERROR) << filename << " failed to rebuild";
- } else {
- LOG(ERROR) << filename << " missing, damaged or truncated; rebuilt";
- }
- }
-
- if (fd >= 0) {
- android::RWLock::AutoWLock writeLock(rwlock);
-
- struct stat sb;
- if (!stat(filename, &sb)) file2watermark[filename] = sb.st_size;
- }
-
- return true;
-}
-
-void LogTags::AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
- const std::string& Format, const char* source,
- bool warn) {
- std::string Key = Name;
- if (Format.length()) Key += "+" + Format;
-
- bool update = !source || !!strcmp(source, system_event_log_tags);
- bool newOne;
-
- {
- android::RWLock::AutoWLock writeLock(rwlock);
-
- tag2total_const_iterator itot = tag2total.find(tag);
-
- // unlikely except for dupes, or updates to uid list (more later)
- if (itot != tag2total.end()) update = false;
-
- newOne = tag2name.find(tag) == tag2name.end();
- key2tag[Key] = tag;
-
- if (Format.length()) {
- if (key2tag.find(Name) == key2tag.end()) {
- key2tag[Name] = tag;
- }
- tag2format[tag] = Format;
- }
- tag2name[tag] = Name;
-
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if (ut != tag2uid.end()) {
- if (uid == AID_ROOT) {
- tag2uid.erase(ut);
- update = true;
- } else if (ut->second.find(uid) == ut->second.end()) {
- const_cast<uid_list&>(ut->second).emplace(uid);
- update = true;
- }
- } else if (newOne && (uid != AID_ROOT)) {
- tag2uid[tag].emplace(uid);
- update = true;
- }
-
- // updatePersist -> trigger output on modified
- // content, reset tag2total if available
- if (update && (itot != tag2total.end())) tag2total[tag] = 0;
- }
-
- if (update) {
- WritePersistEventLogTags(tag, uid, source);
- } else if (warn && !newOne && source) {
- // For the files, we want to report dupes.
- LOG(DEBUG) << "Multiple tag " << tag << " " << Name << " " << Format << " " << source;
- }
-}
-
-// Read the event log tags file, and build up our internal database
-void LogTags::ReadFileEventLogTags(const char* filename, bool warn) {
- bool etc = !strcmp(filename, system_event_log_tags);
-
- if (!etc) {
- RebuildFileEventLogTags(filename, warn);
- }
- std::string content;
- if (android::base::ReadFileToString(filename, &content)) {
- char* cp = (char*)content.c_str();
- char* endp = cp + content.length();
-
- {
- android::RWLock::AutoRLock writeLock(rwlock);
-
- file2watermark[filename] = content.length();
- }
-
- char* lineStart = cp;
- while (cp < endp) {
- if (*cp == '\n') {
- lineStart = cp;
- } else if (lineStart) {
- if (*cp == '#') {
- /* comment; just scan to end */
- lineStart = nullptr;
- } else if (isdigit(*cp)) {
- unsigned long Tag = strtoul(cp, &cp, 10);
- if (warn && (Tag > emptyTag)) {
- LOG(WARNING) << "tag too large " << Tag;
- }
- while ((cp < endp) && (*cp != '\n') && isspace(*cp)) ++cp;
- if (cp >= endp) break;
- if (*cp == '\n') continue;
- const char* name = cp;
- /* Determine whether it is a valid tag name [a-zA-Z0-9_] */
- bool hasAlpha = false;
- while ((cp < endp) && (isalnum(*cp) || (*cp == '_'))) {
- if (!isdigit(*cp)) hasAlpha = true;
- ++cp;
- }
- std::string Name(name, cp - name);
-#ifdef ALLOW_NOISY_LOGGING_OF_PROBLEM_WITH_LOTS_OF_TECHNICAL_DEBT
- static const size_t maximum_official_tag_name_size = 24;
- if (warn && (Name.length() > maximum_official_tag_name_size)) {
- LOG(WARNING) << "tag name too long " << Name;
- }
-#endif
- if (hasAlpha &&
- ((cp >= endp) || (*cp == '#') || isspace(*cp))) {
- if (Tag > emptyTag) {
- if (*cp != '\n') lineStart = nullptr;
- continue;
- }
- while ((cp < endp) && (*cp != '\n') && isspace(*cp))
- ++cp;
- const char* format = cp;
- uid_t uid = AID_ROOT;
- while ((cp < endp) && (*cp != '\n')) {
- if (*cp == '#') {
- uid = sniffUid(cp, endp);
- lineStart = nullptr;
- break;
- }
- ++cp;
- }
- while ((cp > format) && isspace(cp[-1])) {
- --cp;
- lineStart = nullptr;
- }
- std::string Format(format, cp - format);
-
- AddEventLogTags((uint32_t)Tag, uid, Name, Format,
- filename, warn);
- } else {
- if (warn) {
- LOG(ERROR) << android::base::StringPrintf("tag name invalid %.*s",
- (int)(cp - name + 1), name);
- }
- lineStart = nullptr;
- }
- } else if (!isspace(*cp)) {
- break;
- }
- }
- cp++;
- }
- } else if (warn) {
-#ifdef __ANDROID__
- LOG(ERROR) << "Cannot read " << filename;
-#endif
- }
-}
-
-// Extract a 4-byte value from a byte stream.
-static inline uint32_t get4LE(const char* msg) {
- const uint8_t* src = reinterpret_cast<const uint8_t*>(msg);
- return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
-}
-
-// Additional persistent sources for invented log tags. Read the
-// special pmsg event for log tags, and build up our internal
-// database with any found.
-void LogTags::ReadPersistEventLogTags() {
- struct logger_list* logger_list =
- android_logger_list_alloc(ANDROID_LOG_PSTORE | ANDROID_LOG_NONBLOCK, 0, (pid_t)0);
- if (!logger_list) return;
-
- struct logger* e = android_logger_open(logger_list, LOG_ID_EVENTS);
- struct logger* s = android_logger_open(logger_list, LOG_ID_SECURITY);
- if (!e && !s) {
- android_logger_list_free(logger_list);
- return;
- }
-
- for (;;) {
- struct log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
- if (ret <= 0) break;
-
- const char* msg = log_msg.msg();
- if (!msg) continue;
- if (log_msg.entry.len <= sizeof(uint32_t)) continue;
- uint32_t Tag = get4LE(msg);
- if (Tag != TAG_DEF_LOG_TAG) continue;
- uid_t uid = log_msg.entry.uid;
-
- std::string Name;
- std::string Format;
- android_log_list_element elem;
- {
- auto ctx = create_android_log_parser(log_msg.msg() + sizeof(uint32_t),
- log_msg.entry.len - sizeof(uint32_t));
- auto guard = make_scope_guard([&ctx]() { android_log_destroy(&ctx); });
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_LIST) {
- continue;
- }
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_INT) {
- continue;
- }
- Tag = elem.data.int32;
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_STRING) {
- continue;
- }
- Name = std::string(elem.data.string, elem.len);
- elem = android_log_read_next(ctx);
- if (elem.type != EVENT_TYPE_STRING) {
- continue;
- }
- Format = std::string(elem.data.string, elem.len);
- elem = android_log_read_next(ctx);
- }
- if ((elem.type != EVENT_TYPE_LIST_STOP) || !elem.complete) continue;
-
- AddEventLogTags(Tag, uid, Name, Format);
- }
- android_logger_list_free(logger_list);
-}
-
-LogTags::LogTags() {
- ReadFileEventLogTags(system_event_log_tags);
- // Following will likely fail on boot, but is required if logd restarts
- ReadFileEventLogTags(dynamic_event_log_tags, false);
- if (__android_log_is_debuggable()) {
- ReadFileEventLogTags(debug_event_log_tags, false);
- }
- ReadPersistEventLogTags();
-
- logtags = this;
-}
-
-// Converts an event tag into a name
-const char* LogTags::tagToName(uint32_t tag) const {
- tag2name_const_iterator it;
-
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-
- it = tag2name.find(tag);
- if ((it == tag2name.end()) || (it->second.length() == 0)) return nullptr;
-
- return it->second.c_str();
-}
-
-// Prototype in LogUtils.h allowing external access to our database.
-//
-// This must be a pure reader to our database, as everything else is
-// guaranteed single-threaded except this access point which is
-// asynchonous and can be multithreaded and thus rentrant. The
-// object's rwlock is only used to guarantee atomic access to the
-// unordered_map to prevent corruption, with a requirement to be a
-// low chance of contention for this call. If we end up changing
-// this algorithm resulting in write, then we should use a different
-// lock than the object's rwlock to protect groups of associated
-// actions.
-const char* android::tagToName(uint32_t tag) {
- LogTags* me = logtags;
-
- if (!me) return nullptr;
- me->WritePmsgEventLogTags(tag);
- return me->tagToName(tag);
-}
-
-// converts an event tag into a format
-const char* LogTags::tagToFormat(uint32_t tag) const {
- tag2format_const_iterator iform;
-
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-
- iform = tag2format.find(tag);
- if (iform == tag2format.end()) return nullptr;
-
- return iform->second.c_str();
-}
-
-// converts a name into an event tag
-uint32_t LogTags::nameToTag(const char* name) const {
- uint32_t ret = emptyTag;
-
- // Bug: Only works for a single entry, we can have multiple entries,
- // one for each format, so we find first entry recorded, or entry with
- // no format associated with it.
-
- android::RWLock::AutoRLock readLock(const_cast<android::RWLock&>(rwlock));
-
- key2tag_const_iterator ik = key2tag.find(std::string(name));
- if (ik != key2tag.end()) ret = ik->second;
-
- return ret;
-}
-
-// Caller must perform locks, can be under reader (for pre-check) or
-// writer lock. We use this call to invent a new deterministically
-// random tag, unique is cleared if no conflicts. If format is NULL,
-// we are in readonly mode.
-uint32_t LogTags::nameToTag_locked(const std::string& name, const char* format,
- bool& unique) {
- key2tag_const_iterator ik;
-
- bool write = format != nullptr;
- unique = write;
-
- if (!write) {
- // Bug: Only works for a single entry, we can have multiple entries,
- // one for each format, so we find first entry recorded, or entry with
- // no format associated with it.
- ik = key2tag.find(name);
- if (ik == key2tag.end()) return emptyTag;
- return ik->second;
- }
-
- std::string Key(name);
- if (*format) Key += std::string("+") + format;
-
- ik = key2tag.find(Key);
- if (ik != key2tag.end()) {
- unique = false;
- return ik->second;
- }
-
- size_t Hash = key2tag.hash_function()(Key);
- uint32_t Tag = Hash;
- // This sets an upper limit on the conflics we are allowed to deal with.
- for (unsigned i = 0; i < 256;) {
- tag2name_const_iterator it = tag2name.find(Tag);
- if (it == tag2name.end()) return Tag;
- std::string localKey(it->second);
- tag2format_const_iterator iform = tag2format.find(Tag);
- if ((iform == tag2format.end()) && iform->second.length()) {
- localKey += "+" + iform->second;
- }
- unique = !!it->second.compare(localKey);
- if (!unique) return Tag; // unlikely except in a race
-
- ++i;
- // Algorithm to convert hash to next tag
- if (i < 32) {
- Tag = (Hash >> i);
- // size_t is 32 bits, or upper word zero, rotate
- if ((sizeof(Hash) <= 4) || ((Hash & (uint64_t(-1LL) << 32)) == 0)) {
- Tag |= Hash << (32 - i);
- }
- } else {
- Tag = Hash + i - 31;
- }
- }
- return emptyTag;
-}
-
-static int openFile(const char* name, int mode, bool warning) {
- int fd = TEMP_FAILURE_RETRY(open(name, mode));
- if (fd < 0 && warning) {
- PLOG(ERROR) << "Failed to open " << name;
- }
- return fd;
-}
-
-void LogTags::WritePmsgEventLogTags(uint32_t tag, uid_t uid) {
- android::RWLock::AutoRLock readLock(rwlock);
-
- tag2total_const_iterator itot = tag2total.find(tag);
- if (itot == tag2total.end()) return; // source is a static entry
-
- size_t lastTotal = itot->second;
-
- // Every 16K (half the smallest configurable pmsg buffer size) record
- static const size_t rate_to_pmsg = 16 * 1024;
- if (lastTotal && (LogStatistics::sizesTotal() - lastTotal) < rate_to_pmsg) {
- return;
- }
-
- static int pmsg_fd = -1;
- if (pmsg_fd < 0) {
- pmsg_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
- // unlikely, but deal with partners with borken pmsg
- if (pmsg_fd < 0) return;
- }
-
- std::string Name = tag2name[tag];
- tag2format_const_iterator iform = tag2format.find(tag);
- std::string Format = (iform != tag2format.end()) ? iform->second : "";
-
- auto ctx = create_android_logger(TAG_DEF_LOG_TAG);
- auto guard = make_scope_guard([&ctx]() { android_log_destroy(&ctx); });
- if (android_log_write_int32(ctx, static_cast<int32_t>(tag) < 0) ||
- android_log_write_string8_len(ctx, Name.c_str(), Name.size()) < 0 ||
- android_log_write_string8_len(ctx, Format.c_str(), Format.size()) < 0) {
- return;
- }
-
- const char* cp = nullptr;
- ssize_t len = android_log_write_list_buffer(ctx, &cp);
-
- if (len <= 0 || cp == nullptr) {
- return;
- }
-
- std::string buffer(cp, len);
-
- /*
- * struct {
- * // what we provide to pstore
- * android_pmsg_log_header_t pmsgHeader;
- * // what we provide to file
- * android_log_header_t header;
- * // caller provides
- * union {
- * struct {
- * char prio;
- * char payload[];
- * } string;
- * struct {
- * uint32_t tag
- * char payload[];
- * } binary;
- * };
- * };
- */
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
-
- android_log_header_t header = {
- .id = LOG_ID_EVENTS,
- .tid = static_cast<uint16_t>(android::base::GetThreadId()),
- .realtime.tv_sec = static_cast<uint32_t>(ts.tv_sec),
- .realtime.tv_nsec = static_cast<uint32_t>(ts.tv_nsec),
- };
-
- uint32_t outTag = TAG_DEF_LOG_TAG;
- outTag = get4LE((const char*)&outTag);
-
- android_pmsg_log_header_t pmsgHeader = {
- .magic = LOGGER_MAGIC,
- .len = (uint16_t)(sizeof(pmsgHeader) + sizeof(header) + sizeof(outTag) +
- buffer.length()),
- .uid = (uint16_t)AID_ROOT,
- .pid = (uint16_t)getpid(),
- };
-
- struct iovec Vec[] = { { (unsigned char*)&pmsgHeader, sizeof(pmsgHeader) },
- { (unsigned char*)&header, sizeof(header) },
- { (unsigned char*)&outTag, sizeof(outTag) },
- { (unsigned char*)const_cast<char*>(buffer.data()),
- buffer.length() } };
-
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if (ut == tag2uid.end()) {
- TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
- } else if (uid != AID_ROOT) {
- pmsgHeader.uid = (uint16_t)uid;
- TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
- } else {
- for (auto& it : ut->second) {
- pmsgHeader.uid = (uint16_t)it;
- TEMP_FAILURE_RETRY(writev(pmsg_fd, Vec, arraysize(Vec)));
- }
- }
-}
-
-void LogTags::WriteDynamicEventLogTags(uint32_t tag, uid_t uid) {
- static const int mode =
- O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
-
- int fd = openFile(dynamic_event_log_tags, mode, true);
- if (fd < 0) return;
-
- android::RWLock::AutoWLock writeLock(rwlock);
-
- std::string ret = formatEntry_locked(tag, uid, false);
- android::base::WriteStringToFd(ret, fd);
- close(fd);
-
- size_t size = 0;
- file2watermark_const_iterator iwater;
-
- iwater = file2watermark.find(dynamic_event_log_tags);
- if (iwater != file2watermark.end()) size = iwater->second;
-
- file2watermark[dynamic_event_log_tags] = size + ret.length();
-}
-
-void LogTags::WriteDebugEventLogTags(uint32_t tag, uid_t uid) {
- static const int mode =
- O_WRONLY | O_APPEND | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
-
- static bool one = true;
- int fd = openFile(debug_event_log_tags, mode, one);
- one = fd >= 0;
- if (!one) return;
-
- android::RWLock::AutoWLock writeLock(rwlock);
-
- std::string ret = formatEntry_locked(tag, uid, false);
- android::base::WriteStringToFd(ret, fd);
- close(fd);
-
- size_t size = 0;
- file2watermark_const_iterator iwater;
-
- iwater = file2watermark.find(debug_event_log_tags);
- if (iwater != file2watermark.end()) size = iwater->second;
-
- file2watermark[debug_event_log_tags] = size + ret.length();
-}
-
-// How we maintain some runtime or reboot stickiness
-void LogTags::WritePersistEventLogTags(uint32_t tag, uid_t uid,
- const char* source) {
- // very unlikely
- bool etc = source && !strcmp(source, system_event_log_tags);
- if (etc) return;
-
- bool dynamic = source && !strcmp(source, dynamic_event_log_tags);
- bool debug = (!dynamic && source && !strcmp(source, debug_event_log_tags)) ||
- !__android_log_is_debuggable();
-
- WritePmsgEventLogTags(tag, uid);
-
- size_t lastTotal = 0;
- {
- android::RWLock::AutoRLock readLock(rwlock);
-
- tag2total_const_iterator itot = tag2total.find(tag);
- if (itot != tag2total.end()) lastTotal = itot->second;
- }
-
- if (lastTotal == 0) { // denotes first time for this one
- if (!dynamic || !RebuildFileEventLogTags(dynamic_event_log_tags)) {
- WriteDynamicEventLogTags(tag, uid);
- }
-
- if (!debug && !RebuildFileEventLogTags(debug_event_log_tags)) {
- WriteDebugEventLogTags(tag, uid);
- }
- }
-
- lastTotal = LogStatistics::sizesTotal();
- if (!lastTotal) ++lastTotal;
-
- // record totals for next watermark.
- android::RWLock::AutoWLock writeLock(rwlock);
- tag2total[tag] = lastTotal;
-}
-
-// nameToTag converts a name into an event tag. If format is NULL, then we
-// are in readonly mode.
-uint32_t LogTags::nameToTag(uid_t uid, const char* name, const char* format) {
- std::string Name = std::string(name);
- bool write = format != nullptr;
- bool updateUid = uid != AID_ROOT;
- bool updateFormat = format && *format;
- bool unique;
- uint32_t Tag;
-
- {
- android::RWLock::AutoRLock readLock(rwlock);
-
- Tag = nameToTag_locked(Name, format, unique);
- if (updateUid && (Tag != emptyTag) && !unique) {
- tag2uid_const_iterator ut = tag2uid.find(Tag);
- if (updateUid) {
- if ((ut != tag2uid.end()) &&
- (ut->second.find(uid) == ut->second.end())) {
- unique = write; // write passthrough to update uid counts
- if (!write) Tag = emptyTag; // deny read access
- }
- } else {
- unique = write && (ut != tag2uid.end());
- }
- }
- }
-
- if (Tag == emptyTag) return Tag;
- WritePmsgEventLogTags(Tag, uid); // record references periodically
- if (!unique) return Tag;
-
- bool updateWrite = false;
- bool updateTag;
-
- // Special case of AddEventLogTags, checks per-uid counter which makes
- // no sense there, and is also optimized somewhat to reduce write times.
- {
- android::RWLock::AutoWLock writeLock(rwlock);
-
- // double check after switch from read lock to write lock for Tag
- updateTag = tag2name.find(Tag) == tag2name.end();
- // unlikely, either update, race inviting conflict or multiple uids
- if (!updateTag) {
- Tag = nameToTag_locked(Name, format, unique);
- if (Tag == emptyTag) return Tag;
- // is it multiple uid's setting this value
- if (!unique) {
- tag2uid_const_iterator ut = tag2uid.find(Tag);
- if (updateUid) {
- // Add it to the uid list
- if ((ut == tag2uid.end()) ||
- (ut->second.find(uid) != ut->second.end())) {
- return Tag;
- }
- const_cast<uid_list&>(ut->second).emplace(uid);
- updateWrite = true;
- } else {
- if (ut == tag2uid.end()) return Tag;
- // (system) adding a global one, erase the uid list
- tag2uid.erase(ut);
- updateWrite = true;
- }
- }
- }
-
- // Update section
- size_t count;
- if (updateUid) {
- count = 0;
- uid2count_const_iterator ci = uid2count.find(uid);
- if (ci != uid2count.end()) {
- count = ci->second;
- if (count >= max_per_uid) {
- if (!updateWrite) return emptyTag;
- // If we are added to the per-Uid perms, leak the Tag
- // if it already exists.
- updateUid = false;
- updateTag = false;
- updateFormat = false;
- }
- }
- }
-
- // updateWrite -> trigger output on modified content, reset tag2total
- // also sets static to dynamic entries if they are alterred,
- // only occurs if they have a uid, and runtime adds another uid.
- if (updateWrite) tag2total[Tag] = 0;
-
- if (updateTag) {
- // mark as a dynamic entry, but do not upset current total counter
- tag2total_const_iterator itot = tag2total.find(Tag);
- if (itot == tag2total.end()) tag2total[Tag] = 0;
-
- if (*format) {
- key2tag[Name + "+" + format] = Tag;
- if (key2tag.find(Name) == key2tag.end()) key2tag[Name] = Tag;
- } else {
- key2tag[Name] = Tag;
- }
- tag2name[Tag] = Name;
- }
- if (updateFormat) tag2format[Tag] = format;
-
- if (updateUid) {
- tag2uid[Tag].emplace(uid);
- uid2count[uid] = count + 1;
- }
- }
-
- if (updateTag || updateFormat || updateWrite) {
- WritePersistEventLogTags(Tag, uid);
- }
-
- return Tag;
-}
-
-std::string LogTags::formatEntry(uint32_t tag, uid_t uid, const char* name,
- const char* format) {
- if (!format || !format[0]) {
- return android::base::StringPrintf("%" PRIu32 "\t%s\n", tag, name);
- }
- size_t len = (strlen(name) + 7) / 8;
- static const char tabs[] = "\t\t\t";
- if (len > strlen(tabs)) len = strlen(tabs);
- std::string Uid;
- if (uid != AID_ROOT) Uid = android::base::StringPrintf(" # uid=%u", uid);
- return android::base::StringPrintf("%" PRIu32 "\t%s%s\t%s%s\n", tag, name,
- &tabs[len], format, Uid.c_str());
-}
-
-std::string LogTags::formatEntry_locked(uint32_t tag, uid_t uid,
- bool authenticate) {
- const char* name = tag2name[tag].c_str();
-
- const char* format = "";
- tag2format_const_iterator iform = tag2format.find(tag);
- if (iform != tag2format.end()) format = iform->second.c_str();
-
- // Access permission test, do not report dynamic entries
- // that do not belong to us.
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if (ut == tag2uid.end()) {
- return formatEntry(tag, AID_ROOT, name, format);
- }
- if (uid != AID_ROOT) {
- if (authenticate && (ut->second.find(uid) == ut->second.end())) {
- return std::string("");
- }
- return formatEntry(tag, uid, name, format);
- }
-
- // Show all, one for each registered uid (we are group root)
- std::string ret;
- for (auto& it : ut->second) {
- ret += formatEntry(tag, it, name, format);
- }
- return ret;
-}
-
-std::string LogTags::formatEntry(uint32_t tag, uid_t uid) {
- android::RWLock::AutoRLock readLock(rwlock);
- return formatEntry_locked(tag, uid);
-}
-
-std::string LogTags::formatGetEventTag(uid_t uid, const char* name,
- const char* format) {
- bool all = name && (name[0] == '*') && !name[1];
- bool list = !name || all;
- std::string ret;
-
- if (!list) {
- // switch to read entry only if format == "*"
- if (format && (format[0] == '*') && !format[1]) format = nullptr;
-
- // WAI: for null format, only works for a single entry, we can have
- // multiple entries, one for each format, so we find first entry
- // recorded, or entry with no format associated with it.
- // We may desire to print all that match the name, but we did not
- // add a mapping table for that and the cost is too high.
- uint32_t tag = nameToTag(uid, name, format);
- if (tag == emptyTag) return std::string("-1 ESRCH");
- if (uid == AID_ROOT) {
- android::RWLock::AutoRLock readLock(rwlock);
-
- // first uid in list so as to manufacture an accurate reference
- tag2uid_const_iterator ut = tag2uid.find(tag);
- if ((ut != tag2uid.end()) &&
- (ut->second.begin() != ut->second.end())) {
- uid = *(ut->second.begin());
- }
- }
- ret = formatEntry(tag, uid, name, format ?: tagToFormat(tag));
- if (!ret.length()) return std::string("-1 ESRCH");
- return ret;
- }
-
- android::RWLock::AutoRLock readLock(rwlock);
- if (all) {
- // everything under the sun
- for (const auto& it : tag2name) {
- ret += formatEntry_locked(it.first, uid);
- }
- } else {
- // set entries are dynamic
- for (const auto& it : tag2total) {
- ret += formatEntry_locked(it.first, uid);
- }
- }
- return ret;
-}
diff --git a/logd/LogTags.h b/logd/LogTags.h
deleted file mode 100644
index cce700c..0000000
--- a/logd/LogTags.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#pragma once
-
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-
-#include <private/android_filesystem_config.h>
-#include <utils/RWLock.h>
-
-class LogTags {
- // This lock protects all the unordered_map accesses below. It
- // is a reader/writer lock so that contentions are kept to a
- // minimum since writes are rare, even administratably when
- // reads are extended. Resist the temptation to use the writer
- // lock to protect anything outside the following unordered_maps
- // as that would increase the reader contentions. Use a separate
- // mutex to protect the other entities.
- android::RWLock rwlock;
-
- // key is Name + "+" + Format
- std::unordered_map<std::string, uint32_t> key2tag;
- typedef std::unordered_map<std::string, uint32_t>::const_iterator
- key2tag_const_iterator;
-
- // Allows us to manage access permissions based on uid registrants
- // Global entries are specifically erased.
- typedef std::unordered_set<uid_t> uid_list;
- std::unordered_map<uint32_t, uid_list> tag2uid;
- typedef std::unordered_map<uint32_t, uid_list>::const_iterator
- tag2uid_const_iterator;
-
- std::unordered_map<uint32_t, std::string> tag2name;
- typedef std::unordered_map<uint32_t, std::string>::const_iterator
- tag2name_const_iterator;
-
- std::unordered_map<uint32_t, std::string> tag2format;
- typedef std::unordered_map<uint32_t, std::string>::const_iterator
- tag2format_const_iterator;
-
- static const size_t max_per_uid = 256; // Put a cap on the tags per uid
- std::unordered_map<uid_t, size_t> uid2count;
- typedef std::unordered_map<uid_t, size_t>::const_iterator
- uid2count_const_iterator;
-
- // Dynamic entries are assigned
- std::unordered_map<uint32_t, size_t> tag2total;
- typedef std::unordered_map<uint32_t, size_t>::const_iterator
- tag2total_const_iterator;
-
- // emplace unique tag
- uint32_t nameToTag(uid_t uid, const char* name, const char* format);
- // find unique or associated tag
- uint32_t nameToTag_locked(const std::string& name, const char* format,
- bool& unique);
-
- // Record expected file watermarks to detect corruption.
- std::unordered_map<std::string, size_t> file2watermark;
- typedef std::unordered_map<std::string, size_t>::const_iterator
- file2watermark_const_iterator;
-
- void ReadPersistEventLogTags();
-
- // format helpers
- // format a single entry, does not need object data
- static std::string formatEntry(uint32_t tag, uid_t uid, const char* name,
- const char* format);
- // caller locks, database lookup, authenticate against uid
- std::string formatEntry_locked(uint32_t tag, uid_t uid,
- bool authenticate = true);
-
- bool RebuildFileEventLogTags(const char* filename, bool warn = true);
-
- void AddEventLogTags(uint32_t tag, uid_t uid, const std::string& Name,
- const std::string& Format, const char* source = nullptr,
- bool warn = false);
-
- void WriteDynamicEventLogTags(uint32_t tag, uid_t uid);
- void WriteDebugEventLogTags(uint32_t tag, uid_t uid);
- // push tag details to persistent storage
- void WritePersistEventLogTags(uint32_t tag, uid_t uid = AID_ROOT,
- const char* source = nullptr);
-
- static const uint32_t emptyTag = uint32_t(-1);
-
- public:
- static const char system_event_log_tags[];
- static const char dynamic_event_log_tags[];
- // Only for userdebug and eng
- static const char debug_event_log_tags[];
-
- LogTags();
-
- void WritePmsgEventLogTags(uint32_t tag, uid_t uid = AID_ROOT);
- void ReadFileEventLogTags(const char* filename, bool warn = true);
-
- // reverse lookup from tag
- const char* tagToName(uint32_t tag) const;
- const char* tagToFormat(uint32_t tag) const;
- std::string formatEntry(uint32_t tag, uid_t uid);
- // find associated tag
- uint32_t nameToTag(const char* name) const;
-
- // emplace tag if necessary, provide event-log-tag formated output in string
- std::string formatGetEventTag(uid_t uid, const char* name,
- const char* format);
-};
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
deleted file mode 100644
index c0f62d3..0000000
--- a/logd/LogUtils.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012-2015 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.
- */
-
-#pragma once
-
-#include <sys/cdefs.h>
-#include <sys/types.h>
-
-#include <private/android_logger.h>
-#include <utils/FastStrcmp.h>
-
-// Hijack this header as a common include file used by most all sources
-// to report some utilities defined here and there.
-
-#define LOGD_SNDTIMEO 32
-
-namespace android {
-
-// Furnished in main.cpp. Caller must own and free returned value
-char* uidToName(uid_t uid);
-
-// Caller must own and free returned value
-char* pidToName(pid_t pid);
-char* tidToName(pid_t tid);
-
-// Furnished in LogTags.cpp. Thread safe.
-const char* tagToName(uint32_t tag);
-
-// Furnished by LogKlog.cpp
-char* log_strntok_r(char* s, ssize_t& len, char*& saveptr, ssize_t& sublen);
-
-// needle should reference a string longer than 1 character
-static inline const char* strnstr(const char* s, ssize_t len,
- const char* needle) {
- if (len <= 0) return nullptr;
-
- const char c = *needle++;
- const size_t needleLen = strlen(needle);
- do {
- do {
- if (len <= (ssize_t)needleLen) return nullptr;
- --len;
- } while (*s++ != c);
- } while (fastcmp<memcmp>(s, needle, needleLen));
- s--;
- return s;
-}
-}
-
-// Returns true if the log buffer is meant for binary logs.
-static inline bool IsBinary(log_id_t log_id) {
- return log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS || log_id == LOG_ID_SECURITY;
-}
-
-// Returns the numeric log tag for binary log messages.
-static inline uint32_t MsgToTag(const char* msg, uint16_t msg_len) {
- if (msg_len < sizeof(android_event_header_t)) {
- return 0;
- }
-
- return reinterpret_cast<const android_event_header_t*>(msg)->tag;
-}
-
-static inline bool worstUidEnabledForLogid(log_id_t id) {
- return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) ||
- (id == LOG_ID_RADIO) || (id == LOG_ID_EVENTS);
-}
diff --git a/logd/LogWriter.h b/logd/LogWriter.h
deleted file mode 100644
index d43c604..0000000
--- a/logd/LogWriter.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <string>
-
-#include <log/log_read.h>
-
-// An interface for writing logs to a reader.
-class LogWriter {
- public:
- LogWriter(uid_t uid, bool privileged) : uid_(uid), privileged_(privileged) {}
- virtual ~LogWriter() {}
-
- virtual bool Write(const logger_entry& entry, const char* msg) = 0;
- virtual void Shutdown() {}
- virtual void Release() {}
-
- virtual std::string name() const = 0;
- uid_t uid() const { return uid_; }
-
- bool privileged() const { return privileged_; }
-
- private:
- uid_t uid_;
-
- // If this writer sees logs from all UIDs or only its own UID. See clientHasLogCredentials().
- bool privileged_;
-};
\ No newline at end of file
diff --git a/logd/OWNERS b/logd/OWNERS
deleted file mode 100644
index 2394e32..0000000
--- a/logd/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-cferris@google.com
-tomcherry@google.com
diff --git a/logd/PruneList.cpp b/logd/PruneList.cpp
deleted file mode 100644
index c3859f3..0000000
--- a/logd/PruneList.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2014 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 "PruneList.h"
-
-#include <ctype.h>
-
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-bool Prune::Matches(LogBufferElement* element) const {
- return (uid_ == UID_ALL || uid_ == element->uid()) &&
- (pid_ == PID_ALL || pid_ == element->pid());
-}
-
-std::string Prune::Format() const {
- if (uid_ != UID_ALL) {
- if (pid_ != PID_ALL) {
- return android::base::StringPrintf("%u/%u", uid_, pid_);
- }
- return android::base::StringPrintf("%u", uid_);
- }
- if (pid_ != PID_ALL) {
- return android::base::StringPrintf("/%u", pid_);
- }
- // NB: pid_ == PID_ALL can not happen if uid_ == UID_ALL
- return std::string("/");
-}
-
-PruneList::PruneList() {
- Init(nullptr);
-}
-
-bool PruneList::Init(const char* str) {
- high_priority_prune_.clear();
- low_priority_prune_.clear();
-
- // default here means take ro.logd.filter, persist.logd.filter then internal default in order.
- if (str && !strcmp(str, "default")) {
- str = nullptr;
- }
- if (str && !strcmp(str, "disable")) {
- str = "";
- }
-
- std::string filter;
-
- if (str) {
- filter = str;
- } else {
- filter = android::base::GetProperty("ro.logd.filter", "default");
- auto persist_filter = android::base::GetProperty("persist.logd.filter", "default");
- // default here means take ro.logd.filter
- if (persist_filter != "default") {
- filter = persist_filter;
- }
- }
-
- // default here means take internal default.
- if (filter == "default") {
- filter = "~! ~1000/!";
- }
- if (filter == "disable") {
- filter = "";
- }
-
- worst_uid_enabled_ = false;
- worst_pid_of_system_enabled_ = false;
-
- for (str = filter.c_str(); *str; ++str) {
- if (isspace(*str)) {
- continue;
- }
-
- std::list<Prune>* list;
- if (*str == '~' || *str == '!') { // ~ supported, ! undocumented
- ++str;
- // special case, prune the worst UID of those using at least 1/8th of the buffer.
- if (*str == '!') {
- worst_uid_enabled_ = true;
- ++str;
- if (!*str) {
- break;
- }
- if (!isspace(*str)) {
- LOG(ERROR) << "Nothing expected after '~!', but found '" << str << "'";
- return false;
- }
- continue;
- }
- // special case, translated to worst PID of System at priority
- static const char WORST_SYSTEM_PID[] = "1000/!";
- if (!strncmp(str, WORST_SYSTEM_PID, sizeof(WORST_SYSTEM_PID) - 1)) {
- worst_pid_of_system_enabled_ = true;
- str += sizeof(WORST_SYSTEM_PID) - 1;
- if (!*str) {
- break;
- }
- if (!isspace(*str)) {
- LOG(ERROR) << "Nothing expected after '~1000/!', but found '" << str << "'";
- return false;
- }
- continue;
- }
- if (!*str) {
- LOG(ERROR) << "Expected UID or PID after '~', but found nothing";
- return false;
- }
- list = &high_priority_prune_;
- } else {
- list = &low_priority_prune_;
- }
-
- uid_t uid = Prune::UID_ALL;
- if (isdigit(*str)) {
- uid = 0;
- do {
- uid = uid * 10 + *str++ - '0';
- } while (isdigit(*str));
- }
-
- pid_t pid = Prune::PID_ALL;
- if (*str == '/') {
- ++str;
- if (isdigit(*str)) {
- pid = 0;
- do {
- pid = pid * 10 + *str++ - '0';
- } while (isdigit(*str));
- }
- }
-
- if (uid == Prune::UID_ALL && pid == Prune::PID_ALL) {
- LOG(ERROR) << "Expected UID/PID combination, but found none";
- return false;
- }
-
- if (*str && !isspace(*str)) {
- LOG(ERROR) << "Nothing expected after UID/PID combination, but found '" << str << "'";
- return false;
- }
-
- list->emplace_back(uid, pid);
- if (!*str) {
- break;
- }
- }
-
- return true;
-}
-
-std::string PruneList::Format() const {
- std::vector<std::string> prune_rules;
-
- if (worst_uid_enabled_) {
- prune_rules.emplace_back("~!");
- }
- if (worst_pid_of_system_enabled_) {
- prune_rules.emplace_back("~1000/!");
- }
- for (const auto& rule : low_priority_prune_) {
- prune_rules.emplace_back(rule.Format());
- }
- for (const auto& rule : high_priority_prune_) {
- prune_rules.emplace_back("~" + rule.Format());
- }
- return android::base::Join(prune_rules, " ");
-}
-
-bool PruneList::IsHighPriority(LogBufferElement* element) const {
- for (const auto& rule : high_priority_prune_) {
- if (rule.Matches(element)) {
- return true;
- }
- }
- return false;
-}
-
-bool PruneList::IsLowPriority(LogBufferElement* element) const {
- for (const auto& rule : low_priority_prune_) {
- if (rule.Matches(element)) {
- return true;
- }
- }
- return false;
-}
diff --git a/logd/PruneList.h b/logd/PruneList.h
deleted file mode 100644
index 94de5c5..0000000
--- a/logd/PruneList.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-#include <string.h>
-#include <list>
-
-#include "LogBufferElement.h"
-
-class Prune {
- public:
- static const uid_t UID_ALL = (uid_t)-1;
- static const pid_t PID_ALL = (pid_t)-1;
-
- Prune(uid_t uid, pid_t pid) : uid_(uid), pid_(pid) {}
-
- bool Matches(LogBufferElement* element) const;
- std::string Format() const;
-
- uid_t uid() const { return uid_; }
- pid_t pid() const { return pid_; }
-
- private:
- const uid_t uid_;
- const pid_t pid_;
-};
-
-class PruneList {
- public:
- PruneList();
-
- bool Init(const char* str);
- std::string Format() const;
-
- bool IsHighPriority(LogBufferElement* element) const;
- bool IsLowPriority(LogBufferElement* element) const;
-
- bool HasHighPriorityPruneRules() const { return !high_priority_prune_.empty(); }
- bool HasLowPriorityPruneRules() const { return !low_priority_prune_.empty(); }
-
- bool worst_uid_enabled() const { return worst_uid_enabled_; }
- bool worst_pid_of_system_enabled() const { return worst_pid_of_system_enabled_; }
-
- private:
- std::list<Prune> high_priority_prune_;
- std::list<Prune> low_priority_prune_;
-
- bool worst_uid_enabled_;
- bool worst_pid_of_system_enabled_;
-};
diff --git a/logd/README.auditd b/logd/README.auditd
deleted file mode 100644
index 3f614a3..0000000
--- a/logd/README.auditd
+++ /dev/null
@@ -1,17 +0,0 @@
-Auditd Daemon
-
-The audit daemon is a simplified version of its desktop
-counterpart designed to gather the audit logs from the
-audit kernel subsystem. The audit subsystem of the kernel
-includes Linux Security Modules (LSM) messages as well.
-
-To enable the audit subsystem, you must add this to your
-kernel config:
-CONFIG_AUDIT=y
-
-To enable a LSM, you must consult that LSM's documentation, the
-example below is for SELinux:
-CONFIG_SECURITY_SELINUX=y
-
-This does not include possible dependencies that may need to be
-satisfied for that particular LSM.
diff --git a/logd/README.compression.md b/logd/README.compression.md
deleted file mode 100644
index 4ba634a..0000000
--- a/logd/README.compression.md
+++ /dev/null
@@ -1,81 +0,0 @@
-# Log Compression instead of Chatty in Android S
-
-## The problem
-
-* Log buffer space is precious, but suffers from the tragedy of the commons
-* Log spam fills the buffers making them less useful in logcat/bugreports
-* “Spam” is often in the eye of the beholder: which messages are important depends on what you’re trying to debug
-
-## The idea
-
-* Chatty isn’t helping as much as we’d hoped, and is surprisingly expensive
-* Compress logs to make more efficient use of the buffer
-* Address the root cause of log spam at its source:
- * Do not hide log spam at runtime, which de-incentivize fixes
- * Add presubmit coverage similar to SELinux violations to keep log spam down
-
----
-
-## Chatty in Theory
-
-* Delete messages classified as spam to extend the range of logs from other sources
-* “Spam” defined as:
- * Logs from UIDs whose logs consume over 12.5% of a log buffer
- * Back-to-back exact duplicate messages
-
-## Chatty in Practice
-
-* Developer confusion about missing and de-duplicated logs
-* Lowered incentive to fix the root cause of bad logging behavior
-* High CPU overhead
-* Memory usage greatly exceeds configured buffer size
-* Only marginal increase in log range
-
----
-
-## Log Compression in Theory
-
-* Store many more logs in the same log buffer size => better for diagnosis
-* Memory usage stays below configured log size => better system health
-* No gaps in logs, no de-duplicated logs => no developer confusion
-* No hiding bad behavior => increased accountability/incentive to fix root causes
-
-## Log Compression Preliminary Results
-
-* Captured 2, 5 day periods of full time personal usage of Pixel 4 and replayed the logs offline
-* Compression vs Chatty:
- * **3.5x more log messages on average**
- * **50% less CPU usage**
- * **50% less memory usage**
-
----
-
-## Log Messages in 1MB
-
-* The number of log messages still available in logcat after ‘Message Count’ messages have been logged to a 1MB log buffer
-* Note: ‘Simple’ is the Chatty code without log spam detection and without de-duplication.
-
-
-
----
-
-## CPU Time
-
-* Total CPU time on ARM64 (Walleye) and 32bit x86 (Cuttlefish)
-* X axis represents different log buffer size configurations.
- * Chatty uses significantly more CPU time at 1MB (the default Pixel configuration)
- * Chatty scales poorly with increased log buffer sizes
-* Note: “simple” isn’t “compression without actually compressing”, it’s “chatty without doing the chatty elimination”, which is why “simple” is more expensive than “compression” on walleye.
-
-
-
-
----
-
-## Memory Usage
-
-* The memory used by ‘Message Count’ messages, on both Walleye and Cuttlefish
-* Note: Chatty does not consider the metadata (UID, PID, timestamp, etc) in its calculation of log buffer size, so a 1MB log buffer will consume more than 1MB. Note that there are 8 log buffers, 5 of which are typically filled.
-
-
-
diff --git a/logd/README.property b/logd/README.property
deleted file mode 100644
index 8fd7f48..0000000
--- a/logd/README.property
+++ /dev/null
@@ -1,72 +0,0 @@
-The properties that logd and friends react to are:
-
-name type default description
-ro.logd.auditd bool true Enable selinux audit daemon
-ro.logd.auditd.dmesg bool true selinux audit messages sent to dmesg.
-ro.logd.auditd.main bool true selinux audit messages sent to main.
-ro.logd.auditd.events bool true selinux audit messages sent to events.
-persist.logd.security bool false Enable security buffer.
-ro.organization_owned bool false Override persist.logd.security to false
-ro.logd.kernel bool svelte+ Enable klogd daemon
-logd.statistics bool svelte+ Enable logcat -S statistics.
-ro.debuggable number if not "1", logd.statistics &
- ro.logd.kernel default false.
-logd.logpersistd.enable bool auto Safe to start logpersist daemon service
-logd.logpersistd string persist Enable logpersist daemon, "logcatd"
- turns on logcat -f in logd context.
- Responds to logcatd, clear and stop.
-logd.logpersistd.buffer persist logpersistd buffers to collect
-logd.logpersistd.size persist logpersistd size in MB
-logd.logpersistd.rotate_kbytes persist logpersistd outout file size in KB.
-persist.logd.logpersistd string Enable logpersist daemon, "logcatd"
- turns on logcat -f in logd context.
-persist.logd.logpersistd.buffer all logpersistd buffers to collect
-persist.logd.logpersistd.size 256 logpersistd size in MB
-persist.logd.logpersistd.count 256 sets max number of rotated logs to <count>.
-persist.logd.logpersistd.rotate_kbytes 1024 logpersistd output file size in KB
-persist.logd.size number ro Global default size of the buffer for
- all log ids at initial startup, at
- runtime use: logcat -b all -G <value>
-ro.logd.size number svelte default for persist.logd.size. Larger
- platform default sizes than 256KB are
- known to not scale well under log spam
- pressure. Address the spam first,
- resist increasing the log buffer.
-persist.logd.size.<buffer> number ro Size of the buffer for <buffer> log
-ro.logd.size.<buffer> number svelte default for persist.logd.size.<buffer>
-ro.config.low_ram bool false if true, logd.statistics,
- ro.logd.kernel default false,
- logd.size 64K instead of 256K.
-persist.logd.filter string Pruning filter to optimize content.
- At runtime use: logcat -P "<string>"
-ro.logd.filter string "~! ~1000/!" default for persist.logd.filter.
- This default means to prune the
- oldest entries of chattiest UID, and
- the chattiest PID of system
- (1000, or AID_SYSTEM).
-log.tag string persist The global logging level, VERBOSE,
- DEBUG, INFO, WARN, ERROR, ASSERT or
- SILENT. Only the first character is
- the key character.
-persist.log.tag string build default for log.tag
-log.tag.<tag> string persist The <tag> specific logging level.
-persist.log.tag.<tag> string build default for log.tag.<tag>
-
-logd.buffer_type string (empty) Set the log buffer type. Current choices are 'simple',
- 'chatty', or 'serialized'. Defaults to 'chatty' if empty.
-
-NB:
-- auto - managed by /init
-- svelte - see ro.config.low_ram for details.
-- svelte+ - If empty, default to true if `ro.config.low_ram == false && ro.debuggable == true`
-- ro - <base property> temporary override, ro.<base property> platform default.
-- persist - <base property> override, persist.<base property> platform default.
-- build - VERBOSE for native, DEBUG for jvm isLoggable, or developer option.
-- number - support multipliers (K or M) for convenience. Range is limited
- to between 64K and 256M for log buffer sizes. Individual log buffer ids
- such as main, system, ... override global default.
-- Pruning filter rules are specified as UID, UID/PID or /PID. A '~' prefix indicates that elements
- matching the rule should be pruned with higher priority otherwise they're pruned with lower
- priority. All other pruning activity is oldest first. Special case ~! represents an automatic
- pruning for the noisiest UID as determined by the current statistics. Special case ~1000/!
- represents pruning of the worst PID within AID_SYSTEM when AID_SYSTEM is the noisiest UID.
diff --git a/logd/README.replay.md b/logd/README.replay.md
deleted file mode 100644
index 5f7ec9e..0000000
--- a/logd/README.replay.md
+++ /dev/null
@@ -1,46 +0,0 @@
-logd can record and replay log messages for offline analysis.
-
-Recording Messages
-------------------
-
-logd has a `RecordingLogBuffer` buffer that records messages to /data/misc/logd/recorded-messages.
-It stores messages in memory until that file is accessible, in order to capture all messages since
-the beginning of boot. It is only meant for logging developers to use and must be manually enabled
-in by adding `RecordingLogBuffer.cpp` to `Android.bp` and setting
-`log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);` in `main.cpp`.
-
-Recording messages may delay the Log() function from completing and it is highly recommended to make
-the logd socket in `liblog` blocking, by removing `SOCK_NONBLOCK` from the `socket()` call in
-`liblog/logd_writer.cpp`.
-
-Replaying Messages
-------------------
-
-Recorded messages can be replayed offline with the `replay_messages` tool. It runs on host and
-device and supports the following options:
-
-1. `interesting` - this prints 'interesting' statistics for each of the log buffer types (simple,
- chatty, serialized). The statistics are:
- 1. Log Entry Count
- 2. Size (the uncompressed size of the log messages in bytes)
- 3. Overhead (the total cost of the log messages in memory in bytes)
- 4. Range (the range of time that the logs cover in seconds)
-2. `memory_usage BUFFER_TYPE` - this prints the memory usage (sum of private dirty pages of the
- `replay_messages` process). Note that the input file is mmap()'ed as RO/Shared so it does not
- appear in these dirty pages, and a baseline is taken before allocating the log buffers, so only
- their contributions are measured. The tool outputs the memory usage every 100,000 messages.
-3. `latency BUFFER_TYPE` - this prints statistics of the latency of the Log() function for the given
- buffer type. It specifically prints the 1st, 2nd, and 3rd quartiles; the 95th, 99th, and 99.99th
- percentiles; and the maximum latency.
-4. `print_logs BUFFER_TYPE [buffers] [print_point]` - this prints the logs as processed by the given
- buffer_type from the buffers specified by `buffers` starting after the number of logs specified by
- `print_point` have been logged. This acts as if a user called `logcat` immediately after the
- specified logs have been logged, which is particularly useful since it will show the chatty
- pruning messages at that point. It additionally prints the statistics from `logcat -S` after the
- logs.
- `buffers` is a comma separated list of the numeric buffer id values from `<android/log.h>`. For
- example, `0,1,3` represents the main, radio, and system buffers. It can can also be `all`.
- `print_point` is an positive integer. If it is unspecified, logs are printed after the entire
- input file is consumed.
-5. `nothing BUFFER_TYPE` - this does nothing other than read the input file and call Log() for the
- given buffer type. This is used for profiling CPU usage of strictly the log buffer.
diff --git a/logd/RecordedLogMessage.h b/logd/RecordedLogMessage.h
deleted file mode 100644
index f18c422..0000000
--- a/logd/RecordedLogMessage.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <inttypes.h>
-
-#include <log/log_time.h>
-
-struct __attribute__((packed)) RecordedLogMessage {
- uint32_t uid;
- uint32_t pid;
- uint32_t tid;
- log_time realtime;
- uint16_t msg_len;
- uint8_t log_id;
-};
diff --git a/logd/RecordingLogBuffer.cpp b/logd/RecordingLogBuffer.cpp
deleted file mode 100644
index f5991f3..0000000
--- a/logd/RecordingLogBuffer.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2020 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 "RecordingLogBuffer.h"
-
-#include <android-base/file.h>
-
-static void WriteLogMessage(int fd, const RecordedLogMessage& meta, const std::string& msg) {
- android::base::WriteFully(fd, &meta, sizeof(meta));
- android::base::WriteFully(fd, msg.c_str(), meta.msg_len);
-}
-
-void RecordingLogBuffer::RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
- pid_t tid, const char* msg, uint16_t len) {
- auto lock = std::lock_guard{lock_};
- if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
- len = LOGGER_ENTRY_MAX_PAYLOAD;
- }
-
- RecordedLogMessage recorded_log_message = {
- .uid = uid,
- .pid = static_cast<uint32_t>(pid),
- .tid = static_cast<uint32_t>(tid),
- .realtime = realtime,
- .msg_len = len,
- .log_id = static_cast<uint8_t>(log_id),
- };
-
- if (!fd_.ok()) {
- fd_.reset(open("/data/misc/logd/recorded-messages",
- O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0666));
- if (!fd_.ok()) {
- since_boot_messages_.emplace_back(recorded_log_message, std::string(msg, len));
- return;
- } else {
- for (const auto& [meta, msg] : since_boot_messages_) {
- WriteLogMessage(fd_.get(), meta, msg);
- }
- }
- }
-
- WriteLogMessage(fd_.get(), recorded_log_message, std::string(msg, len));
-}
-
-int RecordingLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len) {
- RecordLogMessage(log_id, realtime, uid, pid, tid, msg, len);
- return SimpleLogBuffer::Log(log_id, realtime, uid, pid, tid, msg, len);
-}
\ No newline at end of file
diff --git a/logd/RecordingLogBuffer.h b/logd/RecordingLogBuffer.h
deleted file mode 100644
index 49a0aba..0000000
--- a/logd/RecordingLogBuffer.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include "SimpleLogBuffer.h"
-
-#include <string>
-#include <tuple>
-#include <vector>
-
-#include <android-base/unique_fd.h>
-
-#include "RecordedLogMessage.h"
-
-class RecordingLogBuffer : public SimpleLogBuffer {
- public:
- RecordingLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
- : SimpleLogBuffer(reader_list, tags, stats) {}
-
- int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
- uint16_t len) override;
-
- private:
- void RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len);
-
- std::vector<std::pair<RecordedLogMessage, std::string>> since_boot_messages_;
- android::base::unique_fd fd_;
-};
diff --git a/logd/ReplayMessages.cpp b/logd/ReplayMessages.cpp
deleted file mode 100644
index 56509ec..0000000
--- a/logd/ReplayMessages.cpp
+++ /dev/null
@@ -1,472 +0,0 @@
-/*
- * Copyright (C) 2020 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 <inttypes.h>
-
-#include <chrono>
-#include <map>
-
-#include <android-base/file.h>
-#include <android-base/mapped_file.h>
-#include <android-base/parseint.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <android/log.h>
-#include <log/log_time.h>
-#include <log/logprint.h>
-
-#include "ChattyLogBuffer.h"
-#include "LogBuffer.h"
-#include "LogStatistics.h"
-#include "RecordedLogMessage.h"
-#include "SerializedLogBuffer.h"
-#include "SimpleLogBuffer.h"
-
-using android::base::MappedFile;
-using android::base::ParseInt;
-using android::base::ParseUint;
-using android::base::Split;
-
-char* android::uidToName(uid_t) {
- return nullptr;
-}
-
-static size_t GetPrivateDirty() {
- // Allocate once and hope that we don't need to reallocate >40000, to prevent heap fragmentation
- static std::string smaps(40000, '\0');
- android::base::ReadFileToString("/proc/self/smaps", &smaps);
-
- size_t result = 0;
- size_t base = 0;
- size_t found;
- while (true) {
- found = smaps.find("Private_Dirty:", base);
- if (found == smaps.npos) break;
-
- found += sizeof("Private_Dirty:");
-
- result += atoi(&smaps[found]);
-
- base = found + 1;
- }
-
- return result;
-}
-
-static AndroidLogFormat* GetLogFormat() {
- static AndroidLogFormat* format = [] {
- auto* format = android_log_format_new();
- android_log_setPrintFormat(format, android_log_formatFromString("threadtime"));
- android_log_setPrintFormat(format, android_log_formatFromString("uid"));
- return format;
- }();
- return format;
-}
-
-static void PrintMessage(struct log_msg* buf) {
- bool is_binary =
- buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
-
- AndroidLogEntry entry;
- int err;
- if (is_binary) {
- char binaryMsgBuf[1024];
- err = android_log_processBinaryLogBuffer(&buf->entry, &entry, nullptr, binaryMsgBuf,
- sizeof(binaryMsgBuf));
- } else {
- err = android_log_processLogBuffer(&buf->entry, &entry);
- }
- if (err < 0) {
- fprintf(stderr, "Error parsing log message\n");
- }
-
- android_log_printLogLine(GetLogFormat(), STDOUT_FILENO, &entry);
-}
-
-static log_time GetFirstTimeStamp(const MappedFile& recorded_messages) {
- if (sizeof(RecordedLogMessage) >= recorded_messages.size()) {
- fprintf(stderr, "At least one log message must be present in the input\n");
- exit(1);
- }
-
- auto* meta = reinterpret_cast<RecordedLogMessage*>(recorded_messages.data());
- return meta->realtime;
-}
-
-static LogMask BuffersToLogMask(const char* buffers) {
- if (buffers == nullptr || !strcmp(buffers, "all")) {
- return kLogMaskAll;
- }
- auto string_ids = Split(buffers, ",");
- LogMask log_mask = 0;
- for (const auto& string_id : string_ids) {
- int buffer_id;
- if (!ParseInt(string_id, &buffer_id, 0, 7)) {
- fprintf(stderr, "Could not parse buffer_id '%s'\n", string_id.c_str());
- exit(1);
- }
- log_mask |= 1 << buffer_id;
- }
- return log_mask;
-}
-
-class StdoutWriter : public LogWriter {
- public:
- StdoutWriter() : LogWriter(0, true) {}
- bool Write(const logger_entry& entry, const char* message) override {
- struct log_msg log_msg;
- log_msg.entry = entry;
- if (log_msg.entry.len > LOGGER_ENTRY_MAX_PAYLOAD) {
- fprintf(stderr, "payload too large %" PRIu16, log_msg.entry.len);
- exit(1);
- }
- memcpy(log_msg.msg(), message, log_msg.entry.len);
-
- PrintMessage(&log_msg);
-
- return true;
- }
-
- void Shutdown() override {
- fprintf(stderr, "LogWriter::Shutdown() called\n");
- exit(1);
- }
-
- std::string name() const override { return "stdout writer"; }
-};
-
-class Operation {
- public:
- virtual ~Operation() {}
-
- virtual void Begin() {}
- virtual void Log(const RecordedLogMessage& meta, const char* msg) = 0;
- virtual void End() {}
-};
-
-class PrintInteresting : public Operation {
- public:
- PrintInteresting(log_time first_log_timestamp)
- : stats_simple_{false, false, first_log_timestamp},
- stats_chatty_{false, false, first_log_timestamp},
- stats_serialized_{false, true, first_log_timestamp} {}
-
- void Begin() override {
- printf("message_count,simple_main_lines,simple_radio_lines,simple_events_lines,simple_"
- "system_lines,simple_crash_lines,simple_stats_lines,simple_security_lines,simple_"
- "kernel_lines,simple_main_size,simple_radio_size,simple_events_size,simple_system_"
- "size,simple_crash_size,simple_stats_size,simple_security_size,simple_kernel_size,"
- "simple_main_overhead,simple_radio_overhead,simple_events_overhead,simple_system_"
- "overhead,simple_crash_overhead,simple_stats_overhead,simple_security_overhead,"
- "simple_kernel_overhead,simple_main_range,simple_radio_range,simple_events_range,"
- "simple_system_range,simple_crash_range,simple_stats_range,simple_security_range,"
- "simple_kernel_range,chatty_main_lines,chatty_radio_lines,chatty_events_lines,"
- "chatty_system_lines,chatty_crash_lines,chatty_stats_lines,chatty_security_lines,"
- "chatty_"
- "kernel_lines,chatty_main_size,chatty_radio_size,chatty_events_size,chatty_system_"
- "size,chatty_crash_size,chatty_stats_size,chatty_security_size,chatty_kernel_size,"
- "chatty_main_overhead,chatty_radio_overhead,chatty_events_overhead,chatty_system_"
- "overhead,chatty_crash_overhead,chatty_stats_overhead,chatty_security_overhead,"
- "chatty_kernel_overhead,chatty_main_range,chatty_radio_range,chatty_events_range,"
- "chatty_system_range,chatty_crash_range,chatty_stats_range,chatty_security_range,"
- "chatty_kernel_range,serialized_main_lines,serialized_radio_lines,serialized_events_"
- "lines,serialized_"
- "system_lines,serialized_crash_lines,serialized_stats_lines,serialized_security_"
- "lines,serialized_"
- "kernel_lines,serialized_main_size,serialized_radio_size,serialized_events_size,"
- "serialized_system_"
- "size,serialized_crash_size,serialized_stats_size,serialized_security_size,"
- "serialized_kernel_size,"
- "serialized_main_overhead,serialized_radio_overhead,serialized_events_overhead,"
- "serialized_system_"
- "overhead,serialized_crash_overhead,serialized_stats_overhead,serialized_security_"
- "overhead,"
- "serialized_kernel_overhead,serialized_main_range,serialized_radio_range,serialized_"
- "events_range,"
- "serialized_system_range,serialized_crash_range,serialized_stats_range,serialized_"
- "security_range,"
- "serialized_kernel_range\n");
- }
-
- void Log(const RecordedLogMessage& meta, const char* msg) override {
- simple_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
- meta.pid, meta.tid, msg, meta.msg_len);
-
- chatty_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
- meta.pid, meta.tid, msg, meta.msg_len);
-
- serialized_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid,
- meta.pid, meta.tid, msg, meta.msg_len);
-
- if (num_message_ % 10000 == 0) {
- printf("%" PRIu64 ",%s,%s,%s\n", num_message_,
- stats_simple_.ReportInteresting().c_str(),
- stats_chatty_.ReportInteresting().c_str(),
- stats_serialized_.ReportInteresting().c_str());
- }
-
- num_message_++;
- }
-
- private:
- uint64_t num_message_ = 1;
-
- LogReaderList reader_list_;
- LogTags tags_;
- PruneList prune_list_;
-
- LogStatistics stats_simple_;
- SimpleLogBuffer simple_log_buffer_{&reader_list_, &tags_, &stats_simple_};
-
- LogStatistics stats_chatty_;
- ChattyLogBuffer chatty_log_buffer_{&reader_list_, &tags_, &prune_list_, &stats_chatty_};
-
- LogStatistics stats_serialized_;
- SerializedLogBuffer serialized_log_buffer_{&reader_list_, &tags_, &stats_serialized_};
-};
-
-class SingleBufferOperation : public Operation {
- public:
- SingleBufferOperation(log_time first_log_timestamp, const char* buffer) {
- if (!strcmp(buffer, "simple")) {
- stats_.reset(new LogStatistics{false, false, first_log_timestamp});
- log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, stats_.get()));
- } else if (!strcmp(buffer, "chatty")) {
- stats_.reset(new LogStatistics{false, false, first_log_timestamp});
- log_buffer_.reset(
- new ChattyLogBuffer(&reader_list_, &tags_, &prune_list_, stats_.get()));
- } else if (!strcmp(buffer, "serialized")) {
- stats_.reset(new LogStatistics{false, true, first_log_timestamp});
- log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, stats_.get()));
- } else {
- fprintf(stderr, "invalid log buffer type '%s'\n", buffer);
- abort();
- }
- }
-
- void Log(const RecordedLogMessage& meta, const char* msg) override {
- PreOperation();
- log_buffer_->Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, meta.pid,
- meta.tid, msg, meta.msg_len);
-
- Operation();
-
- num_message_++;
- }
-
- virtual void PreOperation() {}
- virtual void Operation() {}
-
- protected:
- uint64_t num_message_ = 1;
-
- LogReaderList reader_list_;
- LogTags tags_;
- PruneList prune_list_;
-
- std::unique_ptr<LogStatistics> stats_;
- std::unique_ptr<LogBuffer> log_buffer_;
-};
-
-class PrintMemory : public SingleBufferOperation {
- public:
- PrintMemory(log_time first_log_timestamp, const char* buffer)
- : SingleBufferOperation(first_log_timestamp, buffer) {}
-
- void Operation() override {
- if (num_message_ % 100000 == 0) {
- printf("%" PRIu64 ",%s\n", num_message_,
- std::to_string(GetPrivateDirty() - baseline_memory_).c_str());
- }
- }
-
- private:
- size_t baseline_memory_ = GetPrivateDirty();
-};
-
-class PrintLogs : public SingleBufferOperation {
- public:
- PrintLogs(log_time first_log_timestamp, const char* buffer, const char* buffers,
- const char* print_point)
- : SingleBufferOperation(first_log_timestamp, buffer) {
- mask_ = BuffersToLogMask(buffers);
- if (print_point != nullptr) {
- uint64_t result = 0;
- if (!ParseUint(print_point, &result)) {
- fprintf(stderr, "Could not parse print point '%s'\n", print_point);
- exit(1);
- }
- print_point_ = result;
- }
- }
-
- void Operation() override {
- if (print_point_ && num_message_ >= *print_point_) {
- End();
- exit(0);
- }
- }
-
- void End() override {
- std::unique_ptr<LogWriter> test_writer(new StdoutWriter());
- std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, mask_);
- log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr);
-
- auto stats_string = stats_->Format(0, 0, mask_);
- printf("%s\n", stats_string.c_str());
- }
-
- private:
- LogMask mask_ = kLogMaskAll;
- std::optional<uint64_t> print_point_;
-};
-
-class PrintLatency : public SingleBufferOperation {
- public:
- PrintLatency(log_time first_log_timestamp, const char* buffer)
- : SingleBufferOperation(first_log_timestamp, buffer) {}
-
- void PreOperation() override { operation_start_ = std::chrono::steady_clock::now(); }
-
- void Operation() override {
- auto end = std::chrono::steady_clock::now();
- auto duration = (end - operation_start_).count();
- durations_.emplace_back(duration);
- }
-
- void End() override {
- std::sort(durations_.begin(), durations_.end());
- auto q1 = durations_.size() / 4;
- auto q2 = durations_.size() / 2;
- auto q3 = 3 * durations_.size() / 4;
-
- auto p95 = 95 * durations_.size() / 100;
- auto p99 = 99 * durations_.size() / 100;
- auto p9999 = 9999 * durations_.size() / 10000;
-
- printf("q1: %lld q2: %lld q3: %lld p95: %lld p99: %lld p99.99: %lld max: %lld\n",
- durations_[q1], durations_[q2], durations_[q3], durations_[p95], durations_[p99],
- durations_[p9999], durations_.back());
- }
-
- private:
- std::chrono::steady_clock::time_point operation_start_;
- std::vector<long long> durations_;
-};
-
-class PrintAllLogs : public SingleBufferOperation {
- public:
- PrintAllLogs(log_time first_log_timestamp, const char* buffer, const char* buffers)
- : SingleBufferOperation(first_log_timestamp, buffer) {
- LogMask mask = BuffersToLogMask(buffers);
- auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
- std::unique_ptr<LogWriter> stdout_writer(new StdoutWriter());
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(stdout_writer),
- false, 0, mask, 0, {}, 1, {}));
- reader_list_.reader_threads().emplace_back(std::move(log_reader));
- }
-
- void Operation() override {
- // If the rate of reading logs is slower than the rate of incoming logs, then the reader
- // thread is disconnected to not overflow log buffers, therefore we artificially slow down
- // the incoming log rate.
- usleep(100);
- }
-};
-
-int main(int argc, char** argv) {
- if (argc < 3) {
- fprintf(stderr, "Usage: %s FILE OPERATION [BUFFER] [OPTIONS]\n", argv[0]);
- return 1;
- }
-
- if (strcmp(argv[2], "interesting") != 0 && argc < 4) {
- fprintf(stderr, "Operations other than 'interesting' require a BUFFER argument\n");
- return 1;
- }
-
- int recorded_messages_fd = open(argv[1], O_RDONLY);
- if (recorded_messages_fd == -1) {
- fprintf(stderr, "Couldn't open input file\n");
- return 1;
- }
- struct stat fd_stat;
- if (fstat(recorded_messages_fd, &fd_stat) != 0) {
- fprintf(stderr, "Couldn't fstat input file\n");
- return 1;
- }
- auto recorded_messages = MappedFile::FromFd(recorded_messages_fd, 0,
- static_cast<size_t>(fd_stat.st_size), PROT_READ);
- if (recorded_messages == nullptr) {
- fprintf(stderr, "Couldn't mmap input file\n");
- return 1;
- }
-
- // LogStatistics typically uses 'now()' to initialize its log range state, but this doesn't work
- // when replaying older logs, so we instead give it the timestamp from the first log.
- log_time first_log_timestamp = GetFirstTimeStamp(*recorded_messages);
-
- std::unique_ptr<Operation> operation;
- if (!strcmp(argv[2], "interesting")) {
- operation.reset(new PrintInteresting(first_log_timestamp));
- } else if (!strcmp(argv[2], "memory_usage")) {
- operation.reset(new PrintMemory(first_log_timestamp, argv[3]));
- } else if (!strcmp(argv[2], "latency")) {
- operation.reset(new PrintLatency(first_log_timestamp, argv[3]));
- } else if (!strcmp(argv[2], "print_logs")) {
- operation.reset(new PrintLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr,
- argc > 5 ? argv[5] : nullptr));
- } else if (!strcmp(argv[2], "print_all_logs")) {
- operation.reset(
- new PrintAllLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr));
- } else if (!strcmp(argv[2], "nothing")) {
- operation.reset(new SingleBufferOperation(first_log_timestamp, argv[3]));
- } else {
- fprintf(stderr, "unknown operation '%s'\n", argv[2]);
- return 1;
- }
-
- // LogBuffer::Log() won't log without this on host.
- __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE);
- // But we still want to suppress messages <= error to not interrupt the rest of the output.
- __android_log_set_logger([](const struct __android_log_message* log_message) {
- if (log_message->priority < ANDROID_LOG_ERROR) {
- return;
- }
- __android_log_stderr_logger(log_message);
- });
-
- operation->Begin();
-
- uint64_t read_position = 0;
- while (read_position + sizeof(RecordedLogMessage) < recorded_messages->size()) {
- auto* meta =
- reinterpret_cast<RecordedLogMessage*>(recorded_messages->data() + read_position);
- if (read_position + sizeof(RecordedLogMessage) + meta->msg_len >=
- recorded_messages->size()) {
- break;
- }
- char* msg = recorded_messages->data() + read_position + sizeof(RecordedLogMessage);
- read_position += sizeof(RecordedLogMessage) + meta->msg_len;
-
- operation->Log(*meta, msg);
- }
-
- operation->End();
-
- return 0;
-}
diff --git a/logd/SerializedData.h b/logd/SerializedData.h
deleted file mode 100644
index d3d1e18..0000000
--- a/logd/SerializedData.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-#include <algorithm>
-#include <memory>
-
-// This class is used instead of std::string or std::vector because their clear(), erase(), etc
-// functions don't actually deallocate. shrink_to_fit() does deallocate but is not guaranteed to
-// work and swapping with an empty string/vector is clunky.
-class SerializedData {
- public:
- SerializedData() {}
- SerializedData(size_t size) : data_(new uint8_t[size]), size_(size) {}
-
- void Resize(size_t new_size) {
- if (size_ == 0) {
- data_.reset(new uint8_t[new_size]);
- size_ = new_size;
- } else if (new_size == 0) {
- data_.reset();
- size_ = 0;
- } else if (new_size != size_) {
- std::unique_ptr<uint8_t[]> new_data(new uint8_t[new_size]);
- size_t copy_size = std::min(size_, new_size);
- memcpy(new_data.get(), data_.get(), copy_size);
- data_.swap(new_data);
- size_ = new_size;
- }
- }
-
- uint8_t* data() { return data_.get(); }
- const uint8_t* data() const { return data_.get(); }
- size_t size() const { return size_; }
-
- private:
- std::unique_ptr<uint8_t[]> data_;
- size_t size_ = 0;
-};
\ No newline at end of file
diff --git a/logd/SerializedFlushToState.cpp b/logd/SerializedFlushToState.cpp
deleted file mode 100644
index b02ccc3..0000000
--- a/logd/SerializedFlushToState.cpp
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2020 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 "SerializedFlushToState.h"
-
-#include <android-base/logging.h>
-
-SerializedFlushToState::SerializedFlushToState(uint64_t start, LogMask log_mask)
- : FlushToState(start, log_mask) {
- log_id_for_each(i) {
- if (((1 << i) & log_mask) == 0) {
- continue;
- }
- logs_needed_from_next_position_[i] = true;
- }
-}
-
-SerializedFlushToState::~SerializedFlushToState() {
- log_id_for_each(i) {
- if (log_positions_[i]) {
- log_positions_[i]->buffer_it->DecReaderRefCount();
- }
- }
-}
-
-void SerializedFlushToState::CreateLogPosition(log_id_t log_id) {
- CHECK(!logs_[log_id].empty());
- LogPosition log_position;
- auto it = logs_[log_id].begin();
- while (it != logs_[log_id].end() && start() > it->highest_sequence_number()) {
- ++it;
- }
- if (it == logs_[log_id].end()) {
- --it;
- }
- it->IncReaderRefCount();
- log_position.buffer_it = it;
-
- // Find the offset of the first log with sequence number >= start().
- int read_offset = 0;
- while (read_offset < it->write_offset()) {
- const auto* entry = it->log_entry(read_offset);
- if (entry->sequence() >= start()) {
- break;
- }
- read_offset += entry->total_len();
- }
- log_position.read_offset = read_offset;
-
- log_positions_[log_id].emplace(log_position);
-}
-
-void SerializedFlushToState::AddMinHeapEntry(log_id_t log_id) {
- auto& buffer_it = log_positions_[log_id]->buffer_it;
- auto read_offset = log_positions_[log_id]->read_offset;
-
- // If there is another log to read in this buffer, add it to the min heap.
- if (read_offset < buffer_it->write_offset()) {
- auto* entry = buffer_it->log_entry(read_offset);
- min_heap_.emplace(log_id, entry);
- } else if (read_offset == buffer_it->write_offset()) {
- // If there are no more logs to read in this buffer and it's the last buffer, then
- // set logs_needed_from_next_position_ to wait until more logs get logged.
- if (buffer_it == std::prev(logs_[log_id].end())) {
- logs_needed_from_next_position_[log_id] = true;
- } else {
- // Otherwise, if there is another buffer piece, move to that and do the same check.
- buffer_it->DecReaderRefCount();
- ++buffer_it;
- buffer_it->IncReaderRefCount();
- log_positions_[log_id]->read_offset = 0;
- if (buffer_it->write_offset() == 0) {
- logs_needed_from_next_position_[log_id] = true;
- } else {
- auto* entry = buffer_it->log_entry(0);
- min_heap_.emplace(log_id, entry);
- }
- }
- } else {
- // read_offset > buffer_it->write_offset() should never happen.
- CHECK(false);
- }
-}
-
-void SerializedFlushToState::CheckForNewLogs() {
- log_id_for_each(i) {
- if (!logs_needed_from_next_position_[i]) {
- continue;
- }
- if (!log_positions_[i]) {
- if (logs_[i].empty()) {
- continue;
- }
- CreateLogPosition(i);
- }
- logs_needed_from_next_position_[i] = false;
- // If it wasn't possible to insert, logs_needed_from_next_position will be set back to true.
- AddMinHeapEntry(i);
- }
-}
-
-MinHeapElement SerializedFlushToState::PopNextUnreadLog() {
- auto top = min_heap_.top();
- min_heap_.pop();
-
- auto* entry = top.entry;
- auto log_id = top.log_id;
-
- log_positions_[log_id]->read_offset += entry->total_len();
-
- logs_needed_from_next_position_[log_id] = true;
-
- return top;
-}
-
-void SerializedFlushToState::Prune(log_id_t log_id,
- const std::list<SerializedLogChunk>::iterator& buffer_it) {
- // If we don't have a position for this log or if we're not referencing buffer_it, ignore.
- if (!log_positions_[log_id].has_value() || log_positions_[log_id]->buffer_it != buffer_it) {
- return;
- }
-
- // // Decrease the ref count since we're deleting our reference.
- buffer_it->DecReaderRefCount();
-
- // Delete in the reference.
- log_positions_[log_id].reset();
-
- // Remove the MinHeapElement referencing log_id, if it exists, but retain the others.
- std::vector<MinHeapElement> old_elements;
- while (!min_heap_.empty()) {
- auto& element = min_heap_.top();
- if (element.log_id != log_id) {
- old_elements.emplace_back(element);
- }
- min_heap_.pop();
- }
- for (auto&& element : old_elements) {
- min_heap_.emplace(element);
- }
-
- // Finally set logs_needed_from_next_position_, so CheckForNewLogs() will re-create the
- // log_position_ object during the next read.
- logs_needed_from_next_position_[log_id] = true;
-}
diff --git a/logd/SerializedFlushToState.h b/logd/SerializedFlushToState.h
deleted file mode 100644
index 0b20822..0000000
--- a/logd/SerializedFlushToState.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <bitset>
-#include <list>
-#include <queue>
-
-#include "LogBuffer.h"
-#include "SerializedLogChunk.h"
-#include "SerializedLogEntry.h"
-
-struct LogPosition {
- std::list<SerializedLogChunk>::iterator buffer_it;
- int read_offset;
-};
-
-struct MinHeapElement {
- MinHeapElement(log_id_t log_id, const SerializedLogEntry* entry)
- : log_id(log_id), entry(entry) {}
- log_id_t log_id;
- const SerializedLogEntry* entry;
- // The change of comparison operators is intentional, std::priority_queue uses operator<() to
- // compare but creates a max heap. Since we want a min heap, we return the opposite result.
- bool operator<(const MinHeapElement& rhs) const {
- return entry->sequence() > rhs.entry->sequence();
- }
-};
-
-// This class tracks the specific point where a FlushTo client has read through the logs. It
-// directly references the std::list<> iterators from the parent SerializedLogBuffer and the offset
-// into each log chunk where it has last read. All interactions with this class, except for its
-// construction, must be done with SerializedLogBuffer::lock_ held. No log chunks that it
-// references may be pruned, which is handled by ensuring prune does not touch any log chunk with
-// highest sequence number greater or equal to start().
-class SerializedFlushToState : public FlushToState {
- public:
- // Initializes this state object. For each log buffer set in log_mask, this sets
- // logs_needed_from_next_position_.
- SerializedFlushToState(uint64_t start, LogMask log_mask);
-
- // Decrease the reference of all referenced logs. This happens when a reader is disconnected.
- ~SerializedFlushToState() override;
-
- // We can't hold SerializedLogBuffer::lock_ in the constructor, so we must initialize logs here.
- void InitializeLogs(std::list<SerializedLogChunk>* logs) {
- if (logs_ == nullptr) logs_ = logs;
- }
-
- bool HasUnreadLogs() {
- CheckForNewLogs();
- return !min_heap_.empty();
- }
-
- // Pops the next unread log from the min heap and sets logs_needed_from_next_position_ to
- // indicate that we're waiting for more logs from the associated log buffer.
- MinHeapElement PopNextUnreadLog();
-
- // If the parent log buffer prunes logs, the reference that this class contains may become
- // invalid, so this must be called first to drop the reference to buffer_it, if any.
- void Prune(log_id_t log_id, const std::list<SerializedLogChunk>::iterator& buffer_it);
-
- private:
- // If there is a log in the serialized log buffer for `log_id` at the read_offset, add it to the
- // min heap for reading, otherwise set logs_needed_from_next_position_ to indicate that we're
- // waiting for the next log.
- void AddMinHeapEntry(log_id_t log_id);
-
- // Create a LogPosition object for the given log_id by searching through the log chunks for the
- // first chunk and then first log entry within that chunk that is greater or equal to start().
- void CreateLogPosition(log_id_t log_id);
-
- // Checks to see if any log buffers set in logs_needed_from_next_position_ have new logs and
- // calls AddMinHeapEntry() if so.
- void CheckForNewLogs();
-
- std::list<SerializedLogChunk>* logs_ = nullptr;
- // An optional structure that contains an iterator to the serialized log buffer and offset into
- // it that this logger should handle next.
- std::optional<LogPosition> log_positions_[LOG_ID_MAX];
- // A bit for each log that is set if a given log_id has no logs or if this client has read all
- // of its logs. In order words: `logs_[i].empty() || (buffer_it == std::prev(logs_.end) &&
- // next_log_position == logs_write_position_)`. These will be re-checked in each
- // loop in case new logs came in.
- std::bitset<LOG_ID_MAX> logs_needed_from_next_position_ = {};
- // A min heap that has up to one entry per log buffer, sorted by sequence number, of the next
- // element that this reader should read.
- std::priority_queue<MinHeapElement> min_heap_;
-};
diff --git a/logd/SerializedFlushToStateTest.cpp b/logd/SerializedFlushToStateTest.cpp
deleted file mode 100644
index f4515c8..0000000
--- a/logd/SerializedFlushToStateTest.cpp
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright (C) 2020 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 "SerializedFlushToState.h"
-
-#include <map>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <gtest/gtest.h>
-
-using android::base::Join;
-using android::base::StringPrintf;
-
-constexpr size_t kChunkSize = 3 * 4096;
-
-class SerializedFlushToStateTest : public testing::Test {
- protected:
- void SetUp() override {
- // This test spams many unneeded INFO logs, so we suppress them.
- old_log_severity_ = android::base::SetMinimumLogSeverity(android::base::WARNING);
- }
- void TearDown() override { android::base::SetMinimumLogSeverity(old_log_severity_); }
-
- std::string TestReport(const std::vector<uint64_t>& expected,
- const std::vector<uint64_t>& read) {
- auto sequence_to_log_id = [&](uint64_t sequence) -> int {
- for (const auto& [log_id, sequences] : sequence_numbers_per_buffer_) {
- if (std::find(sequences.begin(), sequences.end(), sequence) != sequences.end()) {
- return log_id;
- }
- }
- return -1;
- };
-
- std::map<int, std::vector<uint64_t>> missing_sequences;
- std::vector<uint64_t> missing_expected;
- std::set_difference(expected.begin(), expected.end(), read.begin(), read.end(),
- std::back_inserter(missing_expected));
- for (uint64_t sequence : missing_expected) {
- int log_id = sequence_to_log_id(sequence);
- missing_sequences[log_id].emplace_back(sequence);
- }
-
- std::map<int, std::vector<uint64_t>> extra_sequences;
- std::vector<uint64_t> extra_read;
- std::set_difference(read.begin(), read.end(), expected.begin(), expected.end(),
- std::back_inserter(extra_read));
- for (uint64_t sequence : extra_read) {
- int log_id = sequence_to_log_id(sequence);
- extra_sequences[log_id].emplace_back(sequence);
- }
-
- std::vector<std::string> errors;
- for (const auto& [log_id, sequences] : missing_sequences) {
- errors.emplace_back(
- StringPrintf("Log id %d missing %zu sequences", log_id, sequences.size()));
- }
-
- for (const auto& [log_id, sequences] : extra_sequences) {
- errors.emplace_back(
- StringPrintf("Log id %d has extra %zu sequences", log_id, sequences.size()));
- }
-
- return Join(errors, ", ");
- }
-
- // Read sequence numbers in order from SerializedFlushToState for every mask combination and all
- // sequence numbers from 0 through the highest logged sequence number + 1.
- // This assumes that all of the logs have already been written.
- void TestAllReading() {
- uint64_t max_sequence = sequence_ + 1;
- uint32_t max_mask = (1 << LOG_ID_MAX) - 1;
- for (uint64_t sequence = 0; sequence < max_sequence; ++sequence) {
- for (uint32_t mask = 0; mask < max_mask; ++mask) {
- auto state = SerializedFlushToState{sequence, mask};
- state.InitializeLogs(log_chunks_);
- TestReading(sequence, mask, state);
- }
- }
- }
-
- // Similar to TestAllReading() except that it doesn't assume any logs are in the buffer, instead
- // it calls write_logs() in a loop for sequence/mask combination. It clears log_chunks_ and
- // sequence_numbers_per_buffer_ between calls, such that only the sequence numbers written in
- // the previous call to write_logs() are expected.
- void TestAllReadingWithFutureMessages(const std::function<bool(int)>& write_logs) {
- uint64_t max_sequence = sequence_ + 1;
- uint32_t max_mask = (1 << LOG_ID_MAX) - 1;
- for (uint64_t sequence = 1; sequence < max_sequence; ++sequence) {
- for (uint32_t mask = 1; mask < max_mask; ++mask) {
- log_id_for_each(i) { log_chunks_[i].clear(); }
- auto state = SerializedFlushToState{sequence, mask};
- state.InitializeLogs(log_chunks_);
- int loop_count = 0;
- while (write_logs(loop_count++)) {
- TestReading(sequence, mask, state);
- sequence_numbers_per_buffer_.clear();
- }
- }
- }
- }
-
- void TestReading(uint64_t start, LogMask log_mask, SerializedFlushToState& state) {
- std::vector<uint64_t> expected_sequence;
- log_id_for_each(i) {
- if (((1 << i) & log_mask) == 0) {
- continue;
- }
- for (const auto& sequence : sequence_numbers_per_buffer_[i]) {
- if (sequence >= start) {
- expected_sequence.emplace_back(sequence);
- }
- }
- }
- std::sort(expected_sequence.begin(), expected_sequence.end());
-
- std::vector<uint64_t> read_sequence;
-
- while (state.HasUnreadLogs()) {
- auto top = state.PopNextUnreadLog();
- read_sequence.emplace_back(top.entry->sequence());
- }
-
- EXPECT_TRUE(std::is_sorted(read_sequence.begin(), read_sequence.end()));
-
- EXPECT_EQ(expected_sequence.size(), read_sequence.size());
-
- EXPECT_EQ(expected_sequence, read_sequence)
- << "start: " << start << " log_mask: " << log_mask << " "
- << TestReport(expected_sequence, read_sequence);
- }
-
- // Add a chunk with the given messages to the a given log buffer. Keep track of the sequence
- // numbers for future validation. Optionally mark the block as having finished writing.
- void AddChunkWithMessages(bool finish_writing, int buffer,
- const std::vector<std::string>& messages) {
- auto chunk = SerializedLogChunk{kChunkSize};
- for (const auto& message : messages) {
- auto sequence = sequence_++;
- sequence_numbers_per_buffer_[buffer].emplace_back(sequence);
- ASSERT_TRUE(chunk.CanLog(message.size() + 1));
- chunk.Log(sequence, log_time(), 0, 1, 1, message.c_str(), message.size() + 1);
- }
- if (finish_writing) {
- chunk.FinishWriting();
- }
- log_chunks_[buffer].emplace_back(std::move(chunk));
- }
-
- android::base::LogSeverity old_log_severity_;
- std::map<int, std::vector<uint64_t>> sequence_numbers_per_buffer_;
- std::list<SerializedLogChunk> log_chunks_[LOG_ID_MAX];
- uint64_t sequence_ = 1;
-};
-
-// 0: multiple chunks, with variable number of entries, with/without finishing writing
-// 1: 1 chunk with 1 log and finished writing
-// 2: 1 chunk with 1 log and not finished writing
-// 3: 1 chunk with 0 logs and not finished writing
-// 4: 1 chunk with 0 logs and finished writing (impossible, but SerializedFlushToState handles it)
-// 5-7: 0 chunks
-TEST_F(SerializedFlushToStateTest, smoke) {
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"3rd"});
- AddChunkWithMessages(false, 0, {"4th"});
- AddChunkWithMessages(true, 0, {"4th", "5th", "more", "even", "more", "go", "here"});
- AddChunkWithMessages(false, 2, {"6th"});
- AddChunkWithMessages(true, 0, {"7th"});
- AddChunkWithMessages(false, 3, {});
- AddChunkWithMessages(true, 4, {});
-
- TestAllReading();
-}
-
-TEST_F(SerializedFlushToStateTest, random) {
- srand(1);
- for (int count = 0; count < 20; ++count) {
- unsigned int num_messages = 1 + rand() % 15;
- auto messages = std::vector<std::string>{num_messages, "same message"};
-
- bool compress = rand() % 2;
- int buf = rand() % LOG_ID_MAX;
-
- AddChunkWithMessages(compress, buf, messages);
- }
-
- TestAllReading();
-}
-
-// Same start as smoke, but we selectively write logs to the buffers and ensure they're read.
-TEST_F(SerializedFlushToStateTest, future_writes) {
- auto write_logs = [&](int loop_count) {
- switch (loop_count) {
- case 0:
- // Initial writes.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"3rd"});
- AddChunkWithMessages(false, 0, {"4th"});
- AddChunkWithMessages(true, 0, {"4th", "5th", "more", "even", "more", "go", "here"});
- AddChunkWithMessages(false, 2, {"6th"});
- AddChunkWithMessages(true, 0, {"7th"});
- AddChunkWithMessages(false, 3, {});
- AddChunkWithMessages(true, 4, {});
- break;
- case 1:
- // Smoke test, add a simple chunk.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- break;
- case 2:
- // Add chunks to all but one of the logs.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"1st", "2nd"});
- AddChunkWithMessages(true, 2, {"1st", "2nd"});
- AddChunkWithMessages(true, 3, {"1st", "2nd"});
- AddChunkWithMessages(true, 4, {"1st", "2nd"});
- AddChunkWithMessages(true, 5, {"1st", "2nd"});
- AddChunkWithMessages(true, 6, {"1st", "2nd"});
- break;
- case 3:
- // Finally add chunks to all logs.
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 1, {"1st", "2nd"});
- AddChunkWithMessages(true, 2, {"1st", "2nd"});
- AddChunkWithMessages(true, 3, {"1st", "2nd"});
- AddChunkWithMessages(true, 4, {"1st", "2nd"});
- AddChunkWithMessages(true, 5, {"1st", "2nd"});
- AddChunkWithMessages(true, 6, {"1st", "2nd"});
- AddChunkWithMessages(true, 7, {"1st", "2nd"});
- break;
- default:
- return false;
- }
- return true;
- };
-
- TestAllReadingWithFutureMessages(write_logs);
-}
-
-TEST_F(SerializedFlushToStateTest, no_dangling_references) {
- AddChunkWithMessages(true, 0, {"1st", "2nd"});
- AddChunkWithMessages(true, 0, {"3rd", "4th"});
-
- auto state = SerializedFlushToState{1, kLogMaskAll};
- state.InitializeLogs(log_chunks_);
-
- ASSERT_EQ(log_chunks_[0].size(), 2U);
- auto first_chunk = log_chunks_[0].begin();
- auto second_chunk = std::next(first_chunk);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto first_log = state.PopNextUnreadLog();
- EXPECT_STREQ(first_log.entry->msg(), "1st");
- EXPECT_EQ(first_chunk->reader_ref_count(), 1U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 0U);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto second_log = state.PopNextUnreadLog();
- EXPECT_STREQ(second_log.entry->msg(), "2nd");
- EXPECT_EQ(first_chunk->reader_ref_count(), 1U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 0U);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto third_log = state.PopNextUnreadLog();
- EXPECT_STREQ(third_log.entry->msg(), "3rd");
- EXPECT_EQ(first_chunk->reader_ref_count(), 0U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 1U);
-
- ASSERT_TRUE(state.HasUnreadLogs());
- auto fourth_log = state.PopNextUnreadLog();
- EXPECT_STREQ(fourth_log.entry->msg(), "4th");
- EXPECT_EQ(first_chunk->reader_ref_count(), 0U);
- EXPECT_EQ(second_chunk->reader_ref_count(), 1U);
-
- EXPECT_FALSE(state.HasUnreadLogs());
-}
\ No newline at end of file
diff --git a/logd/SerializedLogBuffer.cpp b/logd/SerializedLogBuffer.cpp
deleted file mode 100644
index 5012d3d..0000000
--- a/logd/SerializedLogBuffer.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2020 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 "SerializedLogBuffer.h"
-
-#include <sys/prctl.h>
-
-#include <limits>
-
-#include <android-base/logging.h>
-#include <android-base/scopeguard.h>
-
-#include "LogSize.h"
-#include "LogStatistics.h"
-#include "SerializedFlushToState.h"
-
-SerializedLogBuffer::SerializedLogBuffer(LogReaderList* reader_list, LogTags* tags,
- LogStatistics* stats)
- : reader_list_(reader_list), tags_(tags), stats_(stats) {
- Init();
-}
-
-void SerializedLogBuffer::Init() {
- log_id_for_each(i) {
- if (!SetSize(i, GetBufferSizeFromProperties(i))) {
- SetSize(i, kLogBufferMinSize);
- }
- }
-
- // Release any sleeping reader threads to dump their current content.
- auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- reader_thread->triggerReader_Locked();
- }
-}
-
-bool SerializedLogBuffer::ShouldLog(log_id_t log_id, const char* msg, uint16_t len) {
- if (log_id == LOG_ID_SECURITY) {
- return true;
- }
-
- int prio = ANDROID_LOG_INFO;
- const char* tag = nullptr;
- size_t tag_len = 0;
- if (IsBinary(log_id)) {
- int32_t tag_int = MsgToTag(msg, len);
- tag = tags_->tagToName(tag_int);
- if (tag) {
- tag_len = strlen(tag);
- }
- } else {
- prio = *msg;
- tag = msg + 1;
- tag_len = strnlen(tag, len - 1);
- }
- return __android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE);
-}
-
-int SerializedLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len) {
- if (log_id >= LOG_ID_MAX || len == 0) {
- return -EINVAL;
- }
-
- if (len > LOGGER_ENTRY_MAX_PAYLOAD) {
- len = LOGGER_ENTRY_MAX_PAYLOAD;
- }
-
- if (!ShouldLog(log_id, msg, len)) {
- stats_->AddTotal(log_id, len);
- return -EACCES;
- }
-
- auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
-
- auto lock = std::lock_guard{lock_};
-
- if (logs_[log_id].empty()) {
- logs_[log_id].push_back(SerializedLogChunk(max_size_[log_id] / 4));
- }
-
- auto total_len = sizeof(SerializedLogEntry) + len;
- if (!logs_[log_id].back().CanLog(total_len)) {
- logs_[log_id].back().FinishWriting();
- logs_[log_id].push_back(SerializedLogChunk(max_size_[log_id] / 4));
- }
-
- auto entry = logs_[log_id].back().Log(sequence, realtime, uid, pid, tid, msg, len);
- stats_->Add(entry->ToLogStatisticsElement(log_id));
-
- MaybePrune(log_id);
-
- reader_list_->NotifyNewLog(1 << log_id);
- return len;
-}
-
-void SerializedLogBuffer::MaybePrune(log_id_t log_id) {
- size_t total_size = GetSizeUsed(log_id);
- size_t after_size = total_size;
- if (total_size > max_size_[log_id]) {
- Prune(log_id, total_size - max_size_[log_id], 0);
- after_size = GetSizeUsed(log_id);
- LOG(INFO) << "Pruned Logs from log_id: " << log_id << ", previous size: " << total_size
- << " after size: " << after_size;
- }
-
- stats_->set_overhead(log_id, after_size);
-}
-
-void SerializedLogBuffer::RemoveChunkFromStats(log_id_t log_id, SerializedLogChunk& chunk) {
- chunk.IncReaderRefCount();
- int read_offset = 0;
- while (read_offset < chunk.write_offset()) {
- auto* entry = chunk.log_entry(read_offset);
- stats_->Subtract(entry->ToLogStatisticsElement(log_id));
- read_offset += entry->total_len();
- }
- chunk.DecReaderRefCount();
-}
-
-void SerializedLogBuffer::NotifyReadersOfPrune(
- log_id_t log_id, const std::list<SerializedLogChunk>::iterator& chunk) {
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- auto& state = reinterpret_cast<SerializedFlushToState&>(reader_thread->flush_to_state());
- state.Prune(log_id, chunk);
- }
-}
-
-void SerializedLogBuffer::Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) {
- auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
-
- auto& log_buffer = logs_[log_id];
- auto it = log_buffer.begin();
- while (it != log_buffer.end()) {
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- if (!reader_thread->IsWatching(log_id)) {
- continue;
- }
-
- if (reader_thread->deadline().time_since_epoch().count() != 0) {
- // Always wake up wrapped readers when pruning. 'Wrapped' readers are an
- // optimization that allows the reader to wait until logs starting at a specified
- // time stamp are about to be pruned. This is error-prone however, since if that
- // timestamp is about to be pruned, the reader is not likely to read the messages
- // fast enough to not back-up logd. Instead, we can achieve an nearly-as-efficient
- // but not error-prune batching effect by waking the reader whenever any chunk is
- // about to be pruned.
- reader_thread->triggerReader_Locked();
- }
-
- // Some readers may be still reading from this log chunk, log a warning that they are
- // about to lose logs.
- // TODO: We should forcefully disconnect the reader instead, such that the reader itself
- // has an indication that they've lost logs.
- if (reader_thread->start() <= it->highest_sequence_number()) {
- LOG(WARNING) << "Skipping entries from slow reader, " << reader_thread->name()
- << ", from LogBuffer::Prune()";
- }
- }
-
- // Increment ahead of time since we're going to erase this iterator from the list.
- auto it_to_prune = it++;
-
- // Readers may have a reference to the chunk to track their last read log_position.
- // Notify them to delete the reference.
- NotifyReadersOfPrune(log_id, it_to_prune);
-
- if (uid != 0) {
- // Reorder the log buffer to remove logs from the given UID. If there are no logs left
- // in the buffer after the removal, delete it.
- if (it_to_prune->ClearUidLogs(uid, log_id, stats_)) {
- log_buffer.erase(it_to_prune);
- }
- } else {
- size_t buffer_size = it_to_prune->PruneSize();
- RemoveChunkFromStats(log_id, *it_to_prune);
- log_buffer.erase(it_to_prune);
- if (buffer_size >= bytes_to_free) {
- return;
- }
- bytes_to_free -= buffer_size;
- }
- }
-}
-
-std::unique_ptr<FlushToState> SerializedLogBuffer::CreateFlushToState(uint64_t start,
- LogMask log_mask) {
- return std::make_unique<SerializedFlushToState>(start, log_mask);
-}
-
-bool SerializedLogBuffer::FlushTo(
- LogWriter* writer, FlushToState& abstract_state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) {
- auto lock = std::unique_lock{lock_};
-
- auto& state = reinterpret_cast<SerializedFlushToState&>(abstract_state);
- state.InitializeLogs(logs_);
-
- while (state.HasUnreadLogs()) {
- MinHeapElement top = state.PopNextUnreadLog();
- auto* entry = top.entry;
- auto log_id = top.log_id;
-
- if (entry->sequence() < state.start()) {
- continue;
- }
- state.set_start(entry->sequence());
-
- if (!writer->privileged() && entry->uid() != writer->uid()) {
- continue;
- }
-
- if (filter) {
- auto ret = filter(log_id, entry->pid(), entry->sequence(), entry->realtime());
- if (ret == FilterResult::kSkip) {
- continue;
- }
- if (ret == FilterResult::kStop) {
- break;
- }
- }
-
- // We copy the log entry such that we can flush it without the lock. We never block pruning
- // waiting for this Flush() to complete.
- constexpr size_t kMaxEntrySize = sizeof(*entry) + LOGGER_ENTRY_MAX_PAYLOAD + 1;
- unsigned char entry_copy[kMaxEntrySize] __attribute__((uninitialized));
- CHECK_LT(entry->msg_len(), LOGGER_ENTRY_MAX_PAYLOAD + 1);
- memcpy(entry_copy, entry, sizeof(*entry) + entry->msg_len());
- lock.unlock();
-
- if (!reinterpret_cast<SerializedLogEntry*>(entry_copy)->Flush(writer, log_id)) {
- return false;
- }
-
- lock.lock();
- }
-
- state.set_start(state.start() + 1);
- return true;
-}
-
-bool SerializedLogBuffer::Clear(log_id_t id, uid_t uid) {
- auto lock = std::lock_guard{lock_};
- Prune(id, ULONG_MAX, uid);
-
- // Clearing SerializedLogBuffer never waits for readers and therefore is always successful.
- return true;
-}
-
-size_t SerializedLogBuffer::GetSizeUsed(log_id_t id) {
- size_t total_size = 0;
- for (const auto& chunk : logs_[id]) {
- total_size += chunk.PruneSize();
- }
- return total_size;
-}
-
-size_t SerializedLogBuffer::GetSize(log_id_t id) {
- auto lock = std::lock_guard{lock_};
- return max_size_[id];
-}
-
-// New SerializedLogChunk objects will be allocated according to the new size, but older one are
-// unchanged. MaybePrune() is called on the log buffer to reduce it to an appropriate size if the
-// new size is lower.
-bool SerializedLogBuffer::SetSize(log_id_t id, size_t size) {
- // Reasonable limits ...
- if (!IsValidBufferSize(size)) {
- return false;
- }
-
- auto lock = std::lock_guard{lock_};
- max_size_[id] = size;
-
- MaybePrune(id);
-
- return true;
-}
diff --git a/logd/SerializedLogBuffer.h b/logd/SerializedLogBuffer.h
deleted file mode 100644
index 294cfe6..0000000
--- a/logd/SerializedLogBuffer.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <atomic>
-#include <bitset>
-#include <list>
-#include <mutex>
-#include <queue>
-#include <thread>
-#include <vector>
-
-#include <android-base/thread_annotations.h>
-
-#include "LogBuffer.h"
-#include "LogReaderList.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "SerializedLogChunk.h"
-#include "SerializedLogEntry.h"
-#include "rwlock.h"
-
-class SerializedLogBuffer final : public LogBuffer {
- public:
- SerializedLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats);
- void Init() override;
-
- int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
- uint16_t len) override;
- std::unique_ptr<FlushToState> CreateFlushToState(uint64_t start, LogMask log_mask) override;
- bool FlushTo(LogWriter* writer, FlushToState& state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) override;
-
- bool Clear(log_id_t id, uid_t uid) override;
- size_t GetSize(log_id_t id) override;
- bool SetSize(log_id_t id, size_t size) override;
-
- uint64_t sequence() const override { return sequence_.load(std::memory_order_relaxed); }
-
- private:
- bool ShouldLog(log_id_t log_id, const char* msg, uint16_t len);
- void MaybePrune(log_id_t log_id) REQUIRES(lock_);
- void Prune(log_id_t log_id, size_t bytes_to_free, uid_t uid) REQUIRES(lock_);
- void NotifyReadersOfPrune(log_id_t log_id, const std::list<SerializedLogChunk>::iterator& chunk)
- REQUIRES(reader_list_->reader_threads_lock());
- void RemoveChunkFromStats(log_id_t log_id, SerializedLogChunk& chunk);
- size_t GetSizeUsed(log_id_t id) REQUIRES(lock_);
-
- LogReaderList* reader_list_;
- LogTags* tags_;
- LogStatistics* stats_;
-
- size_t max_size_[LOG_ID_MAX] GUARDED_BY(lock_) = {};
- std::list<SerializedLogChunk> logs_[LOG_ID_MAX] GUARDED_BY(lock_);
- RwLock lock_;
-
- std::atomic<uint64_t> sequence_ = 1;
-};
diff --git a/logd/SerializedLogChunk.cpp b/logd/SerializedLogChunk.cpp
deleted file mode 100644
index de641d6..0000000
--- a/logd/SerializedLogChunk.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2020 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 "SerializedLogChunk.h"
-
-#include <android-base/logging.h>
-
-#include "CompressionEngine.h"
-
-SerializedLogChunk::~SerializedLogChunk() {
- CHECK_EQ(reader_ref_count_, 0U);
-}
-
-void SerializedLogChunk::Compress() {
- if (compressed_log_.size() == 0) {
- CompressionEngine::GetInstance().Compress(contents_, write_offset_, compressed_log_);
- LOG(INFO) << "Compressed Log, buffer max size: " << contents_.size()
- << " size used: " << write_offset_
- << " compressed size: " << compressed_log_.size();
- }
-}
-
-// TODO: Develop a better reference counting strategy to guard against the case where the writer is
-// much faster than the reader, and we needlessly compess / decompress the logs.
-void SerializedLogChunk::IncReaderRefCount() {
- if (++reader_ref_count_ != 1 || writer_active_) {
- return;
- }
- contents_.Resize(write_offset_);
- CompressionEngine::GetInstance().Decompress(compressed_log_, contents_);
-}
-
-void SerializedLogChunk::DecReaderRefCount() {
- CHECK_NE(reader_ref_count_, 0U);
- if (--reader_ref_count_ != 0) {
- return;
- }
- if (!writer_active_) {
- contents_.Resize(0);
- }
-}
-
-bool SerializedLogChunk::ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* stats) {
- CHECK_EQ(reader_ref_count_, 0U);
- if (write_offset_ == 0) {
- return true;
- }
-
- IncReaderRefCount();
-
- int read_offset = 0;
- int new_write_offset = 0;
- while (read_offset < write_offset_) {
- const auto* entry = log_entry(read_offset);
- if (entry->uid() == uid) {
- read_offset += entry->total_len();
- if (stats != nullptr) {
- stats->Subtract(entry->ToLogStatisticsElement(log_id));
- }
- continue;
- }
- size_t entry_total_len = entry->total_len();
- if (read_offset != new_write_offset) {
- memmove(contents_.data() + new_write_offset, contents_.data() + read_offset,
- entry_total_len);
- }
- read_offset += entry_total_len;
- new_write_offset += entry_total_len;
- }
-
- if (new_write_offset == 0) {
- DecReaderRefCount();
- return true;
- }
-
- // Clear the old compressed logs and set write_offset_ appropriately to compress the new
- // partially cleared log.
- if (new_write_offset != write_offset_) {
- compressed_log_.Resize(0);
- write_offset_ = new_write_offset;
- Compress();
- }
-
- DecReaderRefCount();
-
- return false;
-}
-
-bool SerializedLogChunk::CanLog(size_t len) {
- return write_offset_ + len <= contents_.size();
-}
-
-SerializedLogEntry* SerializedLogChunk::Log(uint64_t sequence, log_time realtime, uid_t uid,
- pid_t pid, pid_t tid, const char* msg, uint16_t len) {
- auto new_log_address = contents_.data() + write_offset_;
- auto* entry = new (new_log_address) SerializedLogEntry(uid, pid, tid, sequence, realtime, len);
- memcpy(entry->msg(), msg, len);
- write_offset_ += entry->total_len();
- highest_sequence_number_ = sequence;
- return entry;
-}
\ No newline at end of file
diff --git a/logd/SerializedLogChunk.h b/logd/SerializedLogChunk.h
deleted file mode 100644
index 0991eac..0000000
--- a/logd/SerializedLogChunk.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <sys/types.h>
-
-#include "LogWriter.h"
-#include "SerializedData.h"
-#include "SerializedLogEntry.h"
-
-class SerializedLogChunk {
- public:
- explicit SerializedLogChunk(size_t size) : contents_(size) {}
- SerializedLogChunk(SerializedLogChunk&& other) noexcept = default;
- ~SerializedLogChunk();
-
- void Compress();
- void IncReaderRefCount();
- void DecReaderRefCount();
-
- // Must have no readers referencing this. Return true if there are no logs left in this chunk.
- bool ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* stats);
-
- bool CanLog(size_t len);
- SerializedLogEntry* Log(uint64_t sequence, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len);
-
- // If this buffer has been compressed, we only consider its compressed size when accounting for
- // memory consumption for pruning. This is since the uncompressed log is only by used by
- // readers, and thus not a representation of how much these logs cost to keep in memory.
- size_t PruneSize() const {
- return sizeof(*this) + (compressed_log_.size() ?: contents_.size());
- }
-
- void FinishWriting() {
- writer_active_ = false;
- Compress();
- if (reader_ref_count_ == 0) {
- contents_.Resize(0);
- }
- }
-
- const SerializedLogEntry* log_entry(int offset) const {
- return reinterpret_cast<const SerializedLogEntry*>(data() + offset);
- }
- const uint8_t* data() const { return contents_.data(); }
- int write_offset() const { return write_offset_; }
- uint64_t highest_sequence_number() const { return highest_sequence_number_; }
-
- // Exposed for testing
- uint32_t reader_ref_count() const { return reader_ref_count_; }
-
- private:
- // The decompressed contents of this log buffer. Deallocated when the ref_count reaches 0 and
- // writer_active_ is false.
- SerializedData contents_;
- int write_offset_ = 0;
- uint32_t reader_ref_count_ = 0;
- bool writer_active_ = true;
- uint64_t highest_sequence_number_ = 1;
- SerializedData compressed_log_;
-};
diff --git a/logd/SerializedLogChunkTest.cpp b/logd/SerializedLogChunkTest.cpp
deleted file mode 100644
index f10b9c6..0000000
--- a/logd/SerializedLogChunkTest.cpp
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2020 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 "SerializedLogChunk.h"
-
-#include <limits>
-
-#include <android-base/stringprintf.h>
-#include <android/log.h>
-#include <gtest/gtest.h>
-
-using android::base::StringPrintf;
-
-TEST(SerializedLogChunk, smoke) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
- EXPECT_EQ(chunk_size + sizeof(SerializedLogChunk), chunk.PruneSize());
-
- static const char log_message[] = "log message";
- size_t expected_total_len = sizeof(SerializedLogEntry) + sizeof(log_message);
- ASSERT_TRUE(chunk.CanLog(expected_total_len));
- EXPECT_TRUE(chunk.CanLog(chunk_size));
- EXPECT_FALSE(chunk.CanLog(chunk_size + 1));
-
- log_time time(CLOCK_REALTIME);
- auto* entry = chunk.Log(1234, time, 0, 1, 2, log_message, sizeof(log_message));
- ASSERT_NE(nullptr, entry);
-
- EXPECT_EQ(1234U, entry->sequence());
- EXPECT_EQ(time, entry->realtime());
- EXPECT_EQ(0U, entry->uid());
- EXPECT_EQ(1, entry->pid());
- EXPECT_EQ(2, entry->tid());
- EXPECT_EQ(sizeof(log_message), entry->msg_len());
- EXPECT_STREQ(log_message, entry->msg());
- EXPECT_EQ(expected_total_len, entry->total_len());
-
- EXPECT_FALSE(chunk.CanLog(chunk_size));
- EXPECT_EQ(static_cast<int>(expected_total_len), chunk.write_offset());
- EXPECT_EQ(1234U, chunk.highest_sequence_number());
-}
-
-TEST(SerializedLogChunk, fill_log_exactly) {
- static const char log_message[] = "this is a log message";
- size_t individual_message_size = sizeof(SerializedLogEntry) + sizeof(log_message);
- size_t chunk_size = individual_message_size * 3;
- auto chunk = SerializedLogChunk{chunk_size};
- EXPECT_EQ(chunk_size + sizeof(SerializedLogChunk), chunk.PruneSize());
-
- ASSERT_TRUE(chunk.CanLog(individual_message_size));
- EXPECT_NE(nullptr, chunk.Log(1, log_time(), 1000, 1, 1, log_message, sizeof(log_message)));
-
- ASSERT_TRUE(chunk.CanLog(individual_message_size));
- EXPECT_NE(nullptr, chunk.Log(2, log_time(), 1000, 2, 1, log_message, sizeof(log_message)));
-
- ASSERT_TRUE(chunk.CanLog(individual_message_size));
- EXPECT_NE(nullptr, chunk.Log(3, log_time(), 1000, 3, 1, log_message, sizeof(log_message)));
-
- EXPECT_FALSE(chunk.CanLog(1));
-}
-
-TEST(SerializedLogChunk, three_logs) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
-
- chunk.Log(2, log_time(0x1234, 0x5678), 0x111, 0x222, 0x333, "initial message",
- strlen("initial message"));
- chunk.Log(3, log_time(0x2345, 0x6789), 0x444, 0x555, 0x666, "second message",
- strlen("second message"));
- auto uint64_t_max = std::numeric_limits<uint64_t>::max();
- auto uint32_t_max = std::numeric_limits<uint32_t>::max();
- chunk.Log(uint64_t_max, log_time(uint32_t_max, uint32_t_max), uint32_t_max, uint32_t_max,
- uint32_t_max, "last message", strlen("last message"));
-
- static const char expected_buffer_data[] =
- "\x11\x01\x00\x00\x22\x02\x00\x00\x33\x03\x00\x00" // UID PID TID
- "\x02\x00\x00\x00\x00\x00\x00\x00" // Sequence
- "\x34\x12\x00\x00\x78\x56\x00\x00" // Timestamp
- "\x0F\x00initial message" // msg_len + message
- "\x44\x04\x00\x00\x55\x05\x00\x00\x66\x06\x00\x00" // UID PID TID
- "\x03\x00\x00\x00\x00\x00\x00\x00" // Sequence
- "\x45\x23\x00\x00\x89\x67\x00\x00" // Timestamp
- "\x0E\x00second message" // msg_len + message
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" // UID PID TID
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" // Sequence
- "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" // Timestamp
- "\x0C\x00last message"; // msg_len + message
-
- for (size_t i = 0; i < chunk_size; ++i) {
- if (i < sizeof(expected_buffer_data)) {
- EXPECT_EQ(static_cast<uint8_t>(expected_buffer_data[i]), chunk.data()[i])
- << "position: " << i;
- } else {
- EXPECT_EQ(0, chunk.data()[i]) << "position: " << i;
- }
- }
-}
-
-// Check that the CHECK() in DecReaderRefCount() if the ref count goes bad is caught.
-TEST(SerializedLogChunk, catch_DecCompressedRef_CHECK) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
- EXPECT_DEATH({ chunk.DecReaderRefCount(); }, "");
-}
-
-// Check that the CHECK() in ClearUidLogs() if the ref count is greater than 0 is caught.
-TEST(SerializedLogChunk, catch_ClearUidLogs_CHECK) {
- size_t chunk_size = 10 * 4096;
- auto chunk = SerializedLogChunk{chunk_size};
- chunk.IncReaderRefCount();
- EXPECT_DEATH({ chunk.ClearUidLogs(1000, LOG_ID_MAIN, nullptr); }, "");
- chunk.DecReaderRefCount();
-}
-
-class UidClearTest : public testing::TestWithParam<bool> {
- protected:
- template <typename Write, typename Check>
- void Test(const Write& write, const Check& check, bool expected_result) {
- write(chunk_);
-
- bool finish_writing = GetParam();
- if (finish_writing) {
- chunk_.FinishWriting();
- }
- EXPECT_EQ(expected_result, chunk_.ClearUidLogs(kUidToClear, LOG_ID_MAIN, nullptr));
- if (finish_writing) {
- chunk_.IncReaderRefCount();
- }
-
- check(chunk_);
-
- if (finish_writing) {
- chunk_.DecReaderRefCount();
- }
- }
-
- static constexpr size_t kChunkSize = 10 * 4096;
- static constexpr uid_t kUidToClear = 1000;
- static constexpr uid_t kOtherUid = 1234;
-
- SerializedLogChunk chunk_{kChunkSize};
-};
-
-// Test that ClearUidLogs() is a no-op if there are no logs of that UID in the buffer.
-TEST_P(UidClearTest, no_logs_in_chunk) {
- auto write = [](SerializedLogChunk&) {};
- auto check = [](SerializedLogChunk&) {};
-
- Test(write, check, true);
-}
-
-// Test that ClearUidLogs() is a no-op if there are no logs of that UID in the buffer.
-TEST_P(UidClearTest, no_logs_from_uid) {
- static const char msg[] = "this is a log message";
- auto write = [](SerializedLogChunk& chunk) {
- chunk.Log(1, log_time(), kOtherUid, 1, 2, msg, sizeof(msg));
- };
-
- auto check = [](SerializedLogChunk& chunk) {
- auto* entry = chunk.log_entry(0);
- EXPECT_STREQ(msg, entry->msg());
- };
-
- Test(write, check, false);
-}
-
-// Test that ClearUidLogs() returns true if all logs in a given buffer correspond to the given UID.
-TEST_P(UidClearTest, all_single) {
- static const char msg[] = "this is a log message";
- auto write = [](SerializedLogChunk& chunk) {
- chunk.Log(1, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- };
- auto check = [](SerializedLogChunk&) {};
-
- Test(write, check, true);
-}
-
-// Test that ClearUidLogs() returns true if all logs in a given buffer correspond to the given UID.
-TEST_P(UidClearTest, all_multiple) {
- static const char msg[] = "this is a log message";
- auto write = [](SerializedLogChunk& chunk) {
- chunk.Log(2, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- chunk.Log(3, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- chunk.Log(4, log_time(), kUidToClear, 1, 2, msg, sizeof(msg));
- };
- auto check = [](SerializedLogChunk&) {};
-
- Test(write, check, true);
-}
-
-static std::string MakePrintable(const uint8_t* in, size_t length) {
- std::string result;
- for (size_t i = 0; i < length; ++i) {
- uint8_t c = in[i];
- if (isprint(c)) {
- result.push_back(c);
- } else {
- result.append(StringPrintf("\\%02x", static_cast<int>(c) & 0xFF));
- }
- }
- return result;
-}
-
-// This test clears UID logs at the beginning and end of the buffer, as well as two back to back
-// logs in the interior.
-TEST_P(UidClearTest, clear_beginning_and_end) {
- static const char msg1[] = "this is a log message";
- static const char msg2[] = "non-cleared message";
- static const char msg3[] = "back to back cleared messages";
- static const char msg4[] = "second in a row gone";
- static const char msg5[] = "but we save this one";
- static const char msg6[] = "and this 1!";
- static const char msg7[] = "the last one goes too";
- auto write = [](SerializedLogChunk& chunk) {
- ASSERT_NE(nullptr, chunk.Log(1, log_time(), kUidToClear, 1, 2, msg1, sizeof(msg1)));
- ASSERT_NE(nullptr, chunk.Log(2, log_time(), kOtherUid, 1, 2, msg2, sizeof(msg2)));
- ASSERT_NE(nullptr, chunk.Log(3, log_time(), kUidToClear, 1, 2, msg3, sizeof(msg3)));
- ASSERT_NE(nullptr, chunk.Log(4, log_time(), kUidToClear, 1, 2, msg4, sizeof(msg4)));
- ASSERT_NE(nullptr, chunk.Log(5, log_time(), kOtherUid, 1, 2, msg5, sizeof(msg5)));
- ASSERT_NE(nullptr, chunk.Log(6, log_time(), kOtherUid, 1, 2, msg6, sizeof(msg6)));
- ASSERT_NE(nullptr, chunk.Log(7, log_time(), kUidToClear, 1, 2, msg7, sizeof(msg7)));
- };
-
- auto check = [](SerializedLogChunk& chunk) {
- size_t read_offset = 0;
- auto* entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg2, entry->msg());
- read_offset += entry->total_len();
-
- entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg5, entry->msg());
- read_offset += entry->total_len();
-
- entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg6, entry->msg()) << MakePrintable(chunk.data(), chunk.write_offset());
- read_offset += entry->total_len();
-
- EXPECT_EQ(static_cast<int>(read_offset), chunk.write_offset());
- };
- Test(write, check, false);
-}
-
-// This tests the opposite case of beginning_and_end, in which we don't clear the beginning or end
-// logs. There is a single log pruned in the middle instead of back to back logs.
-TEST_P(UidClearTest, save_beginning_and_end) {
- static const char msg1[] = "saved first message";
- static const char msg2[] = "cleared interior message";
- static const char msg3[] = "last message stays";
- auto write = [](SerializedLogChunk& chunk) {
- ASSERT_NE(nullptr, chunk.Log(1, log_time(), kOtherUid, 1, 2, msg1, sizeof(msg1)));
- ASSERT_NE(nullptr, chunk.Log(2, log_time(), kUidToClear, 1, 2, msg2, sizeof(msg2)));
- ASSERT_NE(nullptr, chunk.Log(3, log_time(), kOtherUid, 1, 2, msg3, sizeof(msg3)));
- };
-
- auto check = [](SerializedLogChunk& chunk) {
- size_t read_offset = 0;
- auto* entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg1, entry->msg());
- read_offset += entry->total_len();
-
- entry = chunk.log_entry(read_offset);
- EXPECT_STREQ(msg3, entry->msg());
- read_offset += entry->total_len();
-
- EXPECT_EQ(static_cast<int>(read_offset), chunk.write_offset());
- };
- Test(write, check, false);
-}
-
-INSTANTIATE_TEST_CASE_P(UidClearTests, UidClearTest, testing::Values(true, false));
diff --git a/logd/SerializedLogEntry.h b/logd/SerializedLogEntry.h
deleted file mode 100644
index 2f2c244..0000000
--- a/logd/SerializedLogEntry.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <log/log.h>
-#include <log/log_read.h>
-
-#include "LogStatistics.h"
-#include "LogWriter.h"
-
-// These structs are packed into a single chunk of memory for each log type within a
-// SerializedLogChunk object. Their message is contained immediately at the end of the struct. The
-// address of the next log in the buffer is *this + sizeof(SerializedLogEntry) + msg_len_. If that
-// value would overflow the chunk of memory associated with the SerializedLogChunk object, then a
-// new SerializedLogChunk must be allocated to contain the next SerializedLogEntry.
-class __attribute__((packed)) SerializedLogEntry {
- public:
- SerializedLogEntry(uid_t uid, pid_t pid, pid_t tid, uint64_t sequence, log_time realtime,
- uint16_t len)
- : uid_(uid),
- pid_(pid),
- tid_(tid),
- sequence_(sequence),
- realtime_(realtime),
- msg_len_(len) {}
- SerializedLogEntry(const SerializedLogEntry& elem) = delete;
- SerializedLogEntry& operator=(const SerializedLogEntry& elem) = delete;
- ~SerializedLogEntry() {
- // Never place anything in this destructor. This class is in place constructed and never
- // destructed.
- }
-
- LogStatisticsElement ToLogStatisticsElement(log_id_t log_id) const {
- return LogStatisticsElement{
- .uid = uid(),
- .pid = pid(),
- .tid = tid(),
- .tag = IsBinary(log_id) ? MsgToTag(msg(), msg_len()) : 0,
- .realtime = realtime(),
- .msg = msg(),
- .msg_len = msg_len(),
- .dropped_count = 0,
- .log_id = log_id,
- .total_len = total_len(),
- };
- }
-
- bool Flush(LogWriter* writer, log_id_t log_id) const {
- struct logger_entry entry = {};
-
- entry.hdr_size = sizeof(struct logger_entry);
- entry.lid = log_id;
- entry.pid = pid();
- entry.tid = tid();
- entry.uid = uid();
- entry.sec = realtime().tv_sec;
- entry.nsec = realtime().tv_nsec;
- entry.len = msg_len();
-
- return writer->Write(entry, msg());
- }
-
- uid_t uid() const { return uid_; }
- pid_t pid() const { return pid_; }
- pid_t tid() const { return tid_; }
- uint16_t msg_len() const { return msg_len_; }
- uint64_t sequence() const { return sequence_; }
- log_time realtime() const { return realtime_; }
-
- char* msg() { return reinterpret_cast<char*>(this) + sizeof(*this); }
- const char* msg() const { return reinterpret_cast<const char*>(this) + sizeof(*this); }
- uint16_t total_len() const { return sizeof(*this) + msg_len_; }
-
- private:
- const uint32_t uid_;
- const uint32_t pid_;
- const uint32_t tid_;
- const uint64_t sequence_;
- const log_time realtime_;
- const uint16_t msg_len_;
-};
diff --git a/logd/SimpleLogBuffer.cpp b/logd/SimpleLogBuffer.cpp
deleted file mode 100644
index b00dd25..0000000
--- a/logd/SimpleLogBuffer.cpp
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright (C) 2020 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 "SimpleLogBuffer.h"
-
-#include <android-base/logging.h>
-
-#include "LogBufferElement.h"
-#include "LogSize.h"
-
-SimpleLogBuffer::SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats)
- : reader_list_(reader_list), tags_(tags), stats_(stats) {
- Init();
-}
-
-SimpleLogBuffer::~SimpleLogBuffer() {}
-
-void SimpleLogBuffer::Init() {
- log_id_for_each(i) {
- if (!SetSize(i, GetBufferSizeFromProperties(i))) {
- SetSize(i, kLogBufferMinSize);
- }
- }
-
- // Release any sleeping reader threads to dump their current content.
- auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- reader_thread->triggerReader_Locked();
- }
-}
-
-std::list<LogBufferElement>::iterator SimpleLogBuffer::GetOldest(log_id_t log_id) {
- auto it = logs().begin();
- if (oldest_[log_id]) {
- it = *oldest_[log_id];
- }
- while (it != logs().end() && it->log_id() != log_id) {
- it++;
- }
- if (it != logs().end()) {
- oldest_[log_id] = it;
- }
- return it;
-}
-
-bool SimpleLogBuffer::ShouldLog(log_id_t log_id, const char* msg, uint16_t len) {
- if (log_id == LOG_ID_SECURITY) {
- return true;
- }
-
- int prio = ANDROID_LOG_INFO;
- const char* tag = nullptr;
- size_t tag_len = 0;
- if (IsBinary(log_id)) {
- int32_t numeric_tag = MsgToTag(msg, len);
- tag = tags_->tagToName(numeric_tag);
- if (tag) {
- tag_len = strlen(tag);
- }
- } else {
- prio = *msg;
- tag = msg + 1;
- tag_len = strnlen(tag, len - 1);
- }
- return __android_log_is_loggable_len(prio, tag, tag_len, ANDROID_LOG_VERBOSE);
-}
-
-int SimpleLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid,
- const char* msg, uint16_t len) {
- if (log_id >= LOG_ID_MAX) {
- return -EINVAL;
- }
-
- if (!ShouldLog(log_id, msg, len)) {
- // Log traffic received to total
- stats_->AddTotal(log_id, len);
- return -EACCES;
- }
-
- // Slip the time by 1 nsec if the incoming lands on xxxxxx000 ns.
- // This prevents any chance that an outside source can request an
- // exact entry with time specified in ms or us precision.
- if ((realtime.tv_nsec % 1000) == 0) ++realtime.tv_nsec;
-
- auto lock = std::lock_guard{lock_};
- auto sequence = sequence_.fetch_add(1, std::memory_order_relaxed);
- LogInternal(LogBufferElement(log_id, realtime, uid, pid, tid, sequence, msg, len));
- return len;
-}
-
-void SimpleLogBuffer::LogInternal(LogBufferElement&& elem) {
- log_id_t log_id = elem.log_id();
-
- logs_.emplace_back(std::move(elem));
- stats_->Add(logs_.back().ToLogStatisticsElement());
- MaybePrune(log_id);
- reader_list_->NotifyNewLog(1 << log_id);
-}
-
-// These extra parameters are only required for chatty, but since they're a no-op for
-// SimpleLogBuffer, it's easier to include them here, then to duplicate FlushTo() for
-// ChattyLogBuffer.
-class ChattyFlushToState : public FlushToState {
- public:
- ChattyFlushToState(uint64_t start, LogMask log_mask) : FlushToState(start, log_mask) {}
-
- pid_t* last_tid() { return last_tid_; }
-
- bool drop_chatty_messages() const { return drop_chatty_messages_; }
- void set_drop_chatty_messages(bool value) { drop_chatty_messages_ = value; }
-
- private:
- pid_t last_tid_[LOG_ID_MAX] = {};
- bool drop_chatty_messages_ = true;
-};
-
-std::unique_ptr<FlushToState> SimpleLogBuffer::CreateFlushToState(uint64_t start,
- LogMask log_mask) {
- return std::make_unique<ChattyFlushToState>(start, log_mask);
-}
-
-bool SimpleLogBuffer::FlushTo(
- LogWriter* writer, FlushToState& abstract_state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) {
- auto shared_lock = SharedLock{lock_};
-
- auto& state = reinterpret_cast<ChattyFlushToState&>(abstract_state);
-
- std::list<LogBufferElement>::iterator it;
- if (state.start() <= 1) {
- // client wants to start from the beginning
- it = logs_.begin();
- } else {
- // Client wants to start from some specified time. Chances are
- // we are better off starting from the end of the time sorted list.
- for (it = logs_.end(); it != logs_.begin();
- /* do nothing */) {
- --it;
- if (it->sequence() == state.start()) {
- break;
- } else if (it->sequence() < state.start()) {
- it++;
- break;
- }
- }
- }
-
- for (; it != logs_.end(); ++it) {
- LogBufferElement& element = *it;
-
- state.set_start(element.sequence());
-
- if (!writer->privileged() && element.uid() != writer->uid()) {
- continue;
- }
-
- if (((1 << element.log_id()) & state.log_mask()) == 0) {
- continue;
- }
-
- if (filter) {
- FilterResult ret =
- filter(element.log_id(), element.pid(), element.sequence(), element.realtime());
- if (ret == FilterResult::kSkip) {
- continue;
- }
- if (ret == FilterResult::kStop) {
- break;
- }
- }
-
- // drop_chatty_messages is initialized to true, so if the first message that we attempt to
- // flush is a chatty message, we drop it. Once we see a non-chatty message it gets set to
- // false to let further chatty messages be printed.
- if (state.drop_chatty_messages()) {
- if (element.dropped_count() != 0) {
- continue;
- }
- state.set_drop_chatty_messages(false);
- }
-
- bool same_tid = state.last_tid()[element.log_id()] == element.tid();
- // Dropped (chatty) immediately following a valid log from the same source in the same log
- // buffer indicates we have a multiple identical squash. chatty that differs source is due
- // to spam filter. chatty to chatty of different source is also due to spam filter.
- state.last_tid()[element.log_id()] =
- (element.dropped_count() && !same_tid) ? 0 : element.tid();
-
- shared_lock.unlock();
- // We never prune logs equal to or newer than any LogReaderThreads' `start` value, so the
- // `element` pointer is safe here without the lock
- if (!element.FlushTo(writer, stats_, same_tid)) {
- return false;
- }
- shared_lock.lock_shared();
- }
-
- state.set_start(state.start() + 1);
- return true;
-}
-
-bool SimpleLogBuffer::Clear(log_id_t id, uid_t uid) {
- // Try three times to clear, then disconnect the readers and try one final time.
- for (int retry = 0; retry < 3; ++retry) {
- {
- auto lock = std::lock_guard{lock_};
- if (Prune(id, ULONG_MAX, uid)) {
- return true;
- }
- }
- sleep(1);
- }
- // Check if it is still busy after the sleep, we try to prune one entry, not another clear run,
- // so we are looking for the quick side effect of the return value to tell us if we have a
- // _blocked_ reader.
- bool busy = false;
- {
- auto lock = std::lock_guard{lock_};
- busy = !Prune(id, 1, uid);
- }
- // It is still busy, disconnect all readers.
- if (busy) {
- auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- if (reader_thread->IsWatching(id)) {
- LOG(WARNING) << "Kicking blocked reader, " << reader_thread->name()
- << ", from LogBuffer::clear()";
- reader_thread->release_Locked();
- }
- }
- }
- auto lock = std::lock_guard{lock_};
- return Prune(id, ULONG_MAX, uid);
-}
-
-// get the total space allocated to "id"
-size_t SimpleLogBuffer::GetSize(log_id_t id) {
- auto lock = SharedLock{lock_};
- size_t retval = max_size_[id];
- return retval;
-}
-
-// set the total space allocated to "id"
-bool SimpleLogBuffer::SetSize(log_id_t id, size_t size) {
- // Reasonable limits ...
- if (!IsValidBufferSize(size)) {
- return false;
- }
-
- auto lock = std::lock_guard{lock_};
- max_size_[id] = size;
- return true;
-}
-
-void SimpleLogBuffer::MaybePrune(log_id_t id) {
- unsigned long prune_rows;
- if (stats_->ShouldPrune(id, max_size_[id], &prune_rows)) {
- Prune(id, prune_rows, 0);
- }
-}
-
-bool SimpleLogBuffer::Prune(log_id_t id, unsigned long prune_rows, uid_t caller_uid) {
- auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
-
- // Don't prune logs that are newer than the point at which any reader threads are reading from.
- LogReaderThread* oldest = nullptr;
- for (const auto& reader_thread : reader_list_->reader_threads()) {
- if (!reader_thread->IsWatching(id)) {
- continue;
- }
- if (!oldest || oldest->start() > reader_thread->start() ||
- (oldest->start() == reader_thread->start() &&
- reader_thread->deadline().time_since_epoch().count() != 0)) {
- oldest = reader_thread.get();
- }
- }
-
- auto it = GetOldest(id);
-
- while (it != logs_.end()) {
- LogBufferElement& element = *it;
-
- if (element.log_id() != id) {
- ++it;
- continue;
- }
-
- if (caller_uid != 0 && element.uid() != caller_uid) {
- ++it;
- continue;
- }
-
- if (oldest && oldest->start() <= element.sequence()) {
- KickReader(oldest, id, prune_rows);
- return false;
- }
-
- stats_->Subtract(element.ToLogStatisticsElement());
- it = Erase(it);
- if (--prune_rows == 0) {
- return true;
- }
- }
- return true;
-}
-
-std::list<LogBufferElement>::iterator SimpleLogBuffer::Erase(
- std::list<LogBufferElement>::iterator it) {
- bool oldest_is_it[LOG_ID_MAX];
- log_id_for_each(i) { oldest_is_it[i] = oldest_[i] && it == *oldest_[i]; }
-
- it = logs_.erase(it);
-
- log_id_for_each(i) {
- if (oldest_is_it[i]) {
- if (__predict_false(it == logs().end())) {
- oldest_[i] = std::nullopt;
- } else {
- oldest_[i] = it; // Store the next iterator even if it does not correspond to
- // the same log_id, as a starting point for GetOldest().
- }
- }
- }
-
- return it;
-}
-
-// If the selected reader is blocking our pruning progress, decide on
-// what kind of mitigation is necessary to unblock the situation.
-void SimpleLogBuffer::KickReader(LogReaderThread* reader, log_id_t id, unsigned long prune_rows) {
- if (stats_->Sizes(id) > (2 * max_size_[id])) { // +100%
- // A misbehaving or slow reader has its connection
- // dropped if we hit too much memory pressure.
- LOG(WARNING) << "Kicking blocked reader, " << reader->name()
- << ", from LogBuffer::kickMe()";
- reader->release_Locked();
- } else if (reader->deadline().time_since_epoch().count() != 0) {
- // Allow a blocked WRAP deadline reader to trigger and start reporting the log data.
- reader->triggerReader_Locked();
- } else {
- // tell slow reader to skip entries to catch up
- LOG(WARNING) << "Skipping " << prune_rows << " entries from slow reader, " << reader->name()
- << ", from LogBuffer::kickMe()";
- reader->triggerSkip_Locked(id, prune_rows);
- }
-}
diff --git a/logd/SimpleLogBuffer.h b/logd/SimpleLogBuffer.h
deleted file mode 100644
index 8e5b50e..0000000
--- a/logd/SimpleLogBuffer.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2020 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.
- */
-
-#pragma once
-
-#include <atomic>
-#include <list>
-#include <mutex>
-
-#include "LogBuffer.h"
-#include "LogBufferElement.h"
-#include "LogReaderList.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "rwlock.h"
-
-class SimpleLogBuffer : public LogBuffer {
- public:
- SimpleLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats);
- ~SimpleLogBuffer();
- void Init() override final;
-
- int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg,
- uint16_t len) override;
- std::unique_ptr<FlushToState> CreateFlushToState(uint64_t start, LogMask log_mask) override;
- bool FlushTo(LogWriter* writer, FlushToState& state,
- const std::function<FilterResult(log_id_t log_id, pid_t pid, uint64_t sequence,
- log_time realtime)>& filter) override;
-
- bool Clear(log_id_t id, uid_t uid) override;
- size_t GetSize(log_id_t id) override;
- bool SetSize(log_id_t id, size_t size) override final;
-
- uint64_t sequence() const override { return sequence_.load(std::memory_order_relaxed); }
-
- protected:
- virtual bool Prune(log_id_t id, unsigned long prune_rows, uid_t uid) REQUIRES(lock_);
- virtual void LogInternal(LogBufferElement&& elem) REQUIRES(lock_);
-
- // Returns an iterator to the oldest element for a given log type, or logs_.end() if
- // there are no logs for the given log type. Requires logs_lock_ to be held.
- std::list<LogBufferElement>::iterator GetOldest(log_id_t log_id) REQUIRES(lock_);
- std::list<LogBufferElement>::iterator Erase(std::list<LogBufferElement>::iterator it)
- REQUIRES(lock_);
- void KickReader(LogReaderThread* reader, log_id_t id, unsigned long prune_rows)
- REQUIRES_SHARED(lock_);
-
- LogStatistics* stats() { return stats_; }
- LogReaderList* reader_list() { return reader_list_; }
- size_t max_size(log_id_t id) REQUIRES_SHARED(lock_) { return max_size_[id]; }
- std::list<LogBufferElement>& logs() { return logs_; }
-
- RwLock lock_;
-
- private:
- bool ShouldLog(log_id_t log_id, const char* msg, uint16_t len);
- void MaybePrune(log_id_t id) REQUIRES(lock_);
-
- LogReaderList* reader_list_;
- LogTags* tags_;
- LogStatistics* stats_;
-
- std::atomic<uint64_t> sequence_ = 1;
-
- size_t max_size_[LOG_ID_MAX] GUARDED_BY(lock_);
- std::list<LogBufferElement> logs_ GUARDED_BY(lock_);
- // Keeps track of the iterator to the oldest log message of a given log type, as an
- // optimization when pruning logs. Use GetOldest() to retrieve.
- std::optional<std::list<LogBufferElement>::iterator> oldest_[LOG_ID_MAX] GUARDED_BY(lock_);
-};
diff --git a/logd/auditctl.cpp b/logd/auditctl.cpp
deleted file mode 100644
index 98bb02d..0000000
--- a/logd/auditctl.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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/doc_images/cpu_cuttlefish.png b/logd/doc_images/cpu_cuttlefish.png
deleted file mode 100644
index 8d809ca..0000000
--- a/logd/doc_images/cpu_cuttlefish.png
+++ /dev/null
Binary files differ
diff --git a/logd/doc_images/cpu_walleye.png b/logd/doc_images/cpu_walleye.png
deleted file mode 100644
index 39c951b..0000000
--- a/logd/doc_images/cpu_walleye.png
+++ /dev/null
Binary files differ
diff --git a/logd/doc_images/memory_usage.png b/logd/doc_images/memory_usage.png
deleted file mode 100644
index 434d6d3..0000000
--- a/logd/doc_images/memory_usage.png
+++ /dev/null
Binary files differ
diff --git a/logd/doc_images/total_log_count.png b/logd/doc_images/total_log_count.png
deleted file mode 100644
index e73c2c1..0000000
--- a/logd/doc_images/total_log_count.png
+++ /dev/null
Binary files differ
diff --git a/logd/event.logtags b/logd/event.logtags
deleted file mode 100644
index fa13a62..0000000
--- a/logd/event.logtags
+++ /dev/null
@@ -1,39 +0,0 @@
-# The entries in this file map a sparse set of log tag numbers to tag names.
-# This is installed on the device, in /system/etc, and parsed by logcat.
-#
-# Tag numbers are decimal integers, from 0 to 2^31. (Let's leave the
-# negative values alone for now.)
-#
-# Tag names are one or more ASCII letters and numbers or underscores, i.e.
-# "[A-Z][a-z][0-9]_". Do not include spaces or punctuation (the former
-# impacts log readability, the latter makes regex searches more annoying).
-#
-# Tag numbers and names are separated by whitespace. Blank lines and lines
-# starting with '#' are ignored.
-#
-# Optionally, after the tag names can be put a description for the value(s)
-# of the tag. Description are in the format
-# (<name>|data type[|data unit])
-# Multiple values are separated by commas.
-#
-# The data type is a number from the following values:
-# 1: int
-# 2: long
-# 3: string
-# 4: list
-#
-# The data unit is a number taken from the following list:
-# 1: Number of objects
-# 2: Number of bytes
-# 3: Number of milliseconds
-# 4: Number of allocations
-# 5: Id
-# 6: Percent
-# s: Number of seconds (monotonic time)
-# Default value for data of type int/long is 2 (bytes).
-#
-# TODO: generate ".java" and ".h" files with integer constants from this file.
-
-1003 auditd (avc|3)
-1004 chatty (dropped|3)
-1005 tag_def (tag|1),(name|3),(format|3)
diff --git a/logd/fuzz/Android.bp b/logd/fuzz/Android.bp
deleted file mode 100644
index d346cd7..0000000
--- a/logd/fuzz/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 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.
- */
-
-cc_defaults {
- name: "log_fuzzer_defaults",
- static_libs: [
- "libbase",
- "libcutils",
- "libselinux",
- "liblog",
- "liblogd",
- "libcutils",
- "libz",
- "libzstd",
- ],
- cflags: ["-Wextra"],
- host_supported: true,
-}
-
-cc_fuzz {
- name: "log_buffer_log_fuzzer",
- defaults: ["log_fuzzer_defaults"],
- srcs: [
- "log_buffer_log_fuzzer.cpp",
- ],
-}
-
-cc_fuzz {
- name: "serialized_log_buffer_fuzzer",
- defaults: ["log_fuzzer_defaults"],
- srcs: [
- "serialized_log_buffer_fuzzer.cpp",
- ],
- corpus: [
- "corpus/logentry_use_after_compress",
- ]
-}
diff --git a/logd/fuzz/corpus/logentry_use_after_compress b/logd/fuzz/corpus/logentry_use_after_compress
deleted file mode 100644
index 2081b13..0000000
--- a/logd/fuzz/corpus/logentry_use_after_compress
+++ /dev/null
Binary files differ
diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp
deleted file mode 100644
index d71a2f9..0000000
--- a/logd/fuzz/log_buffer_log_fuzzer.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 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 <string>
-
-#include <android-base/logging.h>
-
-#include "../ChattyLogBuffer.h"
-#include "../LogReaderList.h"
-#include "../LogReaderThread.h"
-#include "../LogStatistics.h"
-#include "../SerializedLogBuffer.h"
-
-// We don't want to waste a lot of entropy on messages
-#define MAX_MSG_LENGTH 5
-
-// Tag IDs usually start at 1000, we only want to try 1000 through 1009
-#define MIN_TAG_ID 1000
-#define TAG_MOD 10
-
-char* android::uidToName(uid_t) {
- return strdup("fake");
-}
-
-struct LogInput {
- public:
- log_id_t log_id;
- log_time realtime;
- uid_t uid;
- pid_t pid;
- pid_t tid;
- unsigned int log_mask;
-};
-
-int write_log_messages(const uint8_t** pdata, size_t* data_left, LogBuffer* log_buffer,
- LogStatistics* stats) {
- const uint8_t* data = *pdata;
- const LogInput* logInput = reinterpret_cast<const LogInput*>(data);
- data += sizeof(LogInput);
- *data_left -= sizeof(LogInput);
-
- uint32_t tag = MIN_TAG_ID + data[0] % TAG_MOD;
- uint8_t msg_length = data[1] % MAX_MSG_LENGTH;
- if (msg_length < 2) {
- // Not enough data for message
- return 0;
- }
-
- data += 2 * sizeof(uint8_t);
- *data_left -= 2 * sizeof(uint8_t);
-
- if (*data_left < msg_length) {
- // Not enough data for tag and message
- *pdata = data;
- return 0;
- }
-
- // We need nullterm'd strings
- char msg[sizeof(uint32_t) + MAX_MSG_LENGTH + sizeof(char)];
- char* msg_only = msg + sizeof(uint32_t);
- memcpy(msg, &tag, sizeof(uint32_t));
- memcpy(msg_only, data, msg_length);
- msg_only[msg_length] = '\0';
- data += msg_length;
- *data_left -= msg_length;
-
- // Other elements not in enum.
- log_id_t log_id = static_cast<log_id_t>(unsigned(logInput->log_id) % (LOG_ID_MAX + 1));
- log_buffer->Log(log_id, logInput->realtime, logInput->uid, logInput->pid, logInput->tid, msg,
- sizeof(uint32_t) + msg_length + 1);
- stats->Format(logInput->uid, logInput->pid, logInput->log_mask);
- *pdata = data;
- return 1;
-}
-
-class NoopWriter : public LogWriter {
- public:
- NoopWriter() : LogWriter(0, true) {}
- bool Write(const logger_entry&, const char*) override { return true; }
-
- std::string name() const override { return "noop_writer"; }
-};
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- // We want a random tag length and a random remaining message length
- if (data == nullptr || size < sizeof(LogInput) + 2 * sizeof(uint8_t)) {
- return 0;
- }
-
- android::base::SetMinimumLogSeverity(android::base::ERROR);
-
- LogReaderList reader_list;
- LogTags tags;
- PruneList prune_list;
- LogStatistics stats(true, true);
- std::unique_ptr<LogBuffer> log_buffer;
-#ifdef FUZZ_SERIALIZED
- log_buffer.reset(new SerializedLogBuffer(&reader_list, &tags, &stats));
-#else
- log_buffer.reset(new ChattyLogBuffer(&reader_list, &tags, &prune_list, &stats));
-#endif
- size_t data_left = size;
- const uint8_t** pdata = &data;
-
- prune_list.Init(nullptr);
- // We want to get pruning code to get called.
- log_id_for_each(i) { log_buffer->SetSize(i, 10000); }
-
- while (data_left >= sizeof(LogInput) + 2 * sizeof(uint8_t)) {
- if (!write_log_messages(pdata, &data_left, log_buffer.get(), &stats)) {
- return 0;
- }
- }
-
- // Read out all of the logs.
- {
- auto lock = std::unique_lock{reader_list.reader_threads_lock()};
- std::unique_ptr<LogWriter> test_writer(new NoopWriter());
- std::unique_ptr<LogReaderThread> log_reader(
- new LogReaderThread(log_buffer.get(), &reader_list, std::move(test_writer), true, 0,
- kLogMaskAll, 0, {}, 1, {}));
- reader_list.reader_threads().emplace_back(std::move(log_reader));
- }
-
- // Wait until the reader has finished.
- while (true) {
- usleep(50);
- auto lock = std::unique_lock{reader_list.reader_threads_lock()};
- if (reader_list.reader_threads().size() == 0) {
- break;
- }
- }
-
- log_id_for_each(i) { log_buffer->Clear(i, 0); }
- return 0;
-}
diff --git a/logd/fuzz/serialized_log_buffer_fuzzer.cpp b/logd/fuzz/serialized_log_buffer_fuzzer.cpp
deleted file mode 100644
index d4795b0..0000000
--- a/logd/fuzz/serialized_log_buffer_fuzzer.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define FUZZ_SERIALIZED
-
-#include "log_buffer_log_fuzzer.cpp"
diff --git a/logd/libaudit.cpp b/logd/libaudit.cpp
deleted file mode 100644
index ccea0a2..0000000
--- a/logd/libaudit.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2012, Samsung Telecommunications of America
- * Copyright (C) 2014 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.
- *
- * Written by William Roberts <w.roberts@sta.samsung.com>
- *
- */
-
-#include "libaudit.h"
-
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <limits>
-
-/**
- * Waits for an ack from the kernel
- * @param fd
- * The netlink socket fd
- * @return
- * This function returns 0 on success, else -errno.
- */
-static int get_ack(int fd) {
- struct audit_message rep = {};
- int rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK);
- if (rc < 0) {
- return rc;
- }
-
- if (rep.nlh.nlmsg_type == NLMSG_ERROR) {
- audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0);
- rc = reinterpret_cast<struct nlmsgerr*>(rep.data)->error;
- if (rc) {
- return -rc;
- }
- }
-
- return 0;
-}
-
-/**
- *
- * @param fd
- * The netlink socket fd
- * @param type
- * The type of netlink message
- * @param data
- * The data to send
- * @param size
- * The length of the data in bytes
- * @return
- * This function returns a positive sequence number on success, else -errno.
- */
-static int audit_send(int fd, int type, const void* data, size_t size) {
- struct sockaddr_nl addr = {.nl_family = AF_NETLINK};
-
- /* Set up the netlink headers */
- struct audit_message req = {};
- req.nlh.nlmsg_type = static_cast<uint16_t>(type);
- req.nlh.nlmsg_len = NLMSG_SPACE(size);
- req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
-
- /*
- * Check for a valid fd, even though sendto would catch this, its easier
- * to always blindly increment the sequence number
- */
- if (fd < 0) {
- return -EBADF;
- }
-
- /* Ensure the message is not too big */
- if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
- return -EINVAL;
- }
-
- /* Only memcpy in the data if it was specified */
- if (size && data) {
- memcpy(NLMSG_DATA(&req.nlh), data, size);
- }
-
- /*
- * Only increment the sequence number on a guarantee
- * you will send it to the kernel.
- */
- static uint32_t sequence = 0;
- if (sequence == std::numeric_limits<uint32_t>::max()) {
- sequence = 1;
- } else {
- sequence++;
- }
- req.nlh.nlmsg_seq = sequence;
-
- ssize_t rc = TEMP_FAILURE_RETRY(
- sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*)&addr, sizeof(addr)));
-
- /* Not all the bytes were sent */
- if (rc < 0) {
- return -errno;
- } else if ((uint32_t)rc != req.nlh.nlmsg_len) {
- return -EPROTO;
- }
-
- /* We sent all the bytes, get the ack */
- rc = get_ack(fd);
-
- /* If the ack failed, return the error, else return the sequence number */
- rc = (rc == 0) ? (int)sequence : rc;
-
- return rc;
-}
-
-int audit_setup(int fd, pid_t pid) {
- /*
- * In order to set the auditd PID we send an audit message over the netlink
- * socket with the pid field of the status struct set to our current pid,
- * and the the mask set to AUDIT_STATUS_PID
- */
- struct audit_status status = {
- .mask = AUDIT_STATUS_PID,
- .pid = static_cast<uint32_t>(pid),
- };
-
- /* Let the kernel know this pid will be registering for audit events */
- int rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
- if (rc < 0) {
- return rc;
- }
-
- /*
- * In a request where we need to wait for a response, wait for the message
- * and discard it. This message confirms and sync's us with the kernel.
- * This daemon is now registered as the audit logger.
- *
- * TODO
- * If the daemon dies and restarts the message didn't come back,
- * so I went to non-blocking and it seemed to fix the bug.
- * Need to investigate further.
- */
- struct audit_message rep = {};
- audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
-
- return 0;
-}
-
-int audit_open() {
- return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
-}
-
-int audit_rate_limit(int fd, uint32_t limit) {
- struct audit_status status = {
- .mask = AUDIT_STATUS_RATE_LIMIT, .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) {
- if (fd < 0) {
- return -EBADF;
- }
-
- int flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0;
- flags |= peek;
-
- /*
- * Get the data from the netlink socket but on error we need to be carefull,
- * the interface shows that EINTR can never be returned, other errors,
- * however, can be returned.
- */
- struct sockaddr_nl nladdr;
- socklen_t nladdrlen = sizeof(nladdr);
- ssize_t len = TEMP_FAILURE_RETRY(
- recvfrom(fd, rep, sizeof(*rep), flags, (struct sockaddr*)&nladdr, &nladdrlen));
-
- /*
- * EAGAIN should be re-tried until success or another error manifests.
- */
- if (len < 0) {
- if (block == GET_REPLY_NONBLOCKING && errno == EAGAIN) {
- /* If request is non blocking and errno is EAGAIN, just return 0 */
- return 0;
- }
- return -errno;
- }
-
- if (nladdrlen != sizeof(nladdr)) {
- return -EPROTO;
- }
-
- /* Make sure the netlink message was not spoof'd */
- if (nladdr.nl_pid) {
- return -EINVAL;
- }
-
- /* Check if the reply from the kernel was ok */
- if (!NLMSG_OK(&rep->nlh, (size_t)len)) {
- return len == sizeof(*rep) ? -EFBIG : -EBADE;
- }
-
- return 0;
-}
-
-void audit_close(int fd) {
- close(fd);
-}
diff --git a/logd/libaudit.h b/logd/libaudit.h
deleted file mode 100644
index 27b0866..0000000
--- a/logd/libaudit.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2012, Samsung Telecommunications of America
- * Copyright (C) 2014 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.
- *
- * Written by William Roberts <w.roberts@sta.samsung.com>
- */
-
-#pragma once
-
-#include <stdint.h>
-#include <sys/cdefs.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <linux/audit.h>
-#include <linux/netlink.h>
-
-__BEGIN_DECLS
-
-#define MAX_AUDIT_MESSAGE_LENGTH 8970
-
-typedef enum { GET_REPLY_BLOCKING = 0, GET_REPLY_NONBLOCKING } reply_t;
-
-/* type == AUDIT_SIGNAL_INFO */
-struct audit_sig_info {
- uid_t uid;
- pid_t pid;
- char ctx[0];
-};
-
-struct audit_message {
- struct nlmsghdr nlh;
- char data[MAX_AUDIT_MESSAGE_LENGTH];
-};
-
-/**
- * Opens a connection to the Audit netlink socket
- * @return
- * A valid fd on success or < 0 on error with errno set.
- * Returns the same errors as man 2 socket.
- */
-extern int audit_open(void);
-
-/**
- * Closes the fd returned from audit_open()
- * @param fd
- * The fd to close
- */
-extern void audit_close(int fd);
-
-/**
- *
- * @param fd
- * The fd returned by a call to audit_open()
- * @param rep
- * The response struct to store the response in.
- * @param block
- * Whether or not to block on IO
- * @param peek
- * Whether or not we are to remove the message from
- * the queue when we do a read on the netlink socket.
- * @return
- * This function returns 0 on success, else -errno.
- */
-extern int audit_get_reply(int fd, struct audit_message* rep, reply_t block,
- int peek);
-
-/**
- * Sets a pid to receive audit netlink events from the kernel
- * @param fd
- * The fd returned by a call to audit_open()
- * @param pid
- * The pid whom to set as the receiver of audit messages
- * @return
- * This function returns 0 on success, -errno on error.
- */
-extern int audit_setup(int fd, pid_t pid);
-
-/**
- * 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
deleted file mode 100644
index 530f342..0000000
--- a/logd/logd.rc
+++ /dev/null
@@ -1,35 +0,0 @@
-service logd /system/bin/logd
- socket logd stream 0666 logd logd
- socket logdr seqpacket 0666 logd logd
- socket logdw dgram+passcred 0222 logd logd
- file /proc/kmsg r
- file /dev/kmsg w
- user logd
- group logd system package_info readproc
- capabilities SYSLOG AUDIT_CONTROL
- priority 10
- writepid /dev/cpuset/system-background/tasks
-
-service logd-reinit /system/bin/logd --reinit
- oneshot
- disabled
- user logd
- 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/logd_test.cpp b/logd/logd_test.cpp
deleted file mode 100644
index 828f580..0000000
--- a/logd/logd_test.cpp
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- * Copyright (C) 2014 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 <ctype.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <cutils/sockets.h>
-#include <gtest/gtest.h>
-#include <log/log_read.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#ifdef __ANDROID__
-#include <selinux/selinux.h>
-#endif
-
-#include "LogUtils.h" // For LOGD_SNDTIMEO.
-
-using android::base::unique_fd;
-
-#ifdef __ANDROID__
-static void send_to_control(char* buf, size_t len) {
- int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock >= 0) {
- if (write(sock, buf, strlen(buf) + 1) > 0) {
- ssize_t ret;
- while ((ret = read(sock, buf, len)) > 0) {
- if (((size_t)ret == len) || (len < PAGE_SIZE)) {
- break;
- }
- len -= ret;
- buf += ret;
-
- struct pollfd p = {.fd = sock, .events = POLLIN, .revents = 0 };
-
- ret = poll(&p, 1, 20);
- if ((ret <= 0) || !(p.revents & POLLIN)) {
- break;
- }
- }
- }
- close(sock);
- }
-}
-
-/*
- * returns statistics
- */
-static void my_android_logger_get_statistics(char* buf, size_t len) {
- snprintf(buf, len, "getStatistics 0 1 2 3 4");
- send_to_control(buf, len);
-}
-
-static void alloc_statistics(char** buffer, size_t* length) {
- size_t len = 8192;
- char* buf;
-
- for (int retry = 32; (retry >= 0); delete[] buf, --retry) {
- buf = new char[len];
- my_android_logger_get_statistics(buf, len);
-
- buf[len - 1] = '\0';
- size_t ret = atol(buf) + 1;
- if (ret < 4) {
- delete[] buf;
- buf = nullptr;
- break;
- }
- bool check = ret <= len;
- len = ret;
- if (check) {
- break;
- }
- len += len / 8; // allow for some slop
- }
- *buffer = buf;
- *length = len;
-}
-
-static char* find_benchmark_spam(char* cp) {
- // liblog_benchmarks has been run designed to SPAM. The signature of
- // a noisiest UID statistics is:
- //
- // Chattiest UIDs in main log buffer: Size Pruned
- // UID PACKAGE BYTES LINES
- // 0 root 54164 147569
- //
- char* benchmark = nullptr;
- do {
- static const char signature[] = "\n0 root ";
-
- benchmark = strstr(cp, signature);
- if (!benchmark) {
- break;
- }
- cp = benchmark + sizeof(signature);
- while (isspace(*cp)) {
- ++cp;
- }
- benchmark = cp;
-#ifdef DEBUG
- char* end = strstr(benchmark, "\n");
- if (end == nullptr) {
- end = benchmark + strlen(benchmark);
- }
- fprintf(stderr, "parse for spam counter in \"%.*s\"\n",
- (int)(end - benchmark), benchmark);
-#endif
- // content
- while (isdigit(*cp)) {
- ++cp;
- }
- while (isspace(*cp)) {
- ++cp;
- }
- // optional +/- field?
- if ((*cp == '-') || (*cp == '+')) {
- while (isdigit(*++cp) || (*cp == '.') || (*cp == '%') ||
- (*cp == 'X')) {
- ;
- }
- while (isspace(*cp)) {
- ++cp;
- }
- }
- // number of entries pruned
- unsigned long value = 0;
- while (isdigit(*cp)) {
- value = value * 10ULL + *cp - '0';
- ++cp;
- }
- if (value > 10UL) {
- break;
- }
- benchmark = nullptr;
- } while (*cp);
- return benchmark;
-}
-#endif
-
-#ifdef LOGD_ENABLE_FLAKY_TESTS
-TEST(logd, statistics) {
-#ifdef __ANDROID__
- size_t len;
- char* buf;
-
- // Drop cache so that any access problems can be discovered.
- if (!android::base::WriteStringToFile("3\n", "/proc/sys/vm/drop_caches")) {
- GTEST_LOG_(INFO) << "Could not open trigger dropping inode cache";
- }
-
- alloc_statistics(&buf, &len);
-
- ASSERT_TRUE(nullptr != buf);
-
- // remove trailing FF
- char* cp = buf + len - 1;
- *cp = '\0';
- bool truncated = *--cp != '\f';
- if (!truncated) {
- *cp = '\0';
- }
-
- // squash out the byte count
- cp = buf;
- if (!truncated) {
- while (isdigit(*cp) || (*cp == '\n')) {
- ++cp;
- }
- }
-
- fprintf(stderr, "%s", cp);
-
- EXPECT_LT((size_t)64, strlen(cp));
-
- EXPECT_EQ(0, truncated);
-
- char* main_logs = strstr(cp, "\nChattiest UIDs in main ");
- EXPECT_TRUE(nullptr != main_logs);
-
- char* radio_logs = strstr(cp, "\nChattiest UIDs in radio ");
- if (!radio_logs)
- GTEST_LOG_(INFO) << "Value of: nullptr != radio_logs\n"
- "Actual: false\n"
- "Expected: false\n";
-
- char* system_logs = strstr(cp, "\nChattiest UIDs in system ");
- EXPECT_TRUE(nullptr != system_logs);
-
- char* events_logs = strstr(cp, "\nChattiest UIDs in events ");
- EXPECT_TRUE(nullptr != events_logs);
-
- // Check if there is any " u0_a#### " as this means packagelistparser broken
- char* used_getpwuid = nullptr;
- int used_getpwuid_len;
- char* uid_name = cp;
- static const char getpwuid_prefix[] = " u0_a";
- while ((uid_name = strstr(uid_name, getpwuid_prefix)) != nullptr) {
- used_getpwuid = uid_name + 1;
- uid_name += strlen(getpwuid_prefix);
- while (isdigit(*uid_name)) ++uid_name;
- used_getpwuid_len = uid_name - used_getpwuid;
- if (isspace(*uid_name)) break;
- used_getpwuid = nullptr;
- }
- EXPECT_TRUE(nullptr == used_getpwuid);
- if (used_getpwuid) {
- fprintf(stderr, "libpackagelistparser failed to pick up %.*s\n",
- used_getpwuid_len, used_getpwuid);
- }
-
- delete[] buf;
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif
-
-#ifdef __ANDROID__
-static void caught_signal(int /* signum */) {
-}
-
-static void dump_log_msg(const char* prefix, log_msg* msg, int lid) {
- std::cout << std::flush;
- std::cerr << std::flush;
- fflush(stdout);
- fflush(stderr);
- EXPECT_GE(msg->entry.hdr_size, sizeof(logger_entry));
-
- fprintf(stderr, "%s: [%u] ", prefix, msg->len());
- fprintf(stderr, "hdr_size=%u ", msg->entry.hdr_size);
- fprintf(stderr, "pid=%u tid=%u %u.%09u ", msg->entry.pid, msg->entry.tid, msg->entry.sec,
- msg->entry.nsec);
- lid = msg->entry.lid;
-
- switch (lid) {
- case 0:
- fprintf(stderr, "lid=main ");
- break;
- case 1:
- fprintf(stderr, "lid=radio ");
- break;
- case 2:
- fprintf(stderr, "lid=events ");
- break;
- case 3:
- fprintf(stderr, "lid=system ");
- break;
- case 4:
- fprintf(stderr, "lid=crash ");
- break;
- case 5:
- fprintf(stderr, "lid=security ");
- break;
- case 6:
- fprintf(stderr, "lid=kernel ");
- break;
- default:
- if (lid >= 0) {
- fprintf(stderr, "lid=%d ", lid);
- }
- }
-
- unsigned int len = msg->entry.len;
- fprintf(stderr, "msg[%u]={", len);
- unsigned char* cp = reinterpret_cast<unsigned char*>(msg->msg());
- if (!cp) {
- static const unsigned char garbage[] = "<INVALID>";
- cp = const_cast<unsigned char*>(garbage);
- len = strlen(reinterpret_cast<const char*>(garbage));
- }
- while (len) {
- unsigned char* p = cp;
- while (*p && (((' ' <= *p) && (*p < 0x7F)) || (*p == '\n'))) {
- ++p;
- }
- if (((p - cp) > 3) && !*p && ((unsigned int)(p - cp) < len)) {
- fprintf(stderr, "\"");
- while (*cp) {
- if (*cp != '\n') {
- fprintf(stderr, "%c", *cp);
- } else {
- fprintf(stderr, "\\n");
- }
- ++cp;
- --len;
- }
- fprintf(stderr, "\"");
- } else {
- fprintf(stderr, "%02x", *cp);
- }
- ++cp;
- if (--len) {
- fprintf(stderr, ", ");
- }
- }
- fprintf(stderr, "}\n");
- fflush(stderr);
-}
-#endif
-
-#ifdef __ANDROID__
-// BAD ROBOT
-// Benchmark threshold are generally considered bad form unless there is
-// is some human love applied to the continued maintenance and whether the
-// thresholds are tuned on a per-target basis. Here we check if the values
-// are more than double what is expected. Doubling will not prevent failure
-// on busy or low-end systems that could have a tendency to stretch values.
-//
-// The primary goal of this test is to simulate a spammy app (benchmark
-// being the worst) and check to make sure the logger can deal with it
-// appropriately by checking all the statistics are in an expected range.
-//
-TEST(logd, benchmark) {
- size_t len;
- char* buf;
-
- alloc_statistics(&buf, &len);
- bool benchmark_already_run = buf && find_benchmark_spam(buf);
- delete[] buf;
-
- if (benchmark_already_run) {
- fprintf(stderr,
- "WARNING: spam already present and too much history\n"
- " false OK for prune by worst UID check\n");
- }
-
- FILE* fp;
-
- // Introduce some extreme spam for the worst UID filter
- ASSERT_TRUE(
- nullptr !=
- (fp = popen("/data/nativetest/liblog-benchmarks/liblog-benchmarks"
- " BM_log_maximum_retry"
- " BM_log_maximum"
- " BM_clock_overhead"
- " BM_log_print_overhead"
- " BM_log_latency"
- " BM_log_delay",
- "r")));
-
- char buffer[5120];
-
- static const char* benchmarks[] = {
- "BM_log_maximum_retry ", "BM_log_maximum ", "BM_clock_overhead ",
- "BM_log_print_overhead ", "BM_log_latency ", "BM_log_delay "
- };
- static const unsigned int log_maximum_retry = 0;
- static const unsigned int log_maximum = 1;
- static const unsigned int clock_overhead = 2;
- static const unsigned int log_print_overhead = 3;
- static const unsigned int log_latency = 4;
- static const unsigned int log_delay = 5;
-
- unsigned long ns[arraysize(benchmarks)];
-
- memset(ns, 0, sizeof(ns));
-
- while (fgets(buffer, sizeof(buffer), fp)) {
- for (unsigned i = 0; i < arraysize(ns); ++i) {
- char* cp = strstr(buffer, benchmarks[i]);
- if (!cp) {
- continue;
- }
- sscanf(cp, "%*s %lu %lu", &ns[i], &ns[i]);
- fprintf(stderr, "%-22s%8lu\n", benchmarks[i], ns[i]);
- }
- }
- int ret = pclose(fp);
-
- if (!WIFEXITED(ret) || (WEXITSTATUS(ret) == 127)) {
- fprintf(stderr,
- "WARNING: "
- "/data/nativetest/liblog-benchmarks/liblog-benchmarks missing\n"
- " can not perform test\n");
- return;
- }
-
- EXPECT_GE(200000UL, ns[log_maximum_retry]); // 104734 user
- EXPECT_NE(0UL, ns[log_maximum_retry]); // failure to parse
-
- EXPECT_GE(90000UL, ns[log_maximum]); // 46913 user
- EXPECT_NE(0UL, ns[log_maximum]); // failure to parse
-
- EXPECT_GE(4096UL, ns[clock_overhead]); // 4095
- EXPECT_NE(0UL, ns[clock_overhead]); // failure to parse
-
- EXPECT_GE(250000UL, ns[log_print_overhead]); // 126886 user
- EXPECT_NE(0UL, ns[log_print_overhead]); // failure to parse
-
- EXPECT_GE(10000000UL,
- ns[log_latency]); // 1453559 user space (background cgroup)
- EXPECT_NE(0UL, ns[log_latency]); // failure to parse
-
- EXPECT_GE(20000000UL, ns[log_delay]); // 10500289 user
- EXPECT_NE(0UL, ns[log_delay]); // failure to parse
-
- alloc_statistics(&buf, &len);
-
- bool collected_statistics = !!buf;
- EXPECT_EQ(true, collected_statistics);
-
- ASSERT_TRUE(nullptr != buf);
-
- char* benchmark_statistics_found = find_benchmark_spam(buf);
- ASSERT_TRUE(benchmark_statistics_found != nullptr);
-
- // Check how effective the SPAM filter is, parse out Now size.
- // 0 root 54164 147569
- // ^-- benchmark_statistics_found
-
- unsigned long nowSpamSize = atol(benchmark_statistics_found);
-
- delete[] buf;
-
- ASSERT_NE(0UL, nowSpamSize);
-
- // Determine if we have the spam filter enabled
- int sock = socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
-
- ASSERT_TRUE(sock >= 0);
-
- static const char getPruneList[] = "getPruneList";
- if (write(sock, getPruneList, sizeof(getPruneList)) > 0) {
- char buffer[80];
- memset(buffer, 0, sizeof(buffer));
- read(sock, buffer, sizeof(buffer));
- char* cp = strchr(buffer, '\n');
- if (!cp || (cp[1] != '~') || (cp[2] != '!')) {
- close(sock);
- fprintf(stderr,
- "WARNING: "
- "Logger has SPAM filtration turned off \"%s\"\n",
- buffer);
- return;
- }
- } else {
- int save_errno = errno;
- close(sock);
- FAIL() << "Can not send " << getPruneList << " to logger -- "
- << strerror(save_errno);
- }
-
- static const unsigned long expected_absolute_minimum_log_size = 65536UL;
- unsigned long totalSize = expected_absolute_minimum_log_size;
- static const char getSize[] = { 'g', 'e', 't', 'L', 'o', 'g',
- 'S', 'i', 'z', 'e', ' ', LOG_ID_MAIN + '0',
- '\0' };
- if (write(sock, getSize, sizeof(getSize)) > 0) {
- char buffer[80];
- memset(buffer, 0, sizeof(buffer));
- read(sock, buffer, sizeof(buffer));
- totalSize = atol(buffer);
- if (totalSize < expected_absolute_minimum_log_size) {
- fprintf(stderr,
- "WARNING: "
- "Logger had unexpected referenced size \"%s\"\n",
- buffer);
- totalSize = expected_absolute_minimum_log_size;
- }
- }
- close(sock);
-
- // logd allows excursions to 110% of total size
- totalSize = (totalSize * 11) / 10;
-
- // 50% threshold for SPAM filter (<20% typical, lots of engineering margin)
- ASSERT_GT(totalSize, nowSpamSize * 2);
-}
-#endif
-
-// b/26447386 confirm fixed
-void timeout_negative(const char* command) {
-#ifdef __ANDROID__
- log_msg msg_wrap, msg_timeout;
- bool content_wrap = false, content_timeout = false, written = false;
- unsigned int alarm_wrap = 0, alarm_timeout = 0;
- // A few tries to get it right just in case wrap kicks in due to
- // content providers being active during the test.
- int i = 3;
-
- while (--i) {
- int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
- ASSERT_LT(0, fd);
-
- std::string ask(command);
-
- struct sigaction ignore, old_sigaction;
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- sigaction(SIGALRM, &ignore, &old_sigaction);
- unsigned int old_alarm = alarm(3);
-
- size_t len = ask.length() + 1;
- written = write(fd, ask.c_str(), len) == (ssize_t)len;
- if (!written) {
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
- close(fd);
- continue;
- }
-
- // alarm triggers at 50% of the --wrap time out
- content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
-
- alarm_wrap = alarm(5);
-
- // alarm triggers at 133% of the --wrap time out
- content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- if (!content_timeout) { // make sure we hit dumpAndClose
- content_timeout =
- recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- }
-
- if (old_alarm > 0) {
- unsigned int time_spent = 3 - alarm_wrap;
- if (old_alarm > time_spent + 1) {
- old_alarm -= time_spent;
- } else {
- old_alarm = 2;
- }
- }
- alarm_timeout = alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
-
- close(fd);
-
- if (content_wrap && alarm_wrap && content_timeout && alarm_timeout) {
- break;
- }
- }
-
- if (content_wrap) {
- dump_log_msg("wrap", &msg_wrap, -1);
- }
-
- if (content_timeout) {
- dump_log_msg("timeout", &msg_timeout, -1);
- }
-
- EXPECT_TRUE(written);
- EXPECT_TRUE(content_wrap);
- EXPECT_NE(0U, alarm_wrap);
- EXPECT_TRUE(content_timeout);
- EXPECT_NE(0U, alarm_timeout);
-#else
- command = nullptr;
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, timeout_no_start) {
- timeout_negative("dumpAndClose lids=0,1,2,3,4,5 timeout=6");
-}
-
-TEST(logd, timeout_start_epoch) {
- timeout_negative(
- "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=0.000000000");
-}
-
-#ifdef ENABLE_FLAKY_TESTS
-// b/26447386 refined behavior
-TEST(logd, timeout) {
-#ifdef __ANDROID__
- // b/33962045 This test interferes with other log reader tests that
- // follow because of file descriptor socket persistence in the same
- // process. So let's fork it to isolate it from giving us pain.
-
- pid_t pid = fork();
-
- if (pid) {
- siginfo_t info = {};
- ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
- ASSERT_EQ(0, info.si_status);
- return;
- }
-
- log_msg msg_wrap, msg_timeout;
- bool content_wrap = false, content_timeout = false, written = false;
- unsigned int alarm_wrap = 0, alarm_timeout = 0;
- // A few tries to get it right just in case wrap kicks in due to
- // content providers being active during the test.
- int i = 5;
- log_time start(CLOCK_REALTIME);
- start.tv_sec -= 30; // reach back a moderate period of time
-
- while (--i) {
- int fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET);
- int save_errno = errno;
- if (fd < 0) {
- fprintf(stderr, "failed to open /dev/socket/logdr %s\n",
- strerror(save_errno));
- _exit(fd);
- }
-
- std::string ask = android::base::StringPrintf(
- "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%" PRIu32
- ".%09" PRIu32,
- start.tv_sec, start.tv_nsec);
-
- struct sigaction ignore, old_sigaction;
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- sigaction(SIGALRM, &ignore, &old_sigaction);
- unsigned int old_alarm = alarm(3);
-
- size_t len = ask.length() + 1;
- written = write(fd, ask.c_str(), len) == (ssize_t)len;
- if (!written) {
- alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
- close(fd);
- continue;
- }
-
- // alarm triggers at 50% of the --wrap time out
- content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
-
- alarm_wrap = alarm(5);
-
- // alarm triggers at 133% of the --wrap time out
- content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- if (!content_timeout) { // make sure we hit dumpAndClose
- content_timeout =
- recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
- }
-
- if (old_alarm > 0) {
- unsigned int time_spent = 3 - alarm_wrap;
- if (old_alarm > time_spent + 1) {
- old_alarm -= time_spent;
- } else {
- old_alarm = 2;
- }
- }
- alarm_timeout = alarm(old_alarm);
- sigaction(SIGALRM, &old_sigaction, nullptr);
-
- close(fd);
-
- if (!content_wrap && !alarm_wrap && content_timeout && alarm_timeout) {
- break;
- }
-
- // modify start time in case content providers are relatively
- // active _or_ inactive during the test.
- if (content_timeout) {
- log_time msg(msg_timeout.entry.sec, msg_timeout.entry.nsec);
- if (msg < start) {
- fprintf(stderr, "%u.%09u < %u.%09u\n", msg_timeout.entry.sec,
- msg_timeout.entry.nsec, (unsigned)start.tv_sec,
- (unsigned)start.tv_nsec);
- _exit(-1);
- }
- if (msg > start) {
- start = msg;
- start.tv_sec += 30;
- log_time now = log_time(CLOCK_REALTIME);
- if (start > now) {
- start = now;
- --start.tv_sec;
- }
- }
- } else {
- start.tv_sec -= 120; // inactive, reach further back!
- }
- }
-
- if (content_wrap) {
- dump_log_msg("wrap", &msg_wrap, -1);
- }
-
- if (content_timeout) {
- dump_log_msg("timeout", &msg_timeout, -1);
- }
-
- if (content_wrap || !content_timeout) {
- fprintf(stderr, "start=%" PRIu32 ".%09" PRIu32 "\n", start.tv_sec,
- start.tv_nsec);
- }
-
- EXPECT_TRUE(written);
- EXPECT_FALSE(content_wrap);
- EXPECT_EQ(0U, alarm_wrap);
- EXPECT_TRUE(content_timeout);
- EXPECT_NE(0U, alarm_timeout);
-
- _exit(!written + content_wrap + alarm_wrap + !content_timeout +
- !alarm_timeout);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif
-
-#ifdef LOGD_ENABLE_FLAKY_TESTS
-// b/27242723 confirmed fixed
-TEST(logd, SNDTIMEO) {
-#ifdef __ANDROID__
- static const unsigned sndtimeo =
- LOGD_SNDTIMEO; // <sigh> it has to be done!
- static const unsigned sleep_time = sndtimeo + 3;
- static const unsigned alarm_time = sleep_time + 5;
-
- int fd;
-
- ASSERT_TRUE(
- (fd = socket_local_client("logdr", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_SEQPACKET)) > 0);
-
- struct sigaction ignore, old_sigaction;
- memset(&ignore, 0, sizeof(ignore));
- ignore.sa_handler = caught_signal;
- sigemptyset(&ignore.sa_mask);
- sigaction(SIGALRM, &ignore, &old_sigaction);
- unsigned int old_alarm = alarm(alarm_time);
-
- static const char ask[] = "stream lids=0,1,2,3,4,5,6"; // all sources
- bool reader_requested = write(fd, ask, sizeof(ask)) == sizeof(ask);
- EXPECT_TRUE(reader_requested);
-
- log_msg msg;
- bool read_one = recv(fd, msg.buf, sizeof(msg), 0) > 0;
-
- EXPECT_TRUE(read_one);
- if (read_one) {
- dump_log_msg("user", &msg, -1);
- }
-
- fprintf(stderr, "Sleep for >%d seconds logd SO_SNDTIMEO ...\n", sndtimeo);
- sleep(sleep_time);
-
- // flush will block if we did not trigger. if it did, last entry returns 0
- int recv_ret;
- do {
- recv_ret = recv(fd, msg.buf, sizeof(msg), 0);
- } while (recv_ret > 0);
- int save_errno = (recv_ret < 0) ? errno : 0;
-
- EXPECT_NE(0U, alarm(old_alarm));
- sigaction(SIGALRM, &old_sigaction, nullptr);
-
- EXPECT_EQ(0, recv_ret);
- if (recv_ret > 0) {
- dump_log_msg("user", &msg, -1);
- }
- EXPECT_EQ(0, save_errno);
-
- close(fd);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-#endif
-
-TEST(logd, getEventTag_list) {
-#ifdef __ANDROID__
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "getEventTag name=*");
- send_to_control(buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- char* cp;
- long ret = strtol(buffer, &cp, 10);
- EXPECT_GT(ret, 4096);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, getEventTag_42) {
-#ifdef __ANDROID__
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- snprintf(buffer, sizeof(buffer), "getEventTag id=42");
- send_to_control(buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- char* cp;
- long ret = strtol(buffer, &cp, 10);
- EXPECT_GT(ret, 16);
- EXPECT_TRUE(strstr(buffer, "\t(to life the universe etc|3)") != nullptr);
- EXPECT_TRUE(strstr(buffer, "answer") != nullptr);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, getEventTag_newentry) {
-#ifdef __ANDROID__
- char buffer[256];
- memset(buffer, 0, sizeof(buffer));
- log_time now(CLOCK_MONOTONIC);
- char name[64];
- snprintf(name, sizeof(name), "a%" PRIu64, now.nsec());
- snprintf(buffer, sizeof(buffer), "getEventTag name=%s format=\"(new|1)\"",
- name);
- send_to_control(buffer, sizeof(buffer));
- buffer[sizeof(buffer) - 1] = '\0';
- char* cp;
- long ret = strtol(buffer, &cp, 10);
- EXPECT_GT(ret, 16);
- EXPECT_TRUE(strstr(buffer, "\t(new|1)") != nullptr);
- EXPECT_TRUE(strstr(buffer, name) != nullptr);
-// ToDo: also look for this in /data/misc/logd/event-log-tags and
-// /dev/event-log-tags.
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
-
-TEST(logd, no_epipe) {
-#ifdef __ANDROID__
- // Actually generating SIGPIPE in logd is racy, since we need to close the socket quicker than
- // logd finishes writing the data to it, so we try 10 times, which should be enough to trigger
- // SIGPIPE if logd isn't ignoring SIGPIPE
- for (int i = 0; i < 10; ++i) {
- unique_fd sock1(
- socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
- ASSERT_GT(sock1, 0);
- unique_fd sock2(
- socket_local_client("logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
- ASSERT_GT(sock2, 0);
-
- std::string message = "getStatistics 0 1 2 3 4 5 6 7";
-
- ASSERT_GT(write(sock1, message.c_str(), message.length()), 0);
- sock1.reset();
- ASSERT_GT(write(sock2, message.c_str(), message.length()), 0);
-
- struct pollfd p = {.fd = sock2, .events = POLLIN, .revents = 0};
-
- int ret = poll(&p, 1, 20);
- EXPECT_EQ(ret, 1);
- EXPECT_TRUE(p.revents & POLLIN);
- EXPECT_FALSE(p.revents & POLL_ERR);
- }
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/logd/logtagd.rc b/logd/logtagd.rc
deleted file mode 100644
index 248a78c..0000000
--- a/logd/logtagd.rc
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# logtagd event log tag service (debug only)
-#
-on post-fs-data
- mkdir /data/misc/logd 0750 logd log
- write /data/misc/logd/event-log-tags ""
- chown logd log /data/misc/logd/event-log-tags
- chmod 0600 /data/misc/logd/event-log-tags
- restorecon /data/misc/logd/event-log-tags
diff --git a/logd/main.cpp b/logd/main.cpp
deleted file mode 100644
index c92c5b7..0000000
--- a/logd/main.cpp
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2012-2013 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 <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/capability.h>
-#include <poll.h>
-#include <sched.h>
-#include <semaphore.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/capability.h>
-#include <sys/klog.h>
-#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include <memory>
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <cutils/android_get_control_file.h>
-#include <cutils/sockets.h>
-#include <log/event_tag_map.h>
-#include <packagelistparser/packagelistparser.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#include <processgroup/sched_policy.h>
-#include <utils/threads.h>
-
-#include "ChattyLogBuffer.h"
-#include "CommandListener.h"
-#include "LogAudit.h"
-#include "LogBuffer.h"
-#include "LogKlog.h"
-#include "LogListener.h"
-#include "LogReader.h"
-#include "LogStatistics.h"
-#include "LogTags.h"
-#include "LogUtils.h"
-#include "SerializedLogBuffer.h"
-#include "SimpleLogBuffer.h"
-
-using android::base::GetBoolProperty;
-using android::base::GetProperty;
-using android::base::SetProperty;
-
-#define KMSG_PRIORITY(PRI) \
- '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \
- '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) % 10, '>'
-
-// The service is designed to be run by init, it does not respond well to starting up manually. Init
-// has a 'sigstop' feature that sends SIGSTOP to a service immediately before calling exec(). This
-// allows debuggers, etc to be attached to logd at the very beginning, while still having init
-// handle the user, groups, capabilities, files, etc setup.
-static void DropPrivs(bool klogd, bool auditd) {
- if (set_sched_policy(0, SP_BACKGROUND) < 0) {
- PLOG(FATAL) << "failed to set background scheduling policy";
- }
-
- sched_param param = {};
- if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
- PLOG(FATAL) << "failed to set batch scheduler";
- }
-
- if (!GetBoolProperty("ro.debuggable", false)) {
- if (prctl(PR_SET_DUMPABLE, 0) == -1) {
- PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE";
- }
- }
-
- std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(), cap_free);
- if (cap_clear(caps.get()) < 0) {
- PLOG(FATAL) << "cap_clear() failed";
- }
- if (klogd) {
- cap_value_t cap_syslog = CAP_SYSLOG;
- if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, &cap_syslog, CAP_SET) < 0 ||
- cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, &cap_syslog, CAP_SET) < 0) {
- PLOG(FATAL) << "Failed to set CAP_SYSLOG";
- }
- }
- if (auditd) {
- cap_value_t cap_audit_control = CAP_AUDIT_CONTROL;
- if (cap_set_flag(caps.get(), CAP_PERMITTED, 1, &cap_audit_control, CAP_SET) < 0 ||
- cap_set_flag(caps.get(), CAP_EFFECTIVE, 1, &cap_audit_control, CAP_SET) < 0) {
- PLOG(FATAL) << "Failed to set CAP_AUDIT_CONTROL";
- }
- }
- if (cap_set_proc(caps.get()) < 0) {
- PLOG(FATAL) << "cap_set_proc() failed";
- }
-}
-
-// GetBoolProperty that defaults to true if `ro.debuggable == true && ro.config.low_rawm == false`.
-static bool GetBoolPropertyEngSvelteDefault(const std::string& name) {
- bool default_value =
- GetBoolProperty("ro.debuggable", false) && !GetBoolProperty("ro.config.low_ram", false);
-
- return GetBoolProperty(name, default_value);
-}
-
-char* android::uidToName(uid_t u) {
- struct Userdata {
- uid_t uid;
- char* name;
- } userdata = {
- .uid = u,
- .name = nullptr,
- };
-
- packagelist_parse(
- [](pkg_info* info, void* callback_parameter) {
- auto userdata = reinterpret_cast<Userdata*>(callback_parameter);
- bool result = true;
- if (info->uid == userdata->uid) {
- userdata->name = strdup(info->name);
- // false to stop processing
- result = false;
- }
- packagelist_free(info);
- return result;
- },
- &userdata);
-
- return userdata.name;
-}
-
-static void readDmesg(LogAudit* al, LogKlog* kl) {
- if (!al && !kl) {
- return;
- }
-
- int rc = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
- if (rc <= 0) {
- return;
- }
-
- // Margin for additional input race or trailing nul
- ssize_t len = rc + 1024;
- std::unique_ptr<char[]> buf(new char[len]);
-
- rc = klogctl(KLOG_READ_ALL, buf.get(), len);
- if (rc <= 0) {
- return;
- }
-
- if (rc < len) {
- len = rc + 1;
- }
- buf[--len] = '\0';
-
- ssize_t sublen;
- for (char *ptr = nullptr, *tok = buf.get();
- (rc >= 0) && !!(tok = android::log_strntok_r(tok, len, ptr, sublen));
- tok = nullptr) {
- if ((sublen <= 0) || !*tok) continue;
- if (al) {
- rc = al->log(tok, sublen);
- }
- if (kl) {
- rc = kl->log(tok, sublen);
- }
- }
-}
-
-static int issueReinit() {
- int sock = TEMP_FAILURE_RETRY(socket_local_client(
- "logd", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM));
- if (sock < 0) return -errno;
-
- static const char reinitStr[] = "reinit";
- ssize_t ret = TEMP_FAILURE_RETRY(write(sock, reinitStr, sizeof(reinitStr)));
- if (ret < 0) return -errno;
-
- struct pollfd p;
- memset(&p, 0, sizeof(p));
- p.fd = sock;
- p.events = POLLIN;
- ret = TEMP_FAILURE_RETRY(poll(&p, 1, 1000));
- if (ret < 0) return -errno;
- if ((ret == 0) || !(p.revents & POLLIN)) return -ETIME;
-
- static const char success[] = "success";
- char buffer[sizeof(success) - 1];
- memset(buffer, 0, sizeof(buffer));
- ret = TEMP_FAILURE_RETRY(read(sock, buffer, sizeof(buffer)));
- if (ret < 0) return -errno;
-
- return strncmp(buffer, success, sizeof(success) - 1) != 0;
-}
-
-// Foreground waits for exit of the main persistent threads
-// that are started here. The threads are created to manage
-// UNIX domain client sockets for writing, reading and
-// controlling the user space logger, and for any additional
-// logging plugins like auditd and restart control. Additional
-// transitory per-client threads are created for each reader.
-int main(int argc, char* argv[]) {
- // We want EPIPE when a reader disconnects, not to terminate logd.
- signal(SIGPIPE, SIG_IGN);
- // logd is written under the assumption that the timezone is UTC.
- // If TZ is not set, persist.sys.timezone is looked up in some time utility
- // libc functions, including mktime. It confuses the logd time handling,
- // so here explicitly set TZ to UTC, which overrides the property.
- setenv("TZ", "UTC", 1);
- // issue reinit command. KISS argument parsing.
- if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
- return issueReinit();
- }
-
- android::base::InitLogging(
- argv, [](android::base::LogId log_id, android::base::LogSeverity severity,
- const char* tag, const char* file, unsigned int line, const char* message) {
- if (tag && strcmp(tag, "logd") != 0) {
- auto prefixed_message = android::base::StringPrintf("%s: %s", tag, message);
- android::base::KernelLogger(log_id, severity, "logd", file, line,
- prefixed_message.c_str());
- } else {
- android::base::KernelLogger(log_id, severity, "logd", file, line, message);
- }
- });
-
- static const char dev_kmsg[] = "/dev/kmsg";
- int fdDmesg = android_get_control_file(dev_kmsg);
- if (fdDmesg < 0) {
- fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
- }
-
- int fdPmesg = -1;
- bool klogd = GetBoolPropertyEngSvelteDefault("ro.logd.kernel");
- if (klogd) {
- SetProperty("ro.logd.kernel", "true");
- static const char proc_kmsg[] = "/proc/kmsg";
- fdPmesg = android_get_control_file(proc_kmsg);
- if (fdPmesg < 0) {
- fdPmesg = TEMP_FAILURE_RETRY(
- open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
- }
- if (fdPmesg < 0) PLOG(ERROR) << "Failed to open " << proc_kmsg;
- }
-
- bool auditd = GetBoolProperty("ro.logd.auditd", true);
- DropPrivs(klogd, auditd);
-
- // A cache of event log tags
- LogTags log_tags;
-
- // Pruning configuration.
- PruneList prune_list;
-
- std::string buffer_type = GetProperty("logd.buffer_type", "serialized");
-
- // Partial (required for chatty) or full logging statistics.
- LogStatistics log_statistics(GetBoolPropertyEngSvelteDefault("logd.statistics"),
- buffer_type == "serialized");
-
- // Serves the purpose of managing the last logs times read on a socket connection, and as a
- // reader lock on a range of log entries.
- LogReaderList reader_list;
-
- // LogBuffer is the object which is responsible for holding all log entries.
- LogBuffer* log_buffer = nullptr;
- if (buffer_type == "chatty") {
- log_buffer = new ChattyLogBuffer(&reader_list, &log_tags, &prune_list, &log_statistics);
- } else if (buffer_type == "serialized") {
- log_buffer = new SerializedLogBuffer(&reader_list, &log_tags, &log_statistics);
- } else if (buffer_type == "simple") {
- log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);
- } else {
- LOG(FATAL) << "buffer_type must be one of 'chatty', 'serialized', or 'simple'";
- }
-
- // LogReader listens on /dev/socket/logdr. When a client
- // connects, log entries in the LogBuffer are written to the client.
- LogReader* reader = new LogReader(log_buffer, &reader_list);
- if (reader->startListener()) {
- return EXIT_FAILURE;
- }
-
- // LogListener listens on /dev/socket/logdw for client
- // initiated log messages. New log entries are added to LogBuffer
- // and LogReader is notified to send updates to connected clients.
- LogListener* swl = new LogListener(log_buffer);
- if (!swl->StartListener()) {
- return EXIT_FAILURE;
- }
-
- // Command listener listens on /dev/socket/logd for incoming logd
- // administrative commands.
- CommandListener* cl = new CommandListener(log_buffer, &log_tags, &prune_list, &log_statistics);
- if (cl->startListener()) {
- return EXIT_FAILURE;
- }
-
- // LogAudit listens on NETLINK_AUDIT socket for selinux
- // initiated log messages. New log entries are added to LogBuffer
- // and LogReader is notified to send updates to connected clients.
- LogAudit* al = nullptr;
- if (auditd) {
- int dmesg_fd = GetBoolProperty("ro.logd.auditd.dmesg", true) ? fdDmesg : -1;
- al = new LogAudit(log_buffer, dmesg_fd, &log_statistics);
- }
-
- LogKlog* kl = nullptr;
- if (klogd) {
- kl = new LogKlog(log_buffer, fdDmesg, fdPmesg, al != nullptr, &log_statistics);
- }
-
- readDmesg(al, kl);
-
- // failure is an option ... messages are in dmesg (required by standard)
- if (kl && kl->startListener()) {
- delete kl;
- }
-
- if (al && al->startListener()) {
- delete al;
- }
-
- TEMP_FAILURE_RETRY(pause());
-
- return EXIT_SUCCESS;
-}
diff --git a/logd/rwlock.h b/logd/rwlock.h
deleted file mode 100644
index c37721e..0000000
--- a/logd/rwlock.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2020 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/LICENSE2.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.
- */
-
-#pragma once
-
-#include <pthread.h>
-
-#include <android-base/macros.h>
-#include <android-base/thread_annotations.h>
-
-// As of the end of May 2020, std::shared_mutex is *not* simply a pthread_rwlock, but rather a
-// combination of std::mutex and std::condition variable, which is obviously less efficient. This
-// immitates what std::shared_mutex should be doing and is compatible with RAII thread wrappers.
-
-class SHARED_CAPABILITY("mutex") RwLock {
- public:
- RwLock() {}
- ~RwLock() {}
-
- void lock() ACQUIRE() { pthread_rwlock_wrlock(&rwlock_); }
- void lock_shared() ACQUIRE_SHARED() { pthread_rwlock_rdlock(&rwlock_); }
-
- void unlock() RELEASE() { pthread_rwlock_unlock(&rwlock_); }
-
- private:
- pthread_rwlock_t rwlock_ = PTHREAD_RWLOCK_INITIALIZER;
-};
-
-// std::shared_lock does not have thread annotations, so we need our own.
-
-class SCOPED_CAPABILITY SharedLock {
- public:
- explicit SharedLock(RwLock& lock) ACQUIRE_SHARED(lock) : lock_(lock) { lock_.lock_shared(); }
- ~SharedLock() RELEASE() { lock_.unlock(); }
-
- void lock_shared() ACQUIRE_SHARED() { lock_.lock_shared(); }
- void unlock() RELEASE() { lock_.unlock(); }
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(SharedLock);
-
- private:
- RwLock& lock_;
-};
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
deleted file mode 100644
index 8851a47..0000000
--- a/logwrapper/Android.bp
+++ /dev/null
@@ -1,70 +0,0 @@
-cc_defaults {
- name: "logwrapper_defaults",
- cflags: [
- "-Werror",
- ],
-}
-
-// ========================================================
-// Static and shared library
-// ========================================================
-
-cc_library {
- name: "liblogwrap",
- defaults: ["logwrapper_defaults"],
- recovery_available: true,
- srcs: ["logwrap.cpp"],
- shared_libs: [
- "libcutils",
- "liblog",
- ],
- header_libs: ["libbase_headers"],
- export_include_dirs: ["include"],
- local_include_dirs: ["include"],
-}
-
-// ========================================================
-// Executable
-// ========================================================
-
-cc_defaults {
- name: "logwrapper_common",
- defaults: ["logwrapper_defaults"],
- local_include_dirs: ["include"],
- srcs: [
- "logwrap.cpp",
- "logwrapper.cpp",
- ],
- header_libs: ["libbase_headers"],
- shared_libs: ["libcutils", "liblog"],
-}
-
-cc_binary {
- name: "logwrapper",
- defaults: ["logwrapper_common"],
-}
-
-cc_binary {
- name: "logwrapper_vendor",
- defaults: ["logwrapper_common"],
- stem: "logwrapper",
- vendor: true,
-}
-
-// ========================================================
-// Benchmark
-// ========================================================
-
-cc_benchmark {
- name: "logwrap_fork_execvp_benchmark",
- defaults: ["logwrapper_defaults"],
- srcs: [
- "logwrap_fork_execvp_benchmark.cpp",
- ],
- shared_libs: [
- "libbase",
- "libcutils",
- "liblog",
- "liblogwrap",
- ],
-}
diff --git a/logwrapper/NOTICE b/logwrapper/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/logwrapper/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
- Copyright (c) 2005-2008, 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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/logwrapper/OWNERS b/logwrapper/OWNERS
deleted file mode 100644
index babbe4d..0000000
--- a/logwrapper/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tomcherry@google.com
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
deleted file mode 100644
index cb40ee2..0000000
--- a/logwrapper/include/logwrap/logwrap.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* system/core/include/logwrap/logwrap.h
- *
- * Copyright 2013, 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.
- */
-
-#pragma once
-
-/*
- * Run a command while logging its stdout and stderr
- *
- * Arguments:
- * argc: the number of elements in argv
- * argv: an array of strings containing the command to be executed and its
- * arguments as separate strings. argv does not need to be
- * NULL-terminated
- * status: the equivalent child status as populated by wait(status). This
- * value is only valid when logwrap successfully completes. If NULL
- * the return value of the child will be the function's return value.
- * forward_signals: set to true if you want to forward SIGINT, SIGQUIT, and
- * SIGHUP to the child process, while it is running. You likely do
- * not need to use this; it is primarily for the logwrapper
- * executable itself.
- * log_target: Specify where to log the output of the child, either LOG_NONE,
- * LOG_ALOG (for the Android system log), LOG_KLOG (for the kernel
- * log), or LOG_FILE (and you need to specify a pathname in the
- * file_path argument, otherwise pass NULL). These are bit fields,
- * and can be OR'ed together to log to multiple places.
- * abbreviated: If true, capture up to the first 100 lines and last 4K of
- * output from the child. The abbreviated output is not dumped to
- * the specified log until the child has exited.
- * file_path: if log_target has the LOG_FILE bit set, then this parameter
- * must be set to the pathname of the file to log to.
- *
- * Return value:
- * 0 when logwrap successfully run the child process and captured its status
- * -1 when an internal error occurred
- * -ECHILD if status is NULL and the child didn't exit properly
- * the return value of the child if it exited properly and status is NULL
- *
- */
-
-/* Values for the log_target parameter logwrap_fork_execvp() */
-#define LOG_NONE 0
-#define LOG_ALOG 1
-#define LOG_KLOG 2
-#define LOG_FILE 4
-
-int logwrap_fork_execvp(int argc, const char* const* argv, int* status, bool forward_signals,
- int log_target, bool abbreviated, const char* file_path);
diff --git a/logwrapper/logwrap.cpp b/logwrapper/logwrap.cpp
deleted file mode 100644
index 5a518bc..0000000
--- a/logwrapper/logwrap.cpp
+++ /dev/null
@@ -1,615 +0,0 @@
-/*
- * Copyright (C) 2008 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 <errno.h>
-#include <fcntl.h>
-#include <libgen.h>
-#include <poll.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <algorithm>
-
-#include <android-base/macros.h>
-#include <cutils/klog.h>
-#include <log/log.h>
-#include <logwrap/logwrap.h>
-
-static pthread_mutex_t fd_mutex = PTHREAD_MUTEX_INITIALIZER;
-// Protected by fd_mutex. These signals must be blocked while modifying as well.
-static pid_t child_pid;
-static struct sigaction old_int;
-static struct sigaction old_quit;
-static struct sigaction old_hup;
-
-#define ERROR(fmt, args...) \
- do { \
- fprintf(stderr, fmt, ##args); \
- ALOG(LOG_ERROR, "logwrapper", fmt, ##args); \
- } while (0)
-
-#define FATAL_CHILD(fmt, args...) \
- do { \
- ERROR(fmt, ##args); \
- _exit(-1); \
- } while (0)
-
-#define MAX_KLOG_TAG 16
-
-/* This is a simple buffer that holds up to the first beginning_buf->buf_size
- * bytes of output from a command.
- */
-#define BEGINNING_BUF_SIZE 0x1000
-struct beginning_buf {
- char* buf;
- size_t alloc_len;
- /* buf_size is the usable space, which is one less than the allocated size */
- size_t buf_size;
- size_t used_len;
-};
-
-/* This is a circular buf that holds up to the last ending_buf->buf_size bytes
- * of output from a command after the first beginning_buf->buf_size bytes
- * (which are held in beginning_buf above).
- */
-#define ENDING_BUF_SIZE 0x1000
-struct ending_buf {
- char* buf;
- ssize_t alloc_len;
- /* buf_size is the usable space, which is one less than the allocated size */
- ssize_t buf_size;
- ssize_t used_len;
- /* read and write offsets into the circular buffer */
- int read;
- int write;
-};
-
-/* A structure to hold all the abbreviated buf data */
-struct abbr_buf {
- struct beginning_buf b_buf;
- struct ending_buf e_buf;
- int beginning_buf_full;
-};
-
-/* Collect all the various bits of info needed for logging in one place. */
-struct log_info {
- int log_target;
- char klog_fmt[MAX_KLOG_TAG * 2];
- const char* btag;
- bool abbreviated;
- FILE* fp;
- struct abbr_buf a_buf;
-};
-
-/* Forware declaration */
-static void add_line_to_abbr_buf(struct abbr_buf* a_buf, char* linebuf, int linelen);
-
-/* Return 0 on success, and 1 when full */
-static int add_line_to_linear_buf(struct beginning_buf* b_buf, char* line, ssize_t line_len) {
- int full = 0;
-
- if ((line_len + b_buf->used_len) > b_buf->buf_size) {
- full = 1;
- } else {
- /* Add to the end of the buf */
- memcpy(b_buf->buf + b_buf->used_len, line, line_len);
- b_buf->used_len += line_len;
- }
-
- return full;
-}
-
-static void add_line_to_circular_buf(struct ending_buf* e_buf, char* line, ssize_t line_len) {
- ssize_t free_len;
- ssize_t needed_space;
- int cnt;
-
- if (e_buf->buf == nullptr) {
- return;
- }
-
- if (line_len > e_buf->buf_size) {
- return;
- }
-
- free_len = e_buf->buf_size - e_buf->used_len;
-
- if (line_len > free_len) {
- /* remove oldest entries at read, and move read to make
- * room for the new string */
- needed_space = line_len - free_len;
- e_buf->read = (e_buf->read + needed_space) % e_buf->buf_size;
- e_buf->used_len -= needed_space;
- }
-
- /* Copy the line into the circular buffer, dealing with possible
- * wraparound.
- */
- cnt = std::min(line_len, e_buf->buf_size - e_buf->write);
- memcpy(e_buf->buf + e_buf->write, line, cnt);
- if (cnt < line_len) {
- memcpy(e_buf->buf, line + cnt, line_len - cnt);
- }
- e_buf->used_len += line_len;
- e_buf->write = (e_buf->write + line_len) % e_buf->buf_size;
-}
-
-/* Log directly to the specified log */
-static void do_log_line(struct log_info* log_info, const char* line) {
- if (log_info->log_target & LOG_KLOG) {
- klog_write(6, log_info->klog_fmt, line);
- }
- if (log_info->log_target & LOG_ALOG) {
- ALOG(LOG_INFO, log_info->btag, "%s", line);
- }
- if (log_info->log_target & LOG_FILE) {
- fprintf(log_info->fp, "%s\n", line);
- }
-}
-
-/* Log to either the abbreviated buf, or directly to the specified log
- * via do_log_line() above.
- */
-static void log_line(struct log_info* log_info, char* line, int len) {
- if (log_info->abbreviated) {
- add_line_to_abbr_buf(&log_info->a_buf, line, len);
- } else {
- do_log_line(log_info, line);
- }
-}
-
-/*
- * The kernel will take a maximum of 1024 bytes in any single write to
- * the kernel logging device file, so find and print each line one at
- * a time. The allocated size for buf should be at least 1 byte larger
- * than buf_size (the usable size of the buffer) to make sure there is
- * room to temporarily stuff a null byte to terminate a line for logging.
- */
-static void print_buf_lines(struct log_info* log_info, char* buf, int buf_size) {
- char* line_start;
- char c;
- int i;
-
- line_start = buf;
- for (i = 0; i < buf_size; i++) {
- if (*(buf + i) == '\n') {
- /* Found a line ending, print the line and compute new line_start */
- /* Save the next char and replace with \0 */
- c = *(buf + i + 1);
- *(buf + i + 1) = '\0';
- do_log_line(log_info, line_start);
- /* Restore the saved char */
- *(buf + i + 1) = c;
- line_start = buf + i + 1;
- } else if (*(buf + i) == '\0') {
- /* The end of the buffer, print the last bit */
- do_log_line(log_info, line_start);
- break;
- }
- }
- /* If the buffer was completely full, and didn't end with a newline, just
- * ignore the partial last line.
- */
-}
-
-static void init_abbr_buf(struct abbr_buf* a_buf) {
- char* new_buf;
-
- memset(a_buf, 0, sizeof(struct abbr_buf));
- new_buf = static_cast<char*>(malloc(BEGINNING_BUF_SIZE));
- if (new_buf) {
- a_buf->b_buf.buf = new_buf;
- a_buf->b_buf.alloc_len = BEGINNING_BUF_SIZE;
- a_buf->b_buf.buf_size = BEGINNING_BUF_SIZE - 1;
- }
- new_buf = static_cast<char*>(malloc(ENDING_BUF_SIZE));
- if (new_buf) {
- a_buf->e_buf.buf = new_buf;
- a_buf->e_buf.alloc_len = ENDING_BUF_SIZE;
- a_buf->e_buf.buf_size = ENDING_BUF_SIZE - 1;
- }
-}
-
-static void free_abbr_buf(struct abbr_buf* a_buf) {
- free(a_buf->b_buf.buf);
- free(a_buf->e_buf.buf);
-}
-
-static void add_line_to_abbr_buf(struct abbr_buf* a_buf, char* linebuf, int linelen) {
- if (!a_buf->beginning_buf_full) {
- a_buf->beginning_buf_full = add_line_to_linear_buf(&a_buf->b_buf, linebuf, linelen);
- }
- if (a_buf->beginning_buf_full) {
- add_line_to_circular_buf(&a_buf->e_buf, linebuf, linelen);
- }
-}
-
-static void print_abbr_buf(struct log_info* log_info) {
- struct abbr_buf* a_buf = &log_info->a_buf;
-
- /* Add the abbreviated output to the kernel log */
- if (a_buf->b_buf.alloc_len) {
- print_buf_lines(log_info, a_buf->b_buf.buf, a_buf->b_buf.used_len);
- }
-
- /* Print an ellipsis to indicate that the buffer has wrapped or
- * is full, and some data was not logged.
- */
- if (a_buf->e_buf.used_len == a_buf->e_buf.buf_size) {
- do_log_line(log_info, "...\n");
- }
-
- if (a_buf->e_buf.used_len == 0) {
- return;
- }
-
- /* Simplest way to print the circular buffer is allocate a second buf
- * of the same size, and memcpy it so it's a simple linear buffer,
- * and then cal print_buf_lines on it */
- if (a_buf->e_buf.read < a_buf->e_buf.write) {
- /* no wrap around, just print it */
- print_buf_lines(log_info, a_buf->e_buf.buf + a_buf->e_buf.read, a_buf->e_buf.used_len);
- } else {
- /* The circular buffer will always have at least 1 byte unused,
- * so by allocating alloc_len here we will have at least
- * 1 byte of space available as required by print_buf_lines().
- */
- char* nbuf = static_cast<char*>(malloc(a_buf->e_buf.alloc_len));
- if (!nbuf) {
- return;
- }
- int first_chunk_len = a_buf->e_buf.buf_size - a_buf->e_buf.read;
- memcpy(nbuf, a_buf->e_buf.buf + a_buf->e_buf.read, first_chunk_len);
- /* copy second chunk */
- memcpy(nbuf + first_chunk_len, a_buf->e_buf.buf, a_buf->e_buf.write);
- print_buf_lines(log_info, nbuf, first_chunk_len + a_buf->e_buf.write);
- free(nbuf);
- }
-}
-
-static void signal_handler(int signal_num);
-
-static void block_signals(sigset_t* oldset) {
- sigset_t blockset;
-
- sigemptyset(&blockset);
- sigaddset(&blockset, SIGINT);
- sigaddset(&blockset, SIGQUIT);
- sigaddset(&blockset, SIGHUP);
- pthread_sigmask(SIG_BLOCK, &blockset, oldset);
-}
-
-static void unblock_signals(sigset_t* oldset) {
- pthread_sigmask(SIG_SETMASK, oldset, nullptr);
-}
-
-static void setup_signal_handlers(pid_t pid) {
- struct sigaction handler = {.sa_handler = signal_handler};
-
- child_pid = pid;
- sigaction(SIGINT, &handler, &old_int);
- sigaction(SIGQUIT, &handler, &old_quit);
- sigaction(SIGHUP, &handler, &old_hup);
-}
-
-static void restore_signal_handlers() {
- sigaction(SIGINT, &old_int, nullptr);
- sigaction(SIGQUIT, &old_quit, nullptr);
- sigaction(SIGHUP, &old_hup, nullptr);
- child_pid = 0;
-}
-
-static void signal_handler(int signal_num) {
- if (child_pid == 0 || kill(child_pid, signal_num) != 0) {
- restore_signal_handlers();
- raise(signal_num);
- }
-}
-
-static int parent(const char* tag, int parent_read, pid_t pid, int* chld_sts, int log_target,
- bool abbreviated, const char* file_path, bool forward_signals) {
- int status = 0;
- char buffer[4096];
- struct pollfd poll_fds[] = {
- {
- .fd = parent_read,
- .events = POLLIN,
- },
- };
- int rc = 0;
- int fd;
-
- struct log_info log_info;
-
- int a = 0; // start index of unprocessed data
- int b = 0; // end index of unprocessed data
- int sz;
- bool found_child = false;
- // There is a very small chance that opening child_ptty in the child will fail, but in this case
- // POLLHUP will not be generated below. Therefore, we use a 1 second timeout for poll() until
- // we receive a message from child_ptty. If this times out, we call waitpid() with WNOHANG to
- // check the status of the child process and exit appropriately if it has terminated.
- bool received_messages = false;
- char tmpbuf[256];
-
- log_info.btag = basename(tag);
- if (!log_info.btag) {
- log_info.btag = tag;
- }
-
- if (abbreviated && (log_target == LOG_NONE)) {
- abbreviated = 0;
- }
- if (abbreviated) {
- init_abbr_buf(&log_info.a_buf);
- }
-
- if (log_target & LOG_KLOG) {
- snprintf(log_info.klog_fmt, sizeof(log_info.klog_fmt), "<6>%.*s: %%s\n", MAX_KLOG_TAG,
- log_info.btag);
- }
-
- if ((log_target & LOG_FILE) && !file_path) {
- /* No file_path specified, clear the LOG_FILE bit */
- log_target &= ~LOG_FILE;
- }
-
- if (log_target & LOG_FILE) {
- fd = open(file_path, O_WRONLY | O_CREAT | O_CLOEXEC, 0664);
- if (fd < 0) {
- ERROR("Cannot log to file %s\n", file_path);
- log_target &= ~LOG_FILE;
- } else {
- lseek(fd, 0, SEEK_END);
- log_info.fp = fdopen(fd, "a");
- }
- }
-
- log_info.log_target = log_target;
- log_info.abbreviated = abbreviated;
-
- while (!found_child) {
- int timeout = received_messages ? -1 : 1000;
- if (TEMP_FAILURE_RETRY(poll(poll_fds, arraysize(poll_fds), timeout)) < 0) {
- ERROR("poll failed\n");
- rc = -1;
- goto err_poll;
- }
-
- if (poll_fds[0].revents & POLLIN) {
- received_messages = true;
- sz = TEMP_FAILURE_RETRY(read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
-
- sz += b;
- // Log one line at a time
- for (b = 0; b < sz; b++) {
- if (buffer[b] == '\r') {
- if (abbreviated) {
- /* The abbreviated logging code uses newline as
- * the line separator. Lucikly, the pty layer
- * helpfully cooks the output of the command
- * being run and inserts a CR before NL. So
- * I just change it to NL here when doing
- * abbreviated logging.
- */
- buffer[b] = '\n';
- } else {
- buffer[b] = '\0';
- }
- } else if (buffer[b] == '\n') {
- buffer[b] = '\0';
- log_line(&log_info, &buffer[a], b - a);
- a = b + 1;
- }
- }
-
- if (a == 0 && b == sizeof(buffer) - 1) {
- // buffer is full, flush
- buffer[b] = '\0';
- log_line(&log_info, &buffer[a], b - a);
- b = 0;
- } else if (a != b) {
- // Keep left-overs
- b -= a;
- memmove(buffer, &buffer[a], b);
- a = 0;
- } else {
- a = 0;
- b = 0;
- }
- }
-
- if (!received_messages || (poll_fds[0].revents & POLLHUP)) {
- int ret;
- sigset_t oldset;
-
- if (forward_signals) {
- // Our signal handlers forward these signals to 'child_pid', but waitpid() may reap
- // the child, so we must block these signals until we either 1) conclude that the
- // child is still running or 2) determine the child has been reaped and we have
- // reset the signals to their original disposition.
- block_signals(&oldset);
- }
-
- int flags = (poll_fds[0].revents & POLLHUP) ? 0 : WNOHANG;
- ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, flags));
- if (ret < 0) {
- rc = errno;
- ALOG(LOG_ERROR, "logwrap", "waitpid failed with %s\n", strerror(errno));
- goto err_waitpid;
- }
- if (ret > 0) {
- found_child = true;
- }
-
- if (forward_signals) {
- if (found_child) {
- restore_signal_handlers();
- }
- unblock_signals(&oldset);
- }
- }
- }
-
- if (chld_sts != nullptr) {
- *chld_sts = status;
- } else {
- if (WIFEXITED(status))
- rc = WEXITSTATUS(status);
- else
- rc = -ECHILD;
- }
-
- // Flush remaining data
- if (a != b) {
- buffer[b] = '\0';
- log_line(&log_info, &buffer[a], b - a);
- }
-
- /* All the output has been processed, time to dump the abbreviated output */
- if (abbreviated) {
- print_abbr_buf(&log_info);
- }
-
- if (WIFEXITED(status)) {
- if (WEXITSTATUS(status)) {
- snprintf(tmpbuf, sizeof(tmpbuf), "%s terminated by exit(%d)\n", log_info.btag,
- WEXITSTATUS(status));
- do_log_line(&log_info, tmpbuf);
- }
- } else {
- if (WIFSIGNALED(status)) {
- snprintf(tmpbuf, sizeof(tmpbuf), "%s terminated by signal %d\n", log_info.btag,
- WTERMSIG(status));
- do_log_line(&log_info, tmpbuf);
- } else if (WIFSTOPPED(status)) {
- snprintf(tmpbuf, sizeof(tmpbuf), "%s stopped by signal %d\n", log_info.btag,
- WSTOPSIG(status));
- do_log_line(&log_info, tmpbuf);
- }
- }
-
-err_waitpid:
-err_poll:
- if (log_target & LOG_FILE) {
- fclose(log_info.fp); /* Also closes underlying fd */
- }
- if (abbreviated) {
- free_abbr_buf(&log_info.a_buf);
- }
- return rc;
-}
-
-static void child(int argc, const char* const* argv) {
- // create null terminated argv_child array
- char* argv_child[argc + 1];
- memcpy(argv_child, argv, argc * sizeof(char*));
- argv_child[argc] = nullptr;
-
- if (execvp(argv_child[0], argv_child)) {
- FATAL_CHILD("executing %s failed: %s\n", argv_child[0], strerror(errno));
- }
-}
-
-int logwrap_fork_execvp(int argc, const char* const* argv, int* status, bool forward_signals,
- int log_target, bool abbreviated, const char* file_path) {
- pid_t pid;
- int parent_ptty;
- sigset_t oldset;
- int rc = 0;
-
- rc = pthread_mutex_lock(&fd_mutex);
- if (rc) {
- ERROR("failed to lock signal_fd mutex\n");
- goto err_lock;
- }
-
- /* Use ptty instead of socketpair so that STDOUT is not buffered */
- parent_ptty = TEMP_FAILURE_RETRY(posix_openpt(O_RDWR | O_CLOEXEC));
- if (parent_ptty < 0) {
- ERROR("Cannot create parent ptty\n");
- rc = -1;
- goto err_open;
- }
-
- char child_devname[64];
- if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
- ptsname_r(parent_ptty, child_devname, sizeof(child_devname)) != 0) {
- ERROR("Problem with /dev/ptmx\n");
- rc = -1;
- goto err_ptty;
- }
-
- if (forward_signals) {
- // Block these signals until we have the child pid and our signal handlers set up.
- block_signals(&oldset);
- }
-
- pid = fork();
- if (pid < 0) {
- ERROR("Failed to fork\n");
- rc = -1;
- goto err_fork;
- } else if (pid == 0) {
- pthread_mutex_unlock(&fd_mutex);
- if (forward_signals) {
- unblock_signals(&oldset);
- }
-
- setsid();
-
- int child_ptty = TEMP_FAILURE_RETRY(open(child_devname, O_RDWR | O_CLOEXEC));
- if (child_ptty < 0) {
- FATAL_CHILD("Cannot open child_ptty: %s\n", strerror(errno));
- }
- close(parent_ptty);
-
- dup2(child_ptty, 1);
- dup2(child_ptty, 2);
- close(child_ptty);
-
- child(argc, argv);
- } else {
- if (forward_signals) {
- setup_signal_handlers(pid);
- unblock_signals(&oldset);
- }
-
- rc = parent(argv[0], parent_ptty, pid, status, log_target, abbreviated, file_path,
- forward_signals);
-
- if (forward_signals) {
- restore_signal_handlers();
- }
- }
-
-err_fork:
- if (forward_signals) {
- unblock_signals(&oldset);
- }
-err_ptty:
- close(parent_ptty);
-err_open:
- pthread_mutex_unlock(&fd_mutex);
-err_lock:
- return rc;
-}
diff --git a/logwrapper/logwrap_fork_execvp_benchmark.cpp b/logwrapper/logwrap_fork_execvp_benchmark.cpp
deleted file mode 100644
index b2d0c71..0000000
--- a/logwrapper/logwrap_fork_execvp_benchmark.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2017 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 "logwrap/logwrap.h"
-
-#include <android-base/logging.h>
-#include <benchmark/benchmark.h>
-
-static void BM_android_fork_execvp_ext(benchmark::State& state) {
- const char* argv[] = {"/system/bin/echo", "hello", "world"};
- const int argc = 3;
- while (state.KeepRunning()) {
- int rc = logwrap_fork_execvp(argc, argv, nullptr, false, LOG_NONE, false, nullptr);
- CHECK_EQ(0, rc);
- }
-}
-BENCHMARK(BM_android_fork_execvp_ext);
-
-BENCHMARK_MAIN();
diff --git a/logwrapper/logwrapper.cpp b/logwrapper/logwrapper.cpp
deleted file mode 100644
index 7118d12..0000000
--- a/logwrapper/logwrapper.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2008 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 <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include <cutils/klog.h>
-#include <log/log.h>
-#include <logwrap/logwrap.h>
-
-void fatal(const char* msg) {
- fprintf(stderr, "%s", msg);
- ALOG(LOG_ERROR, "logwrapper", "%s", msg);
- exit(-1);
-}
-
-void usage() {
- fatal("Usage: logwrapper [-a] [-d] [-k] BINARY [ARGS ...]\n"
- "\n"
- "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
- "the Android logging system. Tag is set to BINARY, priority is\n"
- "always LOG_INFO.\n"
- "\n"
- "-a: Causes logwrapper to do abbreviated logging.\n"
- " This logs up to the first 4K and last 4K of the command\n"
- " being run, and logs the output when the command exits\n"
- "-d: Causes logwrapper to SIGSEGV when BINARY terminates\n"
- " fault address is set to the status of wait()\n"
- "-k: Causes logwrapper to log to the kernel log instead of\n"
- " the Android system log\n");
-}
-
-int main(int argc, char* argv[]) {
- int seg_fault_on_exit = 0;
- int log_target = LOG_ALOG;
- bool abbreviated = false;
- int ch;
- int status = 0xAAAA;
- int rc;
-
- while ((ch = getopt(argc, argv, "adk")) != -1) {
- switch (ch) {
- case 'a':
- abbreviated = true;
- break;
- case 'd':
- seg_fault_on_exit = 1;
- break;
- case 'k':
- log_target = LOG_KLOG;
- klog_set_level(6);
- break;
- case '?':
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc < 1) {
- usage();
- }
-
- rc = logwrap_fork_execvp(argc, &argv[0], &status, true, log_target, abbreviated, nullptr);
- if (!rc) {
- if (WIFEXITED(status))
- rc = WEXITSTATUS(status);
- else
- rc = -ECHILD;
- }
-
- if (seg_fault_on_exit) {
- uintptr_t fault_address = (uintptr_t)status;
- *(int*)fault_address = 0; // causes SIGSEGV with fault_address = status
- }
-
- return rc;
-}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 77fa94e..2bceb75 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -78,7 +78,7 @@
# create some directories (some are mount points) and symlinks
LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \
dev proc sys system data data_mirror odm oem acct config storage mnt apex debug_ramdisk \
- linkerconfig $(BOARD_ROOT_EXTRA_FOLDERS)); \
+ linkerconfig second_stage_resources $(BOARD_ROOT_EXTRA_FOLDERS)); \
ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \
ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \
ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 5de422f..967205f 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -10,6 +10,7 @@
libGLESv1_CM.so
libGLESv2.so
libGLESv3.so
+libicu.so
libicui18n.so
libicuuc.so
libjnigraphics.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 37f911a..3146f36 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -182,6 +182,9 @@
mount binder binder /dev/binderfs stats=global
chmod 0755 /dev/binderfs
+ # Mount fusectl
+ mount fusectl none /sys/fs/fuse/connections
+
symlink /dev/binderfs/binder /dev/binder
symlink /dev/binderfs/hwbinder /dev/hwbinder
symlink /dev/binderfs/vndbinder /dev/vndbinder
@@ -461,6 +464,10 @@
# The bind+remount combination allows this to work in containers.
mount rootfs rootfs / remount bind ro nodev
+ # Mount default storage into root namespace
+ mount none /mnt/user/0 /storage bind rec
+ mount none none /storage slave rec
+
# Make sure /sys/kernel/debug (if present) is labeled properly
# Note that tracefs may be mounted under debug, so we need to cross filesystems
restorecon --recursive --cross-filesystems /sys/kernel/debug
@@ -510,6 +517,7 @@
mkdir /metadata/bootstat 0750 system log
mkdir /metadata/ota 0700 root system
mkdir /metadata/ota/snapshots 0700 root system
+ mkdir /metadata/userspacereboot 0770 root system
mkdir /metadata/apex 0700 root system
mkdir /metadata/apex/sessions 0700 root system
@@ -520,6 +528,7 @@
# no-op.
restorecon_recursive /metadata/apex
+ mkdir /metadata/staged-install 0770 root system
on late-fs
# Ensure that tracefs has the correct permissions.
# This does not work correctly if it is called in post-fs.
@@ -552,13 +561,24 @@
# Make sure that apexd is started in the default namespace
enter_default_mount_ns
+ mkdir /data/vendor 0771 root root encryption=Require
+ mkdir /data/vendor_ce 0771 root root encryption=None
+ mkdir /data/vendor_de 0771 root root encryption=None
+ mkdir /data/vendor/hardware 0771 root root
+
+ # Start tombstoned early to be able to store tombstones.
+ mkdir /data/tombstones 0771 system system encryption=Require
+ mkdir /data/vendor/tombstones 0771 root root
+ mkdir /data/vendor/tombstones/wifi 0771 wifi wifi
+ start tombstoned
+
# /data/apex is now available. Start apexd to scan and activate APEXes.
mkdir /data/apex 0755 root system encryption=None
mkdir /data/apex/active 0755 root system
mkdir /data/apex/backup 0700 root system
mkdir /data/apex/hashtree 0700 root system
mkdir /data/apex/sessions 0700 root system
- mkdir /data/app-staging 0750 system system encryption=None
+ mkdir /data/app-staging 0750 system system encryption=DeleteIfNecessary
start apexd
# Avoid predictable entropy pool. Carry over entropy from previous boot.
@@ -586,6 +606,8 @@
chown bluetooth bluetooth /data/misc/bluedroid/bt_config.conf
mkdir /data/misc/bluetooth 0770 bluetooth bluetooth
mkdir /data/misc/bluetooth/logs 0770 bluetooth bluetooth
+ mkdir /data/misc/nfc 0770 nfc nfc
+ mkdir /data/misc/nfc/logs 0770 nfc nfc
mkdir /data/misc/credstore 0700 credstore credstore
mkdir /data/misc/keystore 0700 keystore keystore
mkdir /data/misc/gatekeeper 0700 system system
@@ -636,11 +658,6 @@
mkdir /data/preloads 0775 system system encryption=None
- mkdir /data/vendor 0771 root root encryption=Require
- mkdir /data/vendor_ce 0771 root root encryption=None
- mkdir /data/vendor_de 0771 root root encryption=None
- mkdir /data/vendor/hardware 0771 root root
-
# For security reasons, /data/local/tmp should always be empty.
# Do not place files or directories in /data/local/tmp
mkdir /data/local/tmp 0771 shell shell
@@ -652,9 +669,15 @@
mkdir /data/app-lib 0771 system system encryption=Require
mkdir /data/app 0771 system system encryption=Require
mkdir /data/property 0700 root root encryption=Require
- mkdir /data/tombstones 0771 system system encryption=Require
- mkdir /data/vendor/tombstones 0771 root root
- mkdir /data/vendor/tombstones/wifi 0771 wifi wifi
+
+ # Create directories to push tests to for each linker namespace.
+ # Create the subdirectories in case the first test is run as root
+ # so it doesn't end up owned by root.
+ mkdir /data/local/tests 0700 shell shell
+ mkdir /data/local/tests/product 0700 shell shell
+ mkdir /data/local/tests/system 0700 shell shell
+ mkdir /data/local/tests/unrestricted 0700 shell shell
+ mkdir /data/local/tests/vendor 0700 shell shell
# create dalvik-cache, so as to enforce our permissions
mkdir /data/dalvik-cache 0771 root root encryption=Require
@@ -788,34 +811,19 @@
# IOCTLs on ashmem fds any more.
setprop sys.use_memfd false
- # Explicitly disable FUSE
- setprop persist.sys.fuse false
-
# Set fscklog permission
chown root system /dev/fscklogs/log
chmod 0770 /dev/fscklogs/log
-# Switch between sdcardfs and FUSE depending on persist property
-# TODO: Move this to ro property before launch because FDE devices
-# interact with persistent properties differently during boot
-on zygote-start && property:persist.sys.fuse=true
- # Mount default storage into root namespace
- mount none /mnt/user/0 /storage bind rec
- mount none none /storage slave rec
-on zygote-start && property:persist.sys.fuse=false
- # Mount default storage into root namespace
- mount none /mnt/runtime/default /storage bind rec
- mount none none /storage slave rec
-on zygote-start && property:persist.sys.fuse=""
- # Mount default storage into root namespace
- mount none /mnt/runtime/default /storage bind rec
- mount none none /storage slave rec
+ # Enable FUSE by default
+ setprop persist.sys.fuse true
# It is recommended to put unnecessary data/ initialization from post-fs-data
# to start-zygote in device's init.rc to unblock zygote start.
on zygote-start && property:ro.crypto.state=unencrypted
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
+ start statsd
start netd
start zygote
start zygote_secondary
@@ -823,6 +831,7 @@
on zygote-start && property:ro.crypto.state=unsupported
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
+ start statsd
start netd
start zygote
start zygote_secondary
@@ -830,6 +839,7 @@
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
# A/B update verifier that marks a successful boot.
exec_start update_verifier_nonencrypted
+ start statsd
start netd
start zygote
start zygote_secondary
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 9adbcba..e827cf5 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -5,6 +5,7 @@
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
+ onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index 0e69b16..adc7031 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -5,6 +5,7 @@
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
+ onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 3e80168..fb9e99b 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -5,13 +5,14 @@
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
+ onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh MaxPerformance
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
@@ -21,4 +22,4 @@
socket zygote_secondary stream 660 root system
socket usap_pool_secondary stream 660 root system
onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks
+ task_profiles ProcessCapacityHigh MaxPerformance
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 9c2cdf2..1994bdb 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -17,6 +17,9 @@
devname uevent_devpath
dirname /dev/snd
+subsystem dma_heap
+ devname uevent_devpath
+ dirname /dev/dma_heap
# ueventd can only set permissions on device nodes and their associated
# sysfs attributes, not on arbitrary paths.
#
@@ -39,6 +42,7 @@
/dev/vndbinder 0666 root root
/dev/pmsg0 0222 root log
+/dev/dma_heap/system 0666 system system
# kms driver for drm based gpu
/dev/dri/* 0666 root graphics
diff --git a/run-as/Android.bp b/run-as/Android.bp
index 840a43c..accd07d 100644
--- a/run-as/Android.bp
+++ b/run-as/Android.bp
@@ -25,4 +25,5 @@
"libpackagelistparser",
"libminijail",
],
+ header_libs: ["libcutils_headers"],
}
diff --git a/toolbox/start.cpp b/toolbox/start.cpp
index 46314cf..cffb89c 100644
--- a/toolbox/start.cpp
+++ b/toolbox/start.cpp
@@ -37,6 +37,7 @@
static void ControlDefaultServices(bool start) {
std::vector<std::string> services = {
+ "iorapd",
"netd",
"surfaceflinger",
"audioserver",
@@ -91,4 +92,4 @@
extern "C" int stop_main(int argc, char** argv) {
return StartStop(argc, argv, false);
-}
+}
\ No newline at end of file
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 6840baa..27e1a3f 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -75,3 +75,36 @@
vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
}
+
+prebuilt_etc {
+ name: "keymaster_soft_attestation_keys.xml",
+ vendor: true,
+ src: "set_attestation_key/keymaster_soft_attestation_keys.xml",
+}
+
+cc_binary {
+ name: "trusty_keymaster_set_attestation_key",
+ vendor: true,
+
+ srcs: [
+ "set_attestation_key/set_attestation_key.cpp",
+ "ipc/trusty_keymaster_ipc.cpp",
+ ],
+
+ local_include_dirs: ["include"],
+
+ shared_libs: [
+ "libc",
+ "libcrypto",
+ "liblog",
+ "libtrusty",
+ "libhardware",
+ "libkeymaster_messages",
+ "libxml2",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index 13e6725..ce2cc2e 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -53,6 +53,19 @@
KM_DELETE_ALL_KEYS = (23 << KEYMASTER_REQ_SHIFT),
KM_DESTROY_ATTESTATION_IDS = (24 << KEYMASTER_REQ_SHIFT),
KM_IMPORT_WRAPPED_KEY = (25 << KEYMASTER_REQ_SHIFT),
+
+ // Bootloader/provisioning calls.
+ KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
+ KM_SET_ATTESTATION_KEY = (0x2000 << KEYMASTER_REQ_SHIFT),
+ KM_APPEND_ATTESTATION_CERT_CHAIN = (0x3000 << KEYMASTER_REQ_SHIFT),
+ KM_ATAP_GET_CA_REQUEST = (0x4000 << KEYMASTER_REQ_SHIFT),
+ KM_ATAP_SET_CA_RESPONSE_BEGIN = (0x5000 << KEYMASTER_REQ_SHIFT),
+ KM_ATAP_SET_CA_RESPONSE_UPDATE = (0x6000 << KEYMASTER_REQ_SHIFT),
+ KM_ATAP_SET_CA_RESPONSE_FINISH = (0x7000 << KEYMASTER_REQ_SHIFT),
+ KM_ATAP_READ_UUID = (0x8000 << KEYMASTER_REQ_SHIFT),
+ KM_SET_PRODUCT_ID = (0x9000 << KEYMASTER_REQ_SHIFT),
+ KM_CLEAR_ATTESTATION_CERT_CHAIN = (0xa000 << KEYMASTER_REQ_SHIFT),
+ KM_SET_WRAPPED_ATTESTATION_KEY = (0xb000 << KEYMASTER_REQ_SHIFT),
};
#ifdef __ANDROID__
diff --git a/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
new file mode 100644
index 0000000..fce2ac2
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<AndroidAttestation>
+ <NumberOfKeyboxes>10</NumberOfKeyboxes>
+ <Keybox DeviceID="dev1">
+ <Key algorithm="rsa">
+ <PrivateKey format="pem">
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1qEIEir6LR752/q7yXPKb
+KvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX4YVBeuVKvClqOm21wAQI
+O2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmdXX0jYvKcXgLocQIDAQAB
+AoGBAL6GCwuZqAKm+xpZQ4p7txUGWwmjbcbpysxr88AsNNfXnpTGYGQo2Ix7f2V3
+wc3qZAdKvo5yht8fCBHclygmCGjeldMu/Ja20IT/JxpfYN78xwPno45uKbqaPF/C
+woB2tqiWrx0014gozpvdsfNPnJQEQweBKY4gExZyW728mTpBAkEA4cbZJ2RsCRbs
+NoJtWUmDdAwh8bB0xKGlmGfGaXlchdPcRkxbkp6Uv7NODcxQFLEPEzQat/3V9gQU
+0qMmytQcxQJBANpIWZd4XNVjD7D9jFJU+Y5TjhiYOq6ea35qWntdNDdVuSGOvUAy
+DSg4fXifdvohi8wti2il9kGPu+ylF5qzr70CQFD+/DJklVlhbtZTThVFCTKdk6PY
+ENvlvbmCKSz3i9i624Agro1X9LcdBThv/p6dsnHKNHejSZnbdvjl7OnA1J0CQBW3
+TPJ8zv+Ls2vwTZ2DRrCaL3DS9EObDyasfgP36dH3fUuRX9KbKCPwOstdUgDghX/y
+qAPpPu6W1iNc6VRCvCECQQCQp0XaiXCyzWSWYDJCKMX4KFb/1mW6moXI1g8bi+5x
+fs0scurgHa2GunZU1M9FrbXx8rMdn4Eiz6XxpVcPmy0l
+-----END RSA PRIVATE KEY-----
+ </PrivateKey>
+ <CertificateChain>
+ <NumberOfCertificates>2</NumberOfCertificates>
+ <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICtjCCAh+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDAeFw0xNjAxMDQx
+MjQwNTNaFw0zNTEyMzAxMjQwNTNaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+YWxpZm9ybmlhMRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJv
+aWQxKTAnBgNVBAMMIEFuZHJvaWQgU29mdHdhcmUgQXR0ZXN0YXRpb24gS2V5MIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1
+qEIEir6LR752/q7yXPKbKvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX
+4YVBeuVKvClqOm21wAQIO2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmd
+XX0jYvKcXgLocQIDAQABo2YwZDAdBgNVHQ4EFgQU1AwQG/jNY7n3OVK1DhNcpteZ
+k4YwHwYDVR0jBBgwFoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wEgYDVR0TAQH/BAgw
+BgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAni1IX4xn
+M9waha2Z11Aj6hTsQ7DhnerCI0YecrUZ3GAi5KVoMWwLVcTmnKItnzpPk2sxixZ4
+Fg2Iy9mLzICdhPDCJ+NrOPH90ecXcjFZNX2W88V/q52PlmEmT7K+gbsNSQQiis6f
+9/VCLiVE+iEHElqDtVWtGIL4QBSbnCBjBH8=
+-----END CERTIFICATE-----
+ </Certificate>
+ <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICpzCCAhCgAwIBAgIJAP+U2d2fB8gMMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQwHhcN
+MTYwMTA0MTIzMTA4WhcNMzUxMjMwMTIzMTA4WjBjMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UE
+CgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAs
+Q+wzfNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdL
+t0GAZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwID
+AQABo2MwYTAdBgNVHQ4EFgQUKfrxrMxN0kyWQCd1trDpMuUH/i4wHwYDVR0jBBgw
+FoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAT3LzNlmNDsG5dFsxWfbwjSVJMJ6j
+HBwp0kUtILlNX2S06IDHeHqcOd6os/W/L3BfRxBcxebrTQaZYdKumgf/93y4q+uc
+DyQHXrF/unlx/U1bnt8Uqf7f7XzAiF343ZtkMlbVNZriE/mPzsF83O+kqrJVw4Op
+Lvtc9mL1J1IXvmM=
+-----END CERTIFICATE-----
+ </Certificate>
+ </CertificateChain>
+ </Key>
+ </Keybox>
+ <Keybox DeviceID="dev1">
+ <Key algorithm="ecdsa">
+ <PrivateKey format="pem">
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEICHghkMqFRmEWc82OlD8FMnarfk19SfC39ceTW28QuVEoAoGCCqGSM49
+AwEHoUQDQgAE6555+EJjWazLKpFMiYbMcK2QZpOCqXMmE/6sy/ghJ0whdJdKKv6l
+uU1/ZtTgZRBmNbxTt6CjpnFYPts+Ea4QFA==
+-----END EC PRIVATE KEY-----
+ </PrivateKey>
+ <CertificateChain>
+ <NumberOfCertificates>2</NumberOfCertificates>
+ <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICeDCCAh6gAwIBAgICEAEwCgYIKoZIzj0EAwIwgZgxCzAJBgNVBAYTAlVTMRMw
+EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYD
+VQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxMzAxBgNVBAMMKkFu
+ZHJvaWQgS2V5c3RvcmUgU29mdHdhcmUgQXR0ZXN0YXRpb24gUm9vdDAeFw0xNjAx
+MTEwMDQ2MDlaFw0yNjAxMDgwMDQ2MDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdB
+bmRyb2lkMTswOQYDVQQDDDJBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVz
+dGF0aW9uIEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOue
+efhCY1msyyqRTImGzHCtkGaTgqlzJhP+rMv4ISdMIXSXSir+pblNf2bU4GUQZjW8
+U7ego6ZxWD7bPhGuEBSjZjBkMB0GA1UdDgQWBBQ//KzWGrE6noEguNUlHMVlux6R
+qTAfBgNVHSMEGDAWgBTIrel3TEXDo88NFhDkeUM6IVowzzASBgNVHRMBAf8ECDAG
+AQH/AgEAMA4GA1UdDwEB/wQEAwIChDAKBggqhkjOPQQDAgNIADBFAiBLipt77oK8
+wDOHri/AiZi03cONqycqRZ9pDMfDktQPjgIhAO7aAV229DLp1IQ7YkyUBO86fMy9
+Xvsiu+f+uXc/WT/7
+-----END CERTIFICATE-----
+ </Certificate>
+ <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG
+EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll
+dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD
+VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw
+HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq
+QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59
+dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O
+BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W
+EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG
+SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN
+C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw==
+-----END CERTIFICATE-----
+ </Certificate>
+ </CertificateChain>
+ </Key>
+ </Keybox>
+</AndroidAttestation>
diff --git a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
new file mode 100644
index 0000000..6f74833
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2020 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 <errno.h>
+#include <getopt.h>
+#include <libxml/xmlreader.h>
+#include <openssl/pem.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string>
+
+using std::string;
+
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+static const char* _sopts = "h";
+static const struct option _lopts[] = {
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0},
+};
+
+static const char* usage =
+ "Usage: %s [options] xml-file\n"
+ "\n"
+ "options:\n"
+ " -h, --help prints this message and exit\n"
+ "\n";
+
+static void print_usage_and_exit(const char* prog, int code) {
+ fprintf(stderr, usage, prog);
+ exit(code);
+}
+
+static void parse_options(int argc, char** argv) {
+ int c;
+ int oidx = 0;
+
+ while (1) {
+ c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
+ if (c == -1) {
+ break; /* done */
+ }
+
+ switch (c) {
+ case 'h':
+ print_usage_and_exit(argv[0], EXIT_SUCCESS);
+ break;
+
+ default:
+ print_usage_and_exit(argv[0], EXIT_FAILURE);
+ }
+ }
+}
+
+struct SetAttestationKeyRequest : public keymaster::KeymasterMessage {
+ explicit SetAttestationKeyRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return sizeof(uint32_t) + key_data.SerializedSize(); }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ buf = keymaster::append_uint32_to_buf(buf, end, algorithm);
+ return key_data.Serialize(buf, end);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+ key_data.Deserialize(buf_ptr, end);
+ }
+
+ keymaster_algorithm_t algorithm;
+ keymaster::Buffer key_data;
+};
+
+struct KeymasterNoResponse : public keymaster::KeymasterResponse {
+ explicit KeymasterNoResponse(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+ : keymaster::KeymasterResponse(ver) {}
+
+ size_t NonErrorSerializedSize() const override { return 0; }
+ uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+ bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct SetAttestationKeyResponse : public KeymasterNoResponse {};
+
+struct ClearAttestationCertChainRequest : public keymaster::KeymasterMessage {
+ explicit ClearAttestationCertChainRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+ : KeymasterMessage(ver) {}
+
+ size_t SerializedSize() const override { return sizeof(uint32_t); }
+ uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+ return keymaster::append_uint32_to_buf(buf, end, algorithm);
+ }
+ bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+ return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm);
+ }
+
+ keymaster_algorithm_t algorithm;
+};
+
+struct ClearAttestationCertChainResponse : public KeymasterNoResponse {};
+
+static int set_attestation_key_or_cert_bin(uint32_t cmd, keymaster_algorithm_t algorithm,
+ const void* key_data, size_t key_data_size) {
+ int ret;
+
+ SetAttestationKeyRequest req;
+ req.algorithm = algorithm;
+ req.key_data.Reinitialize(key_data, key_data_size);
+ SetAttestationKeyResponse rsp;
+
+ ret = trusty_keymaster_send(cmd, req, &rsp);
+ if (ret) {
+ fprintf(stderr, "trusty_keymaster_send cmd 0x%x failed %d\n", cmd, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int set_attestation_key_or_cert_pem(uint32_t cmd, keymaster_algorithm_t algorithm,
+ const xmlChar* pemkey) {
+ int ret;
+ int sslret;
+
+ /* Convert from pem to binary */
+ BIO* bio = BIO_new_mem_buf(pemkey, xmlStrlen(pemkey));
+ if (!bio) {
+ fprintf(stderr, "BIO_new_mem_buf failed\n");
+ ERR_print_errors_fp(stderr);
+ return -1;
+ }
+
+ char* key_name;
+ char* key_header;
+ uint8_t* key;
+ long keylen;
+ sslret = PEM_read_bio(bio, &key_name, &key_header, &key, &keylen);
+ BIO_free(bio);
+
+ if (!sslret) {
+ fprintf(stderr, "PEM_read_bio failed\n");
+ ERR_print_errors_fp(stderr);
+ return -1;
+ }
+
+ /* Send key in binary format to trusty */
+ ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+ OPENSSL_free(key_name);
+ OPENSSL_free(key_header);
+ OPENSSL_free(key);
+
+ return ret;
+}
+
+static int set_attestation_key_or_cert_iecs(uint32_t cmd, keymaster_algorithm_t algorithm,
+ const xmlChar* key_base64) {
+ int ret;
+ int sslret;
+
+ /* Remove all whitespace. EVP_DecodeBase64 does not support whitespace. */
+ string key_base64_str((const char*)key_base64);
+ key_base64_str.erase(remove_if(key_base64_str.begin(), key_base64_str.end(), isspace),
+ key_base64_str.end());
+
+ /* Convert from base64 to binary */
+ uint8_t* key;
+ size_t keylen;
+ size_t key_base64_len = key_base64_str.length();
+
+ sslret = EVP_DecodedLength(&keylen, key_base64_len);
+ if (!sslret) {
+ fprintf(stderr, "invalid input length, %zu\n", key_base64_len);
+ return -1;
+ }
+ key = (uint8_t*)malloc(keylen);
+ if (!key) {
+ fprintf(stderr, "failed to allocate key, size %zu\n", key_base64_len);
+ return -1;
+ }
+ sslret = EVP_DecodeBase64(key, &keylen, keylen, (const uint8_t*)key_base64_str.data(),
+ key_base64_len);
+ if (!sslret) {
+ fprintf(stderr, "EVP_DecodeBase64 failed\n");
+ ERR_print_errors_fp(stderr);
+ free(key);
+ return -1;
+ }
+
+ /* Send key in binary format to trusty */
+ ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+ free(key);
+
+ return ret;
+}
+
+static int str_to_algorithm(keymaster_algorithm_t* algorithm, const xmlChar* algorithm_str) {
+ if (xmlStrEqual(algorithm_str, BAD_CAST "rsa")) {
+ *algorithm = KM_ALGORITHM_RSA;
+ } else if (xmlStrEqual(algorithm_str, BAD_CAST "ecdsa")) {
+ *algorithm = KM_ALGORITHM_EC;
+ } else {
+ printf("unsupported algorithm: %s\n", algorithm_str);
+ return -1;
+ }
+ return 0;
+}
+
+static int set_attestation_key_or_cert(uint32_t cmd, const xmlChar* algorithm_str,
+ const xmlChar* format, const xmlChar* str) {
+ int ret;
+ keymaster_algorithm_t algorithm;
+
+ ret = str_to_algorithm(&algorithm, algorithm_str);
+ if (ret) {
+ return ret;
+ }
+
+ if (xmlStrEqual(format, BAD_CAST "pem")) {
+ ret = set_attestation_key_or_cert_pem(cmd, algorithm, str);
+ } else if (xmlStrEqual(format, BAD_CAST "iecs")) {
+ ret = set_attestation_key_or_cert_iecs(cmd, algorithm, str);
+ } else {
+ printf("unsupported key/cert format: %s\n", format);
+ return -1;
+ }
+ return ret;
+}
+
+static int clear_cert_chain(const xmlChar* algorithm_str) {
+ int ret;
+ ClearAttestationCertChainRequest req;
+ ClearAttestationCertChainResponse rsp;
+
+ ret = str_to_algorithm(&req.algorithm, algorithm_str);
+ if (ret) {
+ return ret;
+ }
+
+ ret = trusty_keymaster_send(KM_CLEAR_ATTESTATION_CERT_CHAIN, req, &rsp);
+ if (ret) {
+ fprintf(stderr, "%s: trusty_keymaster_send failed %d\n", __func__, ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int process_xml(xmlTextReaderPtr xml) {
+ int ret;
+ const xmlChar* algorithm = NULL;
+ const xmlChar* element = NULL;
+ const xmlChar* element_format = NULL;
+
+ while ((ret = xmlTextReaderRead(xml)) == 1) {
+ int nodetype = xmlTextReaderNodeType(xml);
+ const xmlChar *name, *value;
+ name = xmlTextReaderConstName(xml);
+ switch (nodetype) {
+ case XML_READER_TYPE_ELEMENT:
+ element = name;
+ element_format = xmlTextReaderGetAttribute(xml, BAD_CAST "format");
+ if (xmlStrEqual(name, BAD_CAST "Key")) {
+ algorithm = xmlTextReaderGetAttribute(xml, BAD_CAST "algorithm");
+ } else if (xmlStrEqual(name, BAD_CAST "CertificateChain")) {
+ ret = clear_cert_chain(algorithm);
+ if (ret) {
+ fprintf(stderr, "%s, algorithm %s: Clear cert chain cmd failed, %d\n",
+ element, algorithm, ret);
+ return ret;
+ }
+ printf("%s, algorithm %s: Clear cert chain cmd done\n", element, algorithm);
+ }
+ break;
+ case XML_READER_TYPE_TEXT:
+ value = xmlTextReaderConstValue(xml);
+ uint32_t cmd;
+ if (xmlStrEqual(element, BAD_CAST "PrivateKey")) {
+ if (xmlStrEqual(element_format, BAD_CAST "pem")) {
+ cmd = KM_SET_ATTESTATION_KEY;
+ } else if (xmlStrEqual(element_format, BAD_CAST "iecs")) {
+ cmd = KM_SET_WRAPPED_ATTESTATION_KEY;
+ } else {
+ printf("unsupported key format: %s\n", element_format);
+ return -1;
+ }
+ } else if (xmlStrEqual(element, BAD_CAST "Certificate")) {
+ cmd = KM_APPEND_ATTESTATION_CERT_CHAIN;
+ } else {
+ break;
+ }
+
+ ret = set_attestation_key_or_cert(cmd, algorithm, element_format, value);
+ if (ret) {
+ fprintf(stderr, "%s, algorithm %s, format %s: Cmd 0x%x failed, %d\n", element,
+ algorithm, element_format, cmd, ret);
+ return ret;
+ }
+ printf("%s, algorithm %s, format %s: Cmd 0x%x done\n", element, algorithm,
+ element_format, cmd);
+ break;
+ case XML_READER_TYPE_END_ELEMENT:
+ element = NULL;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int parse_xml_file(const char* filename) {
+ int ret;
+ xmlTextReaderPtr xml = xmlReaderForFile(filename, NULL, 0);
+ if (!xml) {
+ fprintf(stderr, "failed to open %s\n", filename);
+ return -1;
+ }
+
+ ret = process_xml(xml);
+
+ xmlFreeTextReader(xml);
+ if (ret != 0) {
+ fprintf(stderr, "Failed to parse or process %s\n", filename);
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ int ret = 0;
+
+ parse_options(argc, argv);
+ if (optind + 1 != argc) {
+ print_usage_and_exit(argv[0], EXIT_FAILURE);
+ }
+
+ ret = trusty_keymaster_connect();
+ if (ret) {
+ fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
+ } else {
+ ret = parse_xml_file(argv[optind]);
+ trusty_keymaster_disconnect();
+ }
+
+ return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/trusty/trusty-test.mk b/trusty/trusty-test.mk
index fd353d1..dc4c962 100644
--- a/trusty/trusty-test.mk
+++ b/trusty/trusty-test.mk
@@ -14,3 +14,5 @@
PRODUCT_PACKAGES += \
spiproxyd \
+ trusty_keymaster_set_attestation_key \
+ keymaster_soft_attestation_keys.xml \
\ No newline at end of file
diff --git a/trusty/utils/rpmb_dev/rpmb_dev.c b/trusty/utils/rpmb_dev/rpmb_dev.c
index 5de1efa..2025621 100644
--- a/trusty/utils/rpmb_dev/rpmb_dev.c
+++ b/trusty/utils/rpmb_dev/rpmb_dev.c
@@ -283,6 +283,7 @@
{
.func = rpmb_dev_data_read,
.resp = RPMB_RESP_DATA_READ,
+ .check_key_programmed = true,
.check_addr = true,
.multi_packet_res = true,
.res_mac = true,
diff --git a/trusty/utils/rpmb_dev/rpmb_dev.rc b/trusty/utils/rpmb_dev/rpmb_dev.rc
index 9f60e81..9e203b8 100644
--- a/trusty/utils/rpmb_dev/rpmb_dev.rc
+++ b/trusty/utils/rpmb_dev/rpmb_dev.rc
@@ -16,7 +16,7 @@
disabled
user root
-service rpmb_mock_init /vendor/bin/rpmb_dev --dev /data/vendor/ss/RPMB_DATA --init --key "ea df 64 44 ea 65 5d 1c 87 27 d4 20 71 0d 53 42 dd 73 a3 38 63 e1 d7 94 c3 72 a6 ea e0 64 64 e6" --size 2048
+service rpmb_mock_init /vendor/bin/rpmb_dev --dev /data/vendor/ss/RPMB_DATA --init --size 2048
disabled
user system
group system