Merge "If enablefilecrypto or init_user0 fails, reboot into recovery."
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 0e38897..ee3503b 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -474,13 +474,14 @@
asocket* s = find_local_socket(p->msg.arg1, p->msg.arg0);
if (s) {
unsigned rid = p->msg.arg0;
- p->len = p->msg.data_length;
- if (s->enqueue(s, p) == 0) {
+ // TODO: Convert apacket::data to a type that we can move out of.
+ std::string copy(p->data, p->data + p->msg.data_length);
+
+ if (s->enqueue(s, std::move(copy)) == 0) {
D("Enqueue the socket");
send_ready(s->id, rid, t);
}
- return;
}
}
break;
diff --git a/adb/adb.h b/adb/adb.h
index b5d6bcb..c9c635a 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -73,11 +73,6 @@
};
struct apacket {
- apacket* next;
-
- size_t len;
- char* ptr;
-
amessage msg;
char data[MAX_PAYLOAD];
};
diff --git a/adb/adb_trace.cpp b/adb/adb_trace.cpp
index eac923d..a8ec5fb 100644
--- a/adb/adb_trace.cpp
+++ b/adb/adb_trace.cpp
@@ -42,7 +42,11 @@
const char* message) {
android::base::StderrLogger(id, severity, tag, file, line, message);
#if !ADB_HOST
- gLogdLogger(id, severity, tag, file, line, message);
+ // Only print logs of INFO or higher to logcat, so that `adb logcat` with adbd tracing on
+ // doesn't result in exponential logging.
+ if (severity >= android::base::INFO) {
+ gLogdLogger(id, severity, tag, file, line, message);
+ }
#endif
}
@@ -137,11 +141,15 @@
// -1 is used for the special values "1" and "all" that enable all
// tracing.
adb_trace_mask = ~0;
- return;
+ break;
} else {
adb_trace_mask |= 1 << flag->second;
}
}
+
+ if (adb_trace_mask != 0) {
+ android::base::SetMinimumLogSeverity(android::base::VERBOSE);
+ }
}
void adb_trace_init(char** argv) {
diff --git a/adb/adb_trace.h b/adb/adb_trace.h
index fc6560c..1d2c8c7 100644
--- a/adb/adb_trace.h
+++ b/adb/adb_trace.h
@@ -43,11 +43,11 @@
#define VLOG_IS_ON(TAG) \
((adb_trace_mask & (1 << (TAG))) != 0)
-#define VLOG(TAG) \
+#define VLOG(TAG) \
if (LIKELY(!VLOG_IS_ON(TAG))) \
- ; \
- else \
- LOG(INFO)
+ ; \
+ else \
+ LOG(DEBUG)
// You must define TRACE_TAG before using this macro.
#define D(...) \
diff --git a/adb/jdwp_service.cpp b/adb/jdwp_service.cpp
index f0dff06..6f5396a 100644
--- a/adb/jdwp_service.cpp
+++ b/adb/jdwp_service.cpp
@@ -124,9 +124,6 @@
** for each JDWP process, we record its pid and its connected socket
**/
-// PIDs are transmitted as 4 hex digits in ascii.
-static constexpr size_t PID_LEN = 4;
-
static void jdwp_process_event(int socket, unsigned events, void* _proc);
static void jdwp_process_list_updated(void);
@@ -174,7 +171,7 @@
_jdwp_list.remove_if(pred);
}
- int pid = -1;
+ int32_t pid = -1;
int socket = -1;
fdevent* fde = nullptr;
@@ -221,17 +218,9 @@
if (events & FDE_READ) {
if (proc->pid < 0) {
- /* read the PID as a 4-hexchar string */
- char buf[PID_LEN + 1];
- ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, buf, PID_LEN, 0));
- if (rc != PID_LEN) {
- D("failed to read jdwp pid: %s", strerror(errno));
- goto CloseProcess;
- }
- buf[PID_LEN] = '\0';
-
- if (sscanf(buf, "%04x", &proc->pid) != 1) {
- D("could not decode JDWP %p PID number: '%s'", proc, buf);
+ ssize_t rc = TEMP_FAILURE_RETRY(recv(socket, &proc->pid, sizeof(proc->pid), 0));
+ if (rc != sizeof(proc->pid)) {
+ D("failed to read jdwp pid: rc = %zd, errno = %s", rc, strerror(errno));
goto CloseProcess;
}
@@ -453,7 +442,7 @@
**/
struct JdwpSocket : public asocket {
- bool pass;
+ bool pass = false;
};
static void jdwp_socket_close(asocket* s) {
@@ -467,13 +456,12 @@
}
remove_socket(s);
- free(s);
+ delete s;
}
-static int jdwp_socket_enqueue(asocket* s, apacket* p) {
+static int jdwp_socket_enqueue(asocket* s, std::string) {
/* you can't write to this asocket */
D("LS(%d): JDWP socket received data?", s->id);
- put_apacket(p);
s->peer->close(s->peer);
return -1;
}
@@ -486,9 +474,11 @@
* on the second one, close the connection
*/
if (!jdwp->pass) {
- apacket* p = get_apacket();
- p->len = jdwp_process_list((char*)p->data, s->get_max_payload());
- peer->enqueue(peer, p);
+ std::string data;
+ data.resize(s->get_max_payload());
+ size_t len = jdwp_process_list(&data[0], data.size());
+ data.resize(len);
+ peer->enqueue(peer, std::move(data));
jdwp->pass = true;
} else {
peer->close(peer);
@@ -496,7 +486,7 @@
}
asocket* create_jdwp_service_socket(void) {
- JdwpSocket* s = reinterpret_cast<JdwpSocket*>(calloc(sizeof(*s), 1));
+ JdwpSocket* s = new JdwpSocket();
if (!s) {
fatal("failed to allocate JdwpSocket");
@@ -524,17 +514,14 @@
static std::vector<std::unique_ptr<JdwpTracker>> _jdwp_trackers;
static void jdwp_process_list_updated(void) {
- char buffer[1024];
- int len = jdwp_process_list_msg(buffer, sizeof(buffer));
+ std::string data;
+ data.resize(1024);
+ data.resize(jdwp_process_list_msg(&data[0], data.size()));
for (auto& t : _jdwp_trackers) {
- apacket* p = get_apacket();
- memcpy(p->data, buffer, len);
- p->len = len;
-
if (t->peer) {
// The tracker might not have been connected yet.
- t->peer->enqueue(t->peer, p);
+ t->peer->enqueue(t->peer, data);
}
}
}
@@ -560,17 +547,17 @@
JdwpTracker* t = (JdwpTracker*)s;
if (t->need_initial) {
- apacket* p = get_apacket();
+ std::string data;
+ data.resize(s->get_max_payload());
+ data.resize(jdwp_process_list_msg(&data[0], data.size()));
t->need_initial = false;
- p->len = jdwp_process_list_msg((char*)p->data, s->get_max_payload());
- s->peer->enqueue(s->peer, p);
+ s->peer->enqueue(s->peer, std::move(data));
}
}
-static int jdwp_tracker_enqueue(asocket* s, apacket* p) {
+static int jdwp_tracker_enqueue(asocket* s, std::string) {
/* you can't write to this socket */
D("LS(%d): JDWP tracker received data?", s->id);
- put_apacket(p);
s->peer->close(s->peer);
return -1;
}
diff --git a/adb/range.h b/adb/range.h
new file mode 100644
index 0000000..7a0b822
--- /dev/null
+++ b/adb/range.h
@@ -0,0 +1,65 @@
+#pragma once
+
+/*
+ * 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 <string>
+
+#include <android-base/logging.h>
+
+struct Range {
+ explicit Range(std::string data) : data_(std::move(data)) {}
+
+ Range(const Range& copy) = delete;
+ Range& operator=(const Range& copy) = delete;
+
+ Range(Range&& move) = default;
+ Range& operator=(Range&& move) = default;
+
+ bool empty() const {
+ return size() == 0;
+ }
+
+ size_t size() const {
+ return data_.size() - begin_offset_ - end_offset_;
+ };
+
+ void drop_front(size_t n) {
+ CHECK_GE(size(), n);
+ begin_offset_ += n;
+ }
+
+ void drop_end(size_t n) {
+ CHECK_GE(size(), n);
+ end_offset_ += n;
+ }
+
+ char* data() {
+ return &data_[0] + begin_offset_;
+ }
+
+ std::string::iterator begin() {
+ return data_.begin() + begin_offset_;
+ }
+
+ std::string::iterator end() {
+ return data_.end() - end_offset_;
+ }
+
+ std::string data_;
+ size_t begin_offset_ = 0;
+ size_t end_offset_ = 0;
+};
diff --git a/adb/socket.h b/adb/socket.h
index 64d05a9..2f09080 100644
--- a/adb/socket.h
+++ b/adb/socket.h
@@ -19,9 +19,12 @@
#include <stddef.h>
+#include <deque>
#include <memory>
+#include <string>
#include "fdevent.h"
+#include "range.h"
struct apacket;
class atransport;
@@ -31,43 +34,38 @@
* remote asocket is bound to the protocol engine.
*/
struct asocket {
- /* chain pointers for the local/remote list of
- * asockets that this asocket lives in
- */
- asocket* next;
- asocket* prev;
-
/* the unique identifier for this asocket
*/
- unsigned id;
+ unsigned id = 0;
/* flag: set when the socket's peer has closed
* but packets are still queued for delivery
*/
- int closing;
+ int closing = 0;
// flag: set when the socket failed to write, so the socket will not wait to
// write packets and close directly.
- bool has_write_error;
+ bool has_write_error = 0;
/* flag: quit adbd when both ends close the
* local service socket
*/
- int exit_on_close;
+ int exit_on_close = 0;
// the asocket we are connected to
- asocket* peer;
+ asocket* peer = nullptr;
/* For local asockets, the fde is used to bind
* us to our fd event system. For remote asockets
* these fields are not used.
*/
- fdevent fde;
- int fd;
+ fdevent fde = {};
+ int fd = 0;
- // queue of apackets waiting to be written
- apacket* pkt_first;
- apacket* pkt_last;
+ // queue of data waiting to be written
+ std::deque<Range> packet_queue;
+
+ std::string smart_socket_data;
/* enqueue is called by our peer when it has data
* for us. It should return 0 if we can accept more
@@ -75,27 +73,27 @@
* peer->ready() when we once again are ready to
* receive data.
*/
- int (*enqueue)(asocket* s, apacket* pkt);
+ int (*enqueue)(asocket* s, std::string data) = nullptr;
/* ready is called by the peer when it is ready for
* us to send data via enqueue again
*/
- void (*ready)(asocket* s);
+ void (*ready)(asocket* s) = nullptr;
/* shutdown is called by the peer before it goes away.
* the socket should not do any further calls on its peer.
* Always followed by a call to close. Optional, i.e. can be NULL.
*/
- void (*shutdown)(asocket* s);
+ void (*shutdown)(asocket* s) = nullptr;
/* close is called by the peer when it has gone away.
* we are not allowed to make any further calls on the
* peer once our close method is called.
*/
- void (*close)(asocket* s);
+ void (*close)(asocket* s) = nullptr;
/* A socket is bound to atransport */
- atransport* transport;
+ atransport* transport = nullptr;
size_t get_max_payload() const;
};
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index f7c66db..04ad6f3 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -114,10 +114,10 @@
ASSERT_TRUE(s != nullptr);
arg->bytes_written = 0;
while (true) {
- apacket* p = get_apacket();
- p->len = sizeof(p->data);
- arg->bytes_written += p->len;
- int ret = s->enqueue(s, p);
+ std::string data;
+ data.resize(MAX_PAYLOAD);
+ arg->bytes_written += data.size();
+ int ret = s->enqueue(s, std::move(data));
if (ret == 1) {
// The writer has one packet waiting to send.
break;
diff --git a/adb/sockets.cpp b/adb/sockets.cpp
index c53fbb4..307cbfe 100644
--- a/adb/sockets.cpp
+++ b/adb/sockets.cpp
@@ -37,32 +37,28 @@
#include "adb.h"
#include "adb_io.h"
+#include "range.h"
#include "transport.h"
static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex();
static unsigned local_socket_next_id = 1;
-static asocket local_socket_list = {
- .next = &local_socket_list, .prev = &local_socket_list,
-};
+static auto& local_socket_list = *new std::vector<asocket*>();
/* the the list of currently closing local sockets.
** these have no peer anymore, but still packets to
** write to their fd.
*/
-static asocket local_socket_closing_list = {
- .next = &local_socket_closing_list, .prev = &local_socket_closing_list,
-};
+static auto& local_socket_closing_list = *new std::vector<asocket*>();
// Parse the global list of sockets to find one with id |local_id|.
// If |peer_id| is not 0, also check that it is connected to a peer
// with id |peer_id|. Returns an asocket handle on success, NULL on failure.
asocket* find_local_socket(unsigned local_id, unsigned peer_id) {
- asocket* s;
- asocket* result = NULL;
+ asocket* result = nullptr;
std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
- for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+ for (asocket* s : local_socket_list) {
if (s->id != local_id) {
continue;
}
@@ -75,13 +71,6 @@
return result;
}
-static void insert_local_socket(asocket* s, asocket* list) {
- s->next = list;
- s->prev = s->next->prev;
- s->prev->next = s;
- s->next->prev = s;
-}
-
void install_local_socket(asocket* s) {
std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
@@ -92,29 +81,24 @@
fatal("local socket id overflow");
}
- insert_local_socket(s, &local_socket_list);
+ local_socket_list.push_back(s);
}
void remove_socket(asocket* s) {
std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
- if (s->prev && s->next) {
- s->prev->next = s->next;
- s->next->prev = s->prev;
- s->next = 0;
- s->prev = 0;
- s->id = 0;
+ for (auto list : { &local_socket_list, &local_socket_closing_list }) {
+ list->erase(std::remove_if(list->begin(), list->end(), [s](asocket* x) { return x == s; }),
+ list->end());
}
}
void close_all_sockets(atransport* t) {
- asocket* s;
-
/* this is a little gross, but since s->close() *will* modify
** the list out from under you, your options are limited.
*/
std::lock_guard<std::recursive_mutex> lock(local_socket_list_lock);
restart:
- for (s = local_socket_list.next; s != &local_socket_list; s = s->next) {
+ for (asocket* s : local_socket_list) {
if (s->transport == t || (s->peer && s->peer->transport == t)) {
s->close(s);
goto restart;
@@ -122,55 +106,47 @@
}
}
-static int local_socket_enqueue(asocket* s, apacket* p) {
- D("LS(%d): enqueue %zu", s->id, p->len);
+static int local_socket_enqueue(asocket* s, std::string data) {
+ D("LS(%d): enqueue %zu", s->id, data.size());
- p->ptr = p->data;
+ Range r(std::move(data));
/* if there is already data queue'd, we will receive
** events when it's time to write. just add this to
** the tail
*/
- if (s->pkt_first) {
+ if (!s->packet_queue.empty()) {
goto enqueue;
}
/* write as much as we can, until we
** would block or there is an error/eof
*/
- while (p->len > 0) {
- int r = adb_write(s->fd, p->ptr, p->len);
- if (r > 0) {
- p->len -= r;
- p->ptr += r;
+ while (!r.empty()) {
+ int rc = adb_write(s->fd, r.data(), r.size());
+ if (rc > 0) {
+ r.drop_front(rc);
continue;
}
- if ((r == 0) || (errno != EAGAIN)) {
+
+ if (rc == 0 || errno != EAGAIN) {
D("LS(%d): not ready, errno=%d: %s", s->id, errno, strerror(errno));
- put_apacket(p);
s->has_write_error = true;
s->close(s);
return 1; /* not ready (error) */
} else {
+ // errno == EAGAIN
break;
}
}
- if (p->len == 0) {
- put_apacket(p);
+ if (r.empty()) {
return 0; /* ready for more data */
}
enqueue:
- p->next = 0;
- if (s->pkt_first) {
- s->pkt_last->next = p;
- } else {
- s->pkt_first = p;
- }
- s->pkt_last = p;
-
/* make sure we are notified when we can drain the queue */
+ s->packet_queue.push_back(std::move(r));
fdevent_add(&s->fde, FDE_WRITE);
return 1; /* not ready (backlog) */
@@ -184,7 +160,6 @@
// be sure to hold the socket list lock when calling this
static void local_socket_destroy(asocket* s) {
- apacket *p, *n;
int exit_on_close = s->exit_on_close;
D("LS(%d): destroying fde.fd=%d", s->id, s->fde.fd);
@@ -194,14 +169,8 @@
*/
fdevent_remove(&s->fde);
- /* dispose of any unwritten data */
- for (p = s->pkt_first; p; p = n) {
- D("LS(%d): discarding %zu bytes", s->id, p->len);
- n = p->next;
- put_apacket(p);
- }
remove_socket(s);
- free(s);
+ delete s;
if (exit_on_close) {
D("local_socket_destroy: exiting");
@@ -229,7 +198,7 @@
/* If we are already closing, or if there are no
** pending packets, destroy immediately
*/
- if (s->closing || s->has_write_error || s->pkt_first == NULL) {
+ if (s->closing || s->has_write_error || s->packet_queue.empty()) {
int id = s->id;
local_socket_destroy(s);
D("LS(%d): closed", id);
@@ -243,7 +212,7 @@
fdevent_del(&s->fde, FDE_READ);
remove_socket(s);
D("LS(%d): put on socket_closing_list fd=%d", s->id, s->fd);
- insert_local_socket(s, &local_socket_closing_list);
+ local_socket_closing_list.push_back(s);
CHECK_EQ(FDE_WRITE, s->fde.state & FDE_WRITE);
}
@@ -255,35 +224,30 @@
** in order to simplify the code.
*/
if (ev & FDE_WRITE) {
- apacket* p;
- while ((p = s->pkt_first) != nullptr) {
- while (p->len > 0) {
- int r = adb_write(fd, p->ptr, p->len);
- if (r == -1) {
+ while (!s->packet_queue.empty()) {
+ Range& r = s->packet_queue.front();
+ while (!r.empty()) {
+ int rc = adb_write(fd, r.data(), r.size());
+ if (rc == -1) {
/* returning here is ok because FDE_READ will
** be processed in the next iteration loop
*/
if (errno == EAGAIN) {
return;
}
- } else if (r > 0) {
- p->ptr += r;
- p->len -= r;
+ } else if (rc > 0) {
+ r.drop_front(rc);
continue;
}
- D(" closing after write because r=%d and errno is %d", r, errno);
+ D(" closing after write because rc=%d and errno is %d", rc, errno);
s->has_write_error = true;
s->close(s);
return;
}
- if (p->len == 0) {
- s->pkt_first = p->next;
- if (s->pkt_first == 0) {
- s->pkt_last = 0;
- }
- put_apacket(p);
+ if (r.empty()) {
+ s->packet_queue.pop_front();
}
}
@@ -305,9 +269,10 @@
}
if (ev & FDE_READ) {
- apacket* p = get_apacket();
- char* x = p->data;
const size_t max_payload = s->get_max_payload();
+ std::string data;
+ data.resize(max_payload);
+ char* x = &data[0];
size_t avail = max_payload;
int r = 0;
int is_eof = 0;
@@ -332,16 +297,15 @@
}
D("LS(%d): fd=%d post avail loop. r=%d is_eof=%d forced_eof=%d", s->id, s->fd, r, is_eof,
s->fde.force_eof);
- if ((avail == max_payload) || (s->peer == 0)) {
- put_apacket(p);
- } else {
- p->len = max_payload - avail;
+
+ if (avail != max_payload && s->peer) {
+ data.resize(max_payload - avail);
// s->peer->enqueue() may call s->close() and free s,
// so save variables for debug printing below.
unsigned saved_id = s->id;
int saved_fd = s->fd;
- r = s->peer->enqueue(s->peer, p);
+ r = s->peer->enqueue(s->peer, std::move(data));
D("LS(%u): fd=%d post peer->enqueue(). r=%d", saved_id, saved_fd, r);
if (r < 0) {
@@ -383,10 +347,7 @@
}
asocket* create_local_socket(int fd) {
- asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
- if (s == NULL) {
- fatal("cannot allocate socket");
- }
+ asocket* s = new asocket();
s->fd = fd;
s->enqueue = local_socket_enqueue;
s->ready = local_socket_ready;
@@ -445,12 +406,22 @@
}
#endif /* ADB_HOST */
-static int remote_socket_enqueue(asocket* s, apacket* p) {
+static int remote_socket_enqueue(asocket* s, std::string data) {
D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd);
+ apacket* p = get_apacket();
+
p->msg.command = A_WRTE;
p->msg.arg0 = s->peer->id;
p->msg.arg1 = s->id;
- p->msg.data_length = p->len;
+ p->msg.data_length = data.size();
+
+ if (data.size() > sizeof(p->data)) {
+ put_apacket(p);
+ return -1;
+ }
+
+ // TODO: Convert apacket::data to a type that we can move into.
+ memcpy(p->data, data.data(), data.size());
send_packet(p, s->transport);
return 1;
}
@@ -485,7 +456,7 @@
D("entered remote_socket_close RS(%d) CLOSE fd=%d peer->fd=%d", s->id, s->fd,
s->peer ? s->peer->fd : -1);
D("RS(%d): closed", s->id);
- free(s);
+ delete s;
}
// Create a remote socket to exchange packets with a remote service through transport
@@ -496,11 +467,7 @@
if (id == 0) {
fatal("invalid remote socket id (0)");
}
- asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
-
- if (s == NULL) {
- fatal("cannot allocate socket");
- }
+ asocket* s = new asocket();
s->id = id;
s->enqueue = remote_socket_enqueue;
s->ready = remote_socket_ready;
@@ -550,7 +517,7 @@
s->close(s);
}
-static unsigned unhex(char* s, int len) {
+static unsigned unhex(const char* s, int len) {
unsigned n = 0, c;
while (len-- > 0) {
@@ -654,8 +621,7 @@
#endif // ADB_HOST
-static int smart_socket_enqueue(asocket* s, apacket* p) {
- unsigned len;
+static int smart_socket_enqueue(asocket* s, std::string data) {
#if ADB_HOST
char* service = nullptr;
char* serial = nullptr;
@@ -663,49 +629,38 @@
TransportType type = kTransportAny;
#endif
- D("SS(%d): enqueue %zu", s->id, p->len);
+ D("SS(%d): enqueue %zu", s->id, data.size());
- if (s->pkt_first == 0) {
- s->pkt_first = p;
- s->pkt_last = p;
+ if (s->smart_socket_data.empty()) {
+ s->smart_socket_data = std::move(data);
} else {
- if ((s->pkt_first->len + p->len) > s->get_max_payload()) {
- D("SS(%d): overflow", s->id);
- put_apacket(p);
- goto fail;
- }
-
- memcpy(s->pkt_first->data + s->pkt_first->len, p->data, p->len);
- s->pkt_first->len += p->len;
- put_apacket(p);
-
- p = s->pkt_first;
+ std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
}
/* don't bother if we can't decode the length */
- if (p->len < 4) {
+ if (s->smart_socket_data.size() < 4) {
return 0;
}
- len = unhex(p->data, 4);
- if ((len < 1) || (len > MAX_PAYLOAD)) {
- D("SS(%d): bad size (%d)", s->id, len);
+ uint32_t len = unhex(s->smart_socket_data.data(), 4);
+ if (len == 0 || len > MAX_PAYLOAD) {
+ D("SS(%d): bad size (%u)", s->id, len);
goto fail;
}
- D("SS(%d): len is %d", s->id, len);
+ D("SS(%d): len is %u", s->id, len);
/* can't do anything until we have the full header */
- if ((len + 4) > p->len) {
- D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - p->len);
+ if ((len + 4) > s->smart_socket_data.size()) {
+ D("SS(%d): waiting for %zu more bytes", s->id, len + 4 - s->smart_socket_data.size());
return 0;
}
- p->data[len + 4] = 0;
+ s->smart_socket_data[len + 4] = 0;
- D("SS(%d): '%s'", s->id, (char*)(p->data + 4));
+ D("SS(%d): '%s'", s->id, (char*)(s->smart_socket_data.data() + 4));
#if ADB_HOST
- service = (char*)p->data + 4;
+ service = &s->smart_socket_data[4];
if (!strncmp(service, "host-serial:", strlen("host-serial:"))) {
char* serial_end;
service += strlen("host-serial:");
@@ -753,7 +708,7 @@
}
if (!strncmp(service, "transport", strlen("transport"))) {
D("SS(%d): okay transport", s->id);
- p->len = 0;
+ s->smart_socket_data.clear();
return 0;
}
@@ -824,7 +779,7 @@
/* give him our transport and upref it */
s->peer->transport = s->transport;
- connect_to_remote(s->peer, (char*)(p->data + 4));
+ connect_to_remote(s->peer, s->smart_socket_data.data() + 4);
s->peer = 0;
s->close(s);
return 1;
@@ -844,21 +799,17 @@
static void smart_socket_close(asocket* s) {
D("SS(%d): closed", s->id);
- if (s->pkt_first) {
- put_apacket(s->pkt_first);
- }
if (s->peer) {
s->peer->peer = 0;
s->peer->close(s->peer);
s->peer = 0;
}
- free(s);
+ delete s;
}
static asocket* create_smart_socket(void) {
D("Creating smart socket");
- asocket* s = reinterpret_cast<asocket*>(calloc(1, sizeof(asocket)));
- if (s == NULL) fatal("cannot allocate socket");
+ asocket* s = new asocket();
s->enqueue = smart_socket_enqueue;
s->ready = smart_socket_ready;
s->shutdown = NULL;
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 5acaaec..9ae1297 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -72,6 +72,11 @@
return false;
}
+ if (packet->msg.data_length > sizeof(packet->data)) {
+ D("remote local: read overflow (data length = %" PRIu32 ")", packet->msg.data_length);
+ return false;
+ }
+
if (!ReadFdExactly(fd_.get(), &packet->data, packet->msg.data_length)) {
D("remote local: terminated (data)");
return false;
@@ -373,9 +378,9 @@
*/
struct device_tracker {
asocket socket;
- bool update_needed;
- bool long_output;
- device_tracker* next;
+ bool update_needed = false;
+ bool long_output = false;
+ device_tracker* next = nullptr;
};
/* linked list of all device trackers */
@@ -406,24 +411,25 @@
peer->close(peer);
}
device_tracker_remove(tracker);
- free(tracker);
+ delete tracker;
}
-static int device_tracker_enqueue(asocket* socket, apacket* p) {
+static int device_tracker_enqueue(asocket* socket, std::string) {
/* you can't read from a device tracker, close immediately */
- put_apacket(p);
device_tracker_close(socket);
return -1;
}
static int device_tracker_send(device_tracker* tracker, const std::string& string) {
- apacket* p = get_apacket();
asocket* peer = tracker->socket.peer;
- snprintf(reinterpret_cast<char*>(p->data), 5, "%04x", static_cast<int>(string.size()));
- memcpy(&p->data[4], string.data(), string.size());
- p->len = 4 + string.size();
- return peer->enqueue(peer, p);
+ std::string data;
+ data.resize(4 + string.size());
+ char buf[5];
+ snprintf(buf, sizeof(buf), "%04x", static_cast<int>(string.size()));
+ memcpy(&data[0], buf, 4);
+ memcpy(&data[4], string.data(), string.size());
+ return peer->enqueue(peer, std::move(data));
}
static void device_tracker_ready(asocket* socket) {
@@ -440,7 +446,7 @@
}
asocket* create_device_tracker(bool long_output) {
- device_tracker* tracker = reinterpret_cast<device_tracker*>(calloc(1, sizeof(*tracker)));
+ device_tracker* tracker = new device_tracker();
if (tracker == nullptr) fatal("cannot allocate device tracker");
D("device tracker %p created", tracker);
diff --git a/adb/transport_usb.cpp b/adb/transport_usb.cpp
index 73e8e15..a108699 100644
--- a/adb/transport_usb.cpp
+++ b/adb/transport_usb.cpp
@@ -61,6 +61,10 @@
static int UsbReadPayload(usb_handle* h, apacket* p) {
D("UsbReadPayload(%d)", p->msg.data_length);
+ if (p->msg.data_length > sizeof(p->data)) {
+ return -1;
+ }
+
#if CHECK_PACKET_OVERFLOW
size_t usb_packet_size = usb_get_max_packet_size(h);
CHECK_EQ(0ULL, sizeof(p->data) % usb_packet_size);
@@ -116,6 +120,11 @@
}
if (p->msg.data_length) {
+ if (p->msg.data_length > sizeof(p->data)) {
+ PLOG(ERROR) << "remote usb: read overflow (data length = " << p->msg.data_length << ")";
+ return -1;
+ }
+
if (usb_read(usb, p->data, p->msg.data_length)) {
PLOG(ERROR) << "remote usb: terminated (data)";
return -1;
diff --git a/base/Android.bp b/base/Android.bp
index 01800af..6cadcfc 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -45,6 +45,7 @@
support_system_process: true,
},
srcs: [
+ "chrono_utils.cpp",
"file.cpp",
"logging.cpp",
"parsenetaddress.cpp",
@@ -72,14 +73,12 @@
},
linux: {
srcs: [
- "chrono_utils.cpp",
"errors_unix.cpp",
],
cppflags: ["-Wexit-time-destructors"],
},
darwin: {
srcs: [
- "chrono_utils.cpp",
"errors_unix.cpp",
],
cppflags: ["-Wexit-time-destructors"],
diff --git a/base/chrono_utils.cpp b/base/chrono_utils.cpp
index dbe5483..19080a5 100644
--- a/base/chrono_utils.cpp
+++ b/base/chrono_utils.cpp
@@ -28,7 +28,7 @@
return boot_clock::time_point(std::chrono::seconds(ts.tv_sec) +
std::chrono::nanoseconds(ts.tv_nsec));
#else
- // Darwin does not support clock_gettime.
+ // Darwin and Windows do not support clock_gettime.
return boot_clock::time_point();
#endif // __linux__
}
diff --git a/base/include/android-base/chrono_utils.h b/base/include/android-base/chrono_utils.h
index 7679d4c..c3396ee 100644
--- a/base/include/android-base/chrono_utils.h
+++ b/base/include/android-base/chrono_utils.h
@@ -20,7 +20,9 @@
#include <chrono>
#include <sstream>
+#if __cplusplus > 201103L // C++14
using namespace std::chrono_literals;
+#endif
namespace android {
namespace base {
diff --git a/base/properties.cpp b/base/properties.cpp
index cde4d69..ca8e96f 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -23,6 +23,7 @@
#include <algorithm>
#include <chrono>
+#include <limits>
#include <string>
#include <android-base/parseint.h>
@@ -109,7 +110,7 @@
static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
- ts.tv_sec = s.count();
+ ts.tv_sec = std::min<std::chrono::seconds::rep>(s.count(), std::numeric_limits<time_t>::max());
ts.tv_nsec = ns.count();
}
diff --git a/bootstat/Android.bp b/bootstat/Android.bp
index 2c87018..dd9ba88 100644
--- a/bootstat/Android.bp
+++ b/bootstat/Android.bp
@@ -66,6 +66,9 @@
shared_libs: ["liblogcat"],
init_rc: ["bootstat.rc"],
product_variables: {
+ pdk: {
+ enabled: false,
+ },
debuggable: {
init_rc: ["bootstat-debug.rc"],
},
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 5fddddc..364fca5 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -55,7 +55,7 @@
using android::base::unique_fd;
using unwindstack::Regs;
-extern "C" void __linker_enable_fallback_allocator();
+extern "C" bool __linker_enable_fallback_allocator();
extern "C" void __linker_disable_fallback_allocator();
// This is incredibly sketchy to do inside of a signal handler, especially when libbacktrace
@@ -65,7 +65,11 @@
// This isn't the default method of dumping because it can fail in cases such as address space
// exhaustion.
static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) {
- __linker_enable_fallback_allocator();
+ if (!__linker_enable_fallback_allocator()) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
+ return;
+ }
+
{
std::unique_ptr<Regs> regs;
@@ -84,7 +88,11 @@
static void debuggerd_fallback_tombstone(int output_fd, ucontext_t* ucontext, siginfo_t* siginfo,
void* abort_message) {
- __linker_enable_fallback_allocator();
+ if (!__linker_enable_fallback_allocator()) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "fallback allocator already in use");
+ return;
+ }
+
engrave_tombstone_ucontext(output_fd, reinterpret_cast<uintptr_t>(abort_message), siginfo,
ucontext);
__linker_disable_fallback_allocator();
@@ -116,7 +124,7 @@
closedir(dir);
}
-static bool forward_output(int src_fd, int dst_fd) {
+static bool forward_output(int src_fd, int dst_fd, pid_t expected_tid) {
// Make sure the thread actually got the signal.
struct pollfd pfd = {
.fd = src_fd, .events = POLLIN,
@@ -127,6 +135,18 @@
return false;
}
+ pid_t tid;
+ if (TEMP_FAILURE_RETRY(read(src_fd, &tid, sizeof(tid))) != sizeof(tid)) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to read tid");
+ return false;
+ }
+
+ if (tid != expected_tid) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "received tid %d, expected %d", tid,
+ expected_tid);
+ return false;
+ }
+
while (true) {
char buf[512];
ssize_t rc = TEMP_FAILURE_RETRY(read(src_fd, buf, sizeof(buf)));
@@ -144,16 +164,54 @@
}
}
+struct __attribute__((__packed__)) packed_thread_output {
+ int32_t tid;
+ int32_t fd;
+};
+
+static uint64_t pack_thread_fd(pid_t tid, int fd) {
+ packed_thread_output packed = {.tid = tid, .fd = fd};
+ uint64_t result;
+ static_assert(sizeof(packed) == sizeof(result));
+ memcpy(&result, &packed, sizeof(packed));
+ return result;
+}
+
+static std::pair<pid_t, int> unpack_thread_fd(uint64_t value) {
+ packed_thread_output result;
+ memcpy(&result, &value, sizeof(value));
+ return std::make_pair(result.tid, result.fd);
+}
+
static void trace_handler(siginfo_t* info, ucontext_t* ucontext) {
- static std::atomic<int> trace_output_fd(-1);
+ static std::atomic<uint64_t> trace_output(pack_thread_fd(-1, -1));
if (info->si_value.sival_int == ~0) {
// Asked to dump by the original signal recipient.
- debuggerd_fallback_trace(trace_output_fd, ucontext);
+ uint64_t val = trace_output.load();
+ auto [tid, fd] = unpack_thread_fd(val);
+ if (tid != gettid()) {
+ // We received some other thread's info request?
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "thread %d received output fd for thread %d?", gettid(), tid);
+ return;
+ }
- int tmp = trace_output_fd.load();
- trace_output_fd.store(-1);
- close(tmp);
+ if (!trace_output.compare_exchange_strong(val, pack_thread_fd(-1, -1))) {
+ // Presumably, the timeout in forward_output expired, and the main thread moved on.
+ // If this happened, the main thread closed our fd for us, so just return.
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "cmpxchg for thread %d failed", gettid());
+ return;
+ }
+
+ // Write our tid to the output fd to let the main thread know that we're working.
+ if (TEMP_FAILURE_RETRY(write(fd, &tid, sizeof(tid))) == sizeof(tid)) {
+ debuggerd_fallback_trace(fd, ucontext);
+ } else {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write to output fd");
+ }
+
+ close(fd);
return;
}
@@ -189,7 +247,14 @@
return false;
}
- trace_output_fd.store(pipe_write.get());
+ uint64_t expected = pack_thread_fd(-1, -1);
+ if (!trace_output.compare_exchange_strong(expected,
+ pack_thread_fd(tid, pipe_write.release()))) {
+ auto [tid, fd] = unpack_thread_fd(expected);
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "thread %d is already outputting to fd %d?", tid, fd);
+ return false;
+ }
siginfo_t siginfo = {};
siginfo.si_code = SI_QUEUE;
@@ -203,12 +268,20 @@
return false;
}
- bool success = forward_output(pipe_read.get(), output_fd);
- if (success) {
- // The signaled thread has closed trace_output_fd already.
- (void)pipe_write.release();
- } else {
- trace_output_fd.store(-1);
+ bool success = forward_output(pipe_read.get(), output_fd, tid);
+ if (!success) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "timeout expired while waiting for thread %d to dump", tid);
+ }
+
+ // Regardless of whether the poll succeeds, check to see if the thread took fd ownership.
+ uint64_t post_wait = trace_output.exchange(pack_thread_fd(-1, -1));
+ if (post_wait != pack_thread_fd(-1, -1)) {
+ auto [tid, fd] = unpack_thread_fd(post_wait);
+ if (fd != -1) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc", "closing fd %d for thread %d", fd, tid);
+ close(fd);
+ }
}
return true;
diff --git a/debuggerd/seccomp_policy/crash_dump.arm.policy b/debuggerd/seccomp_policy/crash_dump.arm.policy
index c64e288..b1f459d 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm.policy
@@ -22,6 +22,7 @@
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
+rt_sigaction: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
@@ -30,7 +31,6 @@
getuid32: 1
fstat64: 1
mmap2: arg2 in PROT_READ|PROT_WRITE
-sigaction: 1
geteuid32: 1
getgid32: 1
getegid32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.arm64.policy b/debuggerd/seccomp_policy/crash_dump.arm64.policy
index 0c689bb..e5e7afb 100644
--- a/debuggerd/seccomp_policy/crash_dump.arm64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.arm64.policy
@@ -21,6 +21,7 @@
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
+rt_sigaction: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
@@ -29,7 +30,6 @@
getuid: 1
fstat: 1
mmap: arg2 in PROT_READ|PROT_WRITE
-rt_sigaction: 1
geteuid: 1
getgid: 1
getegid: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.policy.def b/debuggerd/seccomp_policy/crash_dump.policy.def
index dadffac..b78c94a 100644
--- a/debuggerd/seccomp_policy/crash_dump.policy.def
+++ b/debuggerd/seccomp_policy/crash_dump.policy.def
@@ -29,6 +29,7 @@
tgkill: 1
rt_sigprocmask: 1
+rt_sigaction: 1
rt_tgsigqueueinfo: 1
#define PR_SET_VMA 0x53564d41
@@ -42,12 +43,10 @@
getuid: 1
fstat: 1
mmap: arg2 in PROT_READ|PROT_WRITE
-rt_sigaction: 1
#else
getuid32: 1
fstat64: 1
mmap2: arg2 in PROT_READ|PROT_WRITE
-sigaction: 1
#endif
// Needed for logging.
diff --git a/debuggerd/seccomp_policy/crash_dump.x86.policy b/debuggerd/seccomp_policy/crash_dump.x86.policy
index c64e288..b1f459d 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86.policy
@@ -22,6 +22,7 @@
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
+rt_sigaction: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
@@ -30,7 +31,6 @@
getuid32: 1
fstat64: 1
mmap2: arg2 in PROT_READ|PROT_WRITE
-sigaction: 1
geteuid32: 1
getgid32: 1
getegid32: 1
diff --git a/debuggerd/seccomp_policy/crash_dump.x86_64.policy b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
index 0c689bb..e5e7afb 100644
--- a/debuggerd/seccomp_policy/crash_dump.x86_64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.x86_64.policy
@@ -21,6 +21,7 @@
process_vm_readv: 1
tgkill: 1
rt_sigprocmask: 1
+rt_sigaction: 1
rt_tgsigqueueinfo: 1
prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
madvise: 1
@@ -29,7 +30,6 @@
getuid: 1
fstat: 1
mmap: arg2 in PROT_READ|PROT_WRITE
-rt_sigaction: 1
geteuid: 1
getgid: 1
getegid: 1
diff --git a/demangle/DemangleTest.cpp b/demangle/DemangleTest.cpp
index 46a6f76..1787031 100644
--- a/demangle/DemangleTest.cpp
+++ b/demangle/DemangleTest.cpp
@@ -509,6 +509,29 @@
ASSERT_EQ("_ZTH_N3oneE", demangler.Parse("_ZTH_N3oneE"));
}
+TEST(DemangleTest, r_value_reference) {
+ Demangler demangler;
+ ASSERT_EQ(
+ "android::SurfaceComposerClient::Transaction::merge(android::SurfaceComposerClient::"
+ "Transaction&&)",
+ demangler.Parse("_ZN7android21SurfaceComposerClient11Transaction5mergeEOS1_"));
+}
+
+TEST(DemangleTest, initial_St) {
+ Demangler demangler;
+ EXPECT_EQ("std::state", demangler.Parse("_ZSt5state"));
+ EXPECT_EQ("std::_In::ward", demangler.Parse("_ZNSt3_In4wardE"));
+ EXPECT_EQ("std::__terminate(void (*)())", demangler.Parse("_ZSt11__terminatePFvvE"));
+}
+
+TEST(DemangleTest, cfi) {
+ Demangler demangler;
+ EXPECT_EQ("nfa_sys_ptim_timer_update(tPTIM_CB*)",
+ demangler.Parse("_Z25nfa_sys_ptim_timer_updateP8tPTIM_CB"));
+ EXPECT_EQ("nfa_sys_ptim_timer_update(tPTIM_CB*) [clone .cfi]",
+ demangler.Parse("_Z25nfa_sys_ptim_timer_updateP8tPTIM_CB.cfi"));
+}
+
TEST(DemangleTest, demangle) {
std::string str;
diff --git a/demangle/Demangler.cpp b/demangle/Demangler.cpp
index af2816c..7a3aa81 100644
--- a/demangle/Demangler.cpp
+++ b/demangle/Demangler.cpp
@@ -580,6 +580,10 @@
}
return name + 1;
+ case 'O':
+ cur_state_.suffixes.push_back("&&");
+ return name + 1;
+
case 'K':
case 'V': {
const char* suffix;
@@ -701,6 +705,9 @@
cur_state_.str.clear();
}
return name;
+ } else if (strcmp(name, ".cfi") == 0) {
+ function_suffix_ += " [clone .cfi]";
+ return name + 4;
}
}
return nullptr;
@@ -816,6 +823,16 @@
return name + 1;
}
+ if (*name == 'S') {
+ name++;
+ if (*name == 't') {
+ function_name_ = "std::";
+ name++;
+ } else {
+ return nullptr;
+ }
+ }
+
if (std::isdigit(*name)) {
name = GetStringFromLength(name, &function_name_);
} else if (*name == 'L' && std::isdigit(name[1])) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index a2b80ad..9aab0ba 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -32,11 +32,14 @@
#include <unistd.h>
#include <memory>
+#include <string>
#include <thread>
+#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <cutils/android_filesystem_config.h>
#include <cutils/android_reboot.h>
@@ -775,6 +778,22 @@
}
}
+static bool call_vdc(const std::vector<std::string>& args) {
+ std::vector<char const*> argv;
+ argv.emplace_back("/system/bin/vdc");
+ for (auto& arg : args) {
+ argv.emplace_back(arg.c_str());
+ }
+ LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
+ int ret = android_fork_execvp(4, const_cast<char**>(argv.data()), nullptr, false, true);
+ if (ret != 0) {
+ LOG(ERROR) << "vdc returned error code: " << ret;
+ return false;
+ }
+ LOG(DEBUG) << "vdc finished successfully";
+ return true;
+}
+
/* 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.
@@ -881,6 +900,13 @@
LERROR << "Only one encryptable/encrypted partition supported";
}
encryptable = status;
+ if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
+ if (!call_vdc(
+ {"cryptfs", "encryptFstab", fstab->recs[attempted_idx].mount_point})) {
+ LERROR << "Encryption failed";
+ return FS_MGR_MNTALL_FAIL;
+ }
+ }
}
/* Success! Go get the next one */
@@ -955,7 +981,11 @@
encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED;
} else if (mret && mount_errno != EBUSY && mount_errno != EACCES &&
should_use_metadata_encryption(&fstab->recs[attempted_idx])) {
+ if (!call_vdc({"cryptfs", "mountFstab", fstab->recs[attempted_idx].mount_point})) {
+ ++error_count;
+ }
encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED;
+ continue;
} else {
// fs_options might be null so we cannot use PERROR << directly.
// Use StringPrintf to output "(null)" instead.
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 676ee41..08b8b26 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -42,7 +42,6 @@
#define POWER_SUPPLY_SYSFS_PATH "/sys/class/" POWER_SUPPLY_SUBSYSTEM
#define FAKE_BATTERY_CAPACITY 42
#define FAKE_BATTERY_TEMPERATURE 424
-#define ALWAYS_PLUGGED_CAPACITY 100
#define MILLION 1.0e6
#define DEFAULT_VBUS_VOLTAGE 5000000
@@ -81,8 +80,11 @@
props->batteryTechnology.clear();
}
-BatteryMonitor::BatteryMonitor() : mHealthdConfig(nullptr), mBatteryDevicePresent(false),
- mAlwaysPluggedDevice(false), mBatteryFixedCapacity(0), mBatteryFixedTemperature(0) {
+BatteryMonitor::BatteryMonitor()
+ : mHealthdConfig(nullptr),
+ mBatteryDevicePresent(false),
+ mBatteryFixedCapacity(0),
+ mBatteryFixedTemperature(0) {
initBatteryProperties(&props);
}
@@ -223,15 +225,6 @@
mBatteryFixedTemperature :
getIntField(mHealthdConfig->batteryTemperaturePath);
- // For devices which do not have battery and are always plugged
- // into power souce.
- if (mAlwaysPluggedDevice) {
- props.chargerAcOnline = true;
- props.batteryPresent = true;
- props.batteryStatus = BATTERY_STATUS_CHARGING;
- props.batteryHealth = BATTERY_HEALTH_GOOD;
- }
-
std::string buf;
if (readFromFile(mHealthdConfig->batteryStatusPath, &buf) > 0)
@@ -405,11 +398,7 @@
break;
case BATTERY_PROP_BATTERY_STATUS:
- if (mAlwaysPluggedDevice) {
- val->valueInt64 = BATTERY_STATUS_CHARGING;
- } else {
- val->valueInt64 = getChargeStatus();
- }
+ val->valueInt64 = getChargeStatus();
ret = NO_ERROR;
break;
@@ -628,9 +617,6 @@
KLOG_WARNING(LOG_TAG, "No battery devices found\n");
hc->periodic_chores_interval_fast = -1;
hc->periodic_chores_interval_slow = -1;
- mBatteryFixedCapacity = ALWAYS_PLUGGED_CAPACITY;
- mBatteryFixedTemperature = FAKE_BATTERY_TEMPERATURE;
- mAlwaysPluggedDevice = true;
} else {
if (mHealthdConfig->batteryStatusPath.isEmpty())
KLOG_WARNING(LOG_TAG, "BatteryStatusPath not found\n");
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 8865a7d..194e667 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -48,7 +48,6 @@
struct healthd_config *mHealthdConfig;
Vector<String8> mChargerNames;
bool mBatteryDevicePresent;
- bool mAlwaysPluggedDevice;
int mBatteryFixedCapacity;
int mBatteryFixedTemperature;
struct BatteryProperties props;
diff --git a/init/Android.bp b/init/Android.bp
index 6c80ee6..1f2ad2e 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -93,6 +93,8 @@
defaults: ["init_defaults"],
srcs: [
"action.cpp",
+ "action_manager.cpp",
+ "action_parser.cpp",
"bootchart.cpp",
"builtins.cpp",
"capabilities.cpp",
diff --git a/init/action.cpp b/init/action.cpp
index ba03e66..11335ca 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -21,11 +21,9 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
-#include "stable_properties.h"
#include "util.h"
using android::base::Join;
-using android::base::StartsWith;
namespace android {
namespace init {
@@ -70,8 +68,15 @@
return Join(args_, ' ');
}
-Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line)
- : oneshot_(oneshot), subcontext_(subcontext), filename_(filename), line_(line) {}
+Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
+ const std::string& event_trigger,
+ const std::map<std::string, std::string>& property_triggers)
+ : property_triggers_(property_triggers),
+ event_trigger_(event_trigger),
+ oneshot_(oneshot),
+ subcontext_(subcontext),
+ filename_(filename),
+ line_(line) {}
const KeywordFunctionMap* Action::function_map_ = nullptr;
@@ -135,85 +140,6 @@
}
}
-static bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
- static bool enabled =
- android::base::GetBoolProperty("ro.actionable_compatible_property.enabled", false);
-
- if (subcontext == nullptr || !enabled) {
- return true;
- }
-
- if (kExportedActionableProperties.count(prop_name) == 1) {
- return true;
- }
- for (const auto& prefix : kPartnerPrefixes) {
- if (android::base::StartsWith(prop_name, prefix)) {
- return true;
- }
- }
- return false;
-}
-
-Result<Success> Action::ParsePropertyTrigger(const std::string& trigger) {
- const static std::string prop_str("property:");
- std::string prop_name(trigger.substr(prop_str.length()));
- size_t equal_pos = prop_name.find('=');
- if (equal_pos == std::string::npos) {
- return Error() << "property trigger found without matching '='";
- }
-
- std::string prop_value(prop_name.substr(equal_pos + 1));
- prop_name.erase(equal_pos);
-
- if (!IsActionableProperty(subcontext_, prop_name)) {
- return Error() << "unexported property tigger found: " << prop_name;
- }
-
- if (auto [it, inserted] = property_triggers_.emplace(prop_name, prop_value); !inserted) {
- return Error() << "multiple property triggers found for same property";
- }
- return Success();
-}
-
-Result<Success> Action::InitTriggers(const std::vector<std::string>& args) {
- const static std::string prop_str("property:");
- for (std::size_t i = 0; i < args.size(); ++i) {
- if (args[i].empty()) {
- return Error() << "empty trigger is not valid";
- }
-
- if (i % 2) {
- if (args[i] != "&&") {
- return Error() << "&& is the only symbol allowed to concatenate actions";
- } else {
- continue;
- }
- }
-
- if (!args[i].compare(0, prop_str.length(), prop_str)) {
- if (auto result = ParsePropertyTrigger(args[i]); !result) {
- return result;
- }
- } else {
- if (!event_trigger_.empty()) {
- return Error() << "multiple event triggers are not allowed";
- }
-
- event_trigger_ = args[i];
- }
- }
-
- return Success();
-}
-
-Result<Success> Action::InitSingleTrigger(const std::string& trigger) {
- std::vector<std::string> name_vector{trigger};
- if (auto result = InitTriggers(name_vector); !result) {
- return Error() << "InitTriggers() failed: " << result.error();
- }
- return Success();
-}
-
// This function checks that all property triggers are satisfied, that is
// for each (name, value) in property_triggers_, check that the current
// value of the property 'name' == value.
@@ -281,142 +207,5 @@
}
}
-ActionManager::ActionManager() : current_command_(0) {
-}
-
-ActionManager& ActionManager::GetInstance() {
- static ActionManager instance;
- return instance;
-}
-
-void ActionManager::AddAction(std::unique_ptr<Action> action) {
- actions_.emplace_back(std::move(action));
-}
-
-void ActionManager::QueueEventTrigger(const std::string& trigger) {
- event_queue_.emplace(trigger);
-}
-
-void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
- event_queue_.emplace(std::make_pair(name, value));
-}
-
-void ActionManager::QueueAllPropertyActions() {
- QueuePropertyChange("", "");
-}
-
-void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
- auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0);
- std::vector<std::string> name_vector{name};
-
- if (auto result = action->InitSingleTrigger(name); !result) {
- LOG(ERROR) << "Cannot queue BuiltinAction for " << name << ": " << result.error();
- return;
- }
-
- action->AddCommand(func, name_vector, 0);
-
- event_queue_.emplace(action.get());
- actions_.emplace_back(std::move(action));
-}
-
-void ActionManager::ExecuteOneCommand() {
- // Loop through the event queue until we have an action to execute
- while (current_executing_actions_.empty() && !event_queue_.empty()) {
- for (const auto& action : actions_) {
- if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
- event_queue_.front())) {
- current_executing_actions_.emplace(action.get());
- }
- }
- event_queue_.pop();
- }
-
- if (current_executing_actions_.empty()) {
- return;
- }
-
- auto action = current_executing_actions_.front();
-
- if (current_command_ == 0) {
- std::string trigger_name = action->BuildTriggersString();
- LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
- << ":" << action->line() << ")";
- }
-
- action->ExecuteOneCommand(current_command_);
-
- // If this was the last command in the current action, then remove
- // the action from the executing list.
- // If this action was oneshot, then also remove it from actions_.
- ++current_command_;
- if (current_command_ == action->NumCommands()) {
- current_executing_actions_.pop();
- current_command_ = 0;
- if (action->oneshot()) {
- auto eraser = [&action] (std::unique_ptr<Action>& a) {
- return a.get() == action;
- };
- actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
- }
- }
-}
-
-bool ActionManager::HasMoreCommands() const {
- return !current_executing_actions_.empty() || !event_queue_.empty();
-}
-
-void ActionManager::DumpState() const {
- for (const auto& a : actions_) {
- a->DumpState();
- }
-}
-
-void ActionManager::ClearQueue() {
- // We are shutting down so don't claim the oneshot builtin actions back
- current_executing_actions_ = {};
- event_queue_ = {};
- current_command_ = 0;
-}
-
-Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
- const std::string& filename, int line) {
- std::vector<std::string> triggers(args.begin() + 1, args.end());
- if (triggers.size() < 1) {
- return Error() << "Actions must have a trigger";
- }
-
- Subcontext* action_subcontext = nullptr;
- if (subcontexts_) {
- for (auto& subcontext : *subcontexts_) {
- if (StartsWith(filename, subcontext.path_prefix())) {
- action_subcontext = &subcontext;
- break;
- }
- }
- }
-
- auto action = std::make_unique<Action>(false, action_subcontext, filename, line);
-
- if (auto result = action->InitTriggers(triggers); !result) {
- return Error() << "InitTriggers() failed: " << result.error();
- }
-
- action_ = std::move(action);
- return Success();
-}
-
-Result<Success> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
- return action_ ? action_->AddCommand(std::move(args), line) : Success();
-}
-
-Result<Success> ActionParser::EndSection() {
- if (action_ && action_->NumCommands() > 0) {
- action_manager_->AddAction(std::move(action_));
- }
-
- return Success();
-}
-
} // namespace init
} // namespace android
diff --git a/init/action.h b/init/action.h
index 1bfc6c7..4f063cc 100644
--- a/init/action.h
+++ b/init/action.h
@@ -25,7 +25,6 @@
#include "builtins.h"
#include "keyword_map.h"
-#include "parser.h"
#include "result.h"
#include "subcontext.h"
@@ -58,12 +57,12 @@
class Action {
public:
- Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line);
+ Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
+ const std::string& event_trigger,
+ const std::map<std::string, std::string>& property_triggers);
Result<Success> AddCommand(const std::vector<std::string>& args, int line);
void AddCommand(BuiltinFunction f, const std::vector<std::string>& args, int line);
- Result<Success> InitTriggers(const std::vector<std::string>& args);
- Result<Success> InitSingleTrigger(const std::string& trigger);
std::size_t NumCommands() const;
void ExecuteOneCommand(std::size_t command) const;
void ExecuteAllCommands() const;
@@ -84,7 +83,6 @@
void ExecuteCommand(const Command& command) const;
bool CheckPropertyTriggers(const std::string& name = "",
const std::string& value = "") const;
- Result<Success> ParsePropertyTrigger(const std::string& trigger);
std::map<std::string, std::string> property_triggers_;
std::string event_trigger_;
@@ -96,48 +94,6 @@
static const KeywordFunctionMap* function_map_;
};
-class ActionManager {
- public:
- static ActionManager& GetInstance();
-
- // Exposed for testing
- ActionManager();
-
- void AddAction(std::unique_ptr<Action> action);
- void QueueEventTrigger(const std::string& trigger);
- void QueuePropertyChange(const std::string& name, const std::string& value);
- void QueueAllPropertyActions();
- void QueueBuiltinAction(BuiltinFunction func, const std::string& name);
- void ExecuteOneCommand();
- bool HasMoreCommands() const;
- void DumpState() const;
- void ClearQueue();
-
- private:
- ActionManager(ActionManager const&) = delete;
- void operator=(ActionManager const&) = delete;
-
- std::vector<std::unique_ptr<Action>> actions_;
- std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;
- std::queue<const Action*> current_executing_actions_;
- std::size_t current_command_;
-};
-
-class ActionParser : public SectionParser {
- public:
- ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
- : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
- Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
- int line) override;
- Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
- Result<Success> EndSection() override;
-
- private:
- ActionManager* action_manager_;
- std::vector<Subcontext>* subcontexts_;
- std::unique_ptr<Action> action_;
-};
-
} // namespace init
} // namespace android
diff --git a/init/action_manager.cpp b/init/action_manager.cpp
new file mode 100644
index 0000000..22977bb
--- /dev/null
+++ b/init/action_manager.cpp
@@ -0,0 +1,116 @@
+/*
+ * 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 "action_manager.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace init {
+
+ActionManager::ActionManager() : current_command_(0) {}
+
+ActionManager& ActionManager::GetInstance() {
+ static ActionManager instance;
+ return instance;
+}
+
+void ActionManager::AddAction(std::unique_ptr<Action> action) {
+ actions_.emplace_back(std::move(action));
+}
+
+void ActionManager::QueueEventTrigger(const std::string& trigger) {
+ event_queue_.emplace(trigger);
+}
+
+void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
+ event_queue_.emplace(std::make_pair(name, value));
+}
+
+void ActionManager::QueueAllPropertyActions() {
+ QueuePropertyChange("", "");
+}
+
+void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
+ auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
+ std::map<std::string, std::string>{});
+ std::vector<std::string> name_vector{name};
+
+ action->AddCommand(func, name_vector, 0);
+
+ event_queue_.emplace(action.get());
+ actions_.emplace_back(std::move(action));
+}
+
+void ActionManager::ExecuteOneCommand() {
+ // Loop through the event queue until we have an action to execute
+ while (current_executing_actions_.empty() && !event_queue_.empty()) {
+ for (const auto& action : actions_) {
+ if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
+ event_queue_.front())) {
+ current_executing_actions_.emplace(action.get());
+ }
+ }
+ event_queue_.pop();
+ }
+
+ if (current_executing_actions_.empty()) {
+ return;
+ }
+
+ auto action = current_executing_actions_.front();
+
+ if (current_command_ == 0) {
+ std::string trigger_name = action->BuildTriggersString();
+ LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
+ << ":" << action->line() << ")";
+ }
+
+ action->ExecuteOneCommand(current_command_);
+
+ // If this was the last command in the current action, then remove
+ // the action from the executing list.
+ // If this action was oneshot, then also remove it from actions_.
+ ++current_command_;
+ if (current_command_ == action->NumCommands()) {
+ current_executing_actions_.pop();
+ current_command_ = 0;
+ if (action->oneshot()) {
+ auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
+ actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
+ }
+ }
+}
+
+bool ActionManager::HasMoreCommands() const {
+ return !current_executing_actions_.empty() || !event_queue_.empty();
+}
+
+void ActionManager::DumpState() const {
+ for (const auto& a : actions_) {
+ a->DumpState();
+ }
+}
+
+void ActionManager::ClearQueue() {
+ // We are shutting down so don't claim the oneshot builtin actions back
+ current_executing_actions_ = {};
+ event_queue_ = {};
+ current_command_ = 0;
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/action_manager.h b/init/action_manager.h
new file mode 100644
index 0000000..5f47a6d
--- /dev/null
+++ b/init/action_manager.h
@@ -0,0 +1,59 @@
+/*
+ * 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 _INIT_ACTION_MANAGER_H
+#define _INIT_ACTION_MANAGER_H
+
+#include <string>
+#include <vector>
+
+#include "action.h"
+#include "builtins.h"
+
+namespace android {
+namespace init {
+
+class ActionManager {
+ public:
+ static ActionManager& GetInstance();
+
+ // Exposed for testing
+ ActionManager();
+
+ void AddAction(std::unique_ptr<Action> action);
+ void QueueEventTrigger(const std::string& trigger);
+ void QueuePropertyChange(const std::string& name, const std::string& value);
+ void QueueAllPropertyActions();
+ void QueueBuiltinAction(BuiltinFunction func, const std::string& name);
+ void ExecuteOneCommand();
+ bool HasMoreCommands() const;
+ void DumpState() const;
+ void ClearQueue();
+
+ private:
+ ActionManager(ActionManager const&) = delete;
+ void operator=(ActionManager const&) = delete;
+
+ std::vector<std::unique_ptr<Action>> actions_;
+ std::queue<std::variant<EventTrigger, PropertyChange, BuiltinAction>> event_queue_;
+ std::queue<const Action*> current_executing_actions_;
+ std::size_t current_command_;
+};
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/action_parser.cpp b/init/action_parser.cpp
new file mode 100644
index 0000000..8a4b518
--- /dev/null
+++ b/init/action_parser.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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 "action_parser.h"
+
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+
+#include "stable_properties.h"
+
+using android::base::GetBoolProperty;
+using android::base::StartsWith;
+
+namespace android {
+namespace init {
+
+namespace {
+
+bool IsActionableProperty(Subcontext* subcontext, const std::string& prop_name) {
+ static bool enabled = GetBoolProperty("ro.actionable_compatible_property.enabled", false);
+
+ if (subcontext == nullptr || !enabled) {
+ return true;
+ }
+
+ if (kExportedActionableProperties.count(prop_name) == 1) {
+ return true;
+ }
+ for (const auto& prefix : kPartnerPrefixes) {
+ if (android::base::StartsWith(prop_name, prefix)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+Result<Success> ParsePropertyTrigger(const std::string& trigger, Subcontext* subcontext,
+ std::map<std::string, std::string>* property_triggers) {
+ const static std::string prop_str("property:");
+ std::string prop_name(trigger.substr(prop_str.length()));
+ size_t equal_pos = prop_name.find('=');
+ if (equal_pos == std::string::npos) {
+ return Error() << "property trigger found without matching '='";
+ }
+
+ std::string prop_value(prop_name.substr(equal_pos + 1));
+ prop_name.erase(equal_pos);
+
+ if (!IsActionableProperty(subcontext, prop_name)) {
+ return Error() << "unexported property tigger found: " << prop_name;
+ }
+
+ if (auto [it, inserted] = property_triggers->emplace(prop_name, prop_value); !inserted) {
+ return Error() << "multiple property triggers found for same property";
+ }
+ return Success();
+}
+
+Result<Success> ParseTriggers(const std::vector<std::string>& args, Subcontext* subcontext,
+ std::string* event_trigger,
+ std::map<std::string, std::string>* property_triggers) {
+ const static std::string prop_str("property:");
+ for (std::size_t i = 0; i < args.size(); ++i) {
+ if (args[i].empty()) {
+ return Error() << "empty trigger is not valid";
+ }
+
+ if (i % 2) {
+ if (args[i] != "&&") {
+ return Error() << "&& is the only symbol allowed to concatenate actions";
+ } else {
+ continue;
+ }
+ }
+
+ if (!args[i].compare(0, prop_str.length(), prop_str)) {
+ if (auto result = ParsePropertyTrigger(args[i], subcontext, property_triggers);
+ !result) {
+ return result;
+ }
+ } else {
+ if (!event_trigger->empty()) {
+ return Error() << "multiple event triggers are not allowed";
+ }
+
+ *event_trigger = args[i];
+ }
+ }
+
+ return Success();
+}
+
+} // namespace
+
+Result<Success> ActionParser::ParseSection(std::vector<std::string>&& args,
+ const std::string& filename, int line) {
+ std::vector<std::string> triggers(args.begin() + 1, args.end());
+ if (triggers.size() < 1) {
+ return Error() << "Actions must have a trigger";
+ }
+
+ Subcontext* action_subcontext = nullptr;
+ if (subcontexts_) {
+ for (auto& subcontext : *subcontexts_) {
+ if (StartsWith(filename, subcontext.path_prefix())) {
+ action_subcontext = &subcontext;
+ break;
+ }
+ }
+ }
+
+ std::string event_trigger;
+ std::map<std::string, std::string> property_triggers;
+
+ if (auto result = ParseTriggers(triggers, action_subcontext, &event_trigger, &property_triggers);
+ !result) {
+ return Error() << "ParseTriggers() failed: " << result.error();
+ }
+
+ auto action = std::make_unique<Action>(false, action_subcontext, filename, line, event_trigger,
+ property_triggers);
+
+ action_ = std::move(action);
+ return Success();
+}
+
+Result<Success> ActionParser::ParseLineSection(std::vector<std::string>&& args, int line) {
+ return action_ ? action_->AddCommand(std::move(args), line) : Success();
+}
+
+Result<Success> ActionParser::EndSection() {
+ if (action_ && action_->NumCommands() > 0) {
+ action_manager_->AddAction(std::move(action_));
+ }
+
+ return Success();
+}
+
+} // namespace init
+} // namespace android
diff --git a/init/action_parser.h b/init/action_parser.h
new file mode 100644
index 0000000..b7f7074
--- /dev/null
+++ b/init/action_parser.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _INIT_ACTION_PARSER_H
+#define _INIT_ACTION_PARSER_H
+
+#include <string>
+#include <vector>
+
+#include "action.h"
+#include "action_manager.h"
+#include "parser.h"
+#include "subcontext.h"
+
+namespace android {
+namespace init {
+
+class ActionParser : public SectionParser {
+ public:
+ ActionParser(ActionManager* action_manager, std::vector<Subcontext>* subcontexts)
+ : action_manager_(action_manager), subcontexts_(subcontexts), action_(nullptr) {}
+ Result<Success> ParseSection(std::vector<std::string>&& args, const std::string& filename,
+ int line) override;
+ Result<Success> ParseLineSection(std::vector<std::string>&& args, int line) override;
+ Result<Success> EndSection() override;
+
+ private:
+ ActionManager* action_manager_;
+ std::vector<Subcontext>* subcontexts_;
+ std::unique_ptr<Action> action_;
+};
+
+} // namespace init
+} // namespace android
+
+#endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 0d77622..1040b47 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -58,7 +58,7 @@
#include <selinux/selinux.h>
#include <system/thread_defs.h>
-#include "action.h"
+#include "action_manager.h"
#include "bootchart.h"
#include "init.h"
#include "parser.h"
@@ -511,8 +511,9 @@
property_set("ro.crypto.state", "encrypted");
property_set("ro.crypto.type", "file");
- // defaultcrypto detects file/block encryption. init flow is same for each.
- ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
+ // Although encrypted, vold has already set the device up, so we do not need to
+ // do anything different from the nonencrypted case.
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
if (e4crypt_install_keyring()) {
@@ -520,8 +521,9 @@
}
property_set("ro.crypto.type", "file");
- // encrypt detects file/block encryption. init flow is same for each.
- ActionManager::GetInstance().QueueEventTrigger("encrypt");
+ // Although encrypted, vold has already set the device up, so we do not need to
+ // do anything different from the nonencrypted case.
+ ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
return Success();
} else if (code > 0) {
Error() << "fs_mgr_mount_all() returned unexpected error " << code;
@@ -1043,6 +1045,10 @@
{"load_system_props", {0, 0, {false, do_load_system_props}}},
{"loglevel", {1, 1, {false, do_loglevel}}},
{"mkdir", {1, 4, {true, do_mkdir}}},
+ // TODO: Do mount operations in vendor_init.
+ // mount_all is currently too complex to run in vendor_init as it queues action triggers,
+ // imports rc scripts, etc. It should be simplified and run in vendor_init context.
+ // mount and umount are run in the same context as mount_all for symmetry.
{"mount_all", {1, kMax, {false, do_mount_all}}},
{"mount", {3, kMax, {false, do_mount}}},
{"umount", {1, 1, {false, do_umount}}},
diff --git a/init/init.cpp b/init/init.cpp
index 79623c3..7e4eaa8 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -19,6 +19,7 @@
#include <dirent.h>
#include <fcntl.h>
#include <paths.h>
+#include <pthread.h>
#include <seccomp_policy.h>
#include <signal.h>
#include <stdlib.h>
@@ -44,6 +45,7 @@
#include <memory>
#include <optional>
+#include "action_parser.h"
#include "import_parser.h"
#include "init_first_stage.h"
#include "keychords.h"
@@ -491,6 +493,16 @@
HandlePowerctlMessage("shutdown,container");
}
+static void UnblockSigterm() {
+ sigset_t mask;
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGTERM);
+
+ if (sigprocmask(SIG_UNBLOCK, &mask, nullptr) == -1) {
+ PLOG(FATAL) << "failed to unblock SIGTERM for PID " << getpid();
+ }
+}
+
static void InstallSigtermHandler() {
sigset_t mask;
sigemptyset(&mask);
@@ -500,6 +512,12 @@
PLOG(FATAL) << "failed to block SIGTERM";
}
+ // Register a handler to unblock SIGTERM in the child processes.
+ const int result = pthread_atfork(nullptr, nullptr, &UnblockSigterm);
+ if (result != 0) {
+ LOG(FATAL) << "Failed to register a fork handler: " << strerror(result);
+ }
+
sigterm_signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
if (sigterm_signal_fd == -1) {
PLOG(FATAL) << "failed to create signalfd for SIGTERM";
diff --git a/init/init.h b/init/init.h
index ff7bdeb..ecce5d7 100644
--- a/init/init.h
+++ b/init/init.h
@@ -21,6 +21,7 @@
#include <vector>
#include "action.h"
+#include "action_manager.h"
#include "parser.h"
#include "service.h"
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 6fa07e7..0f4cc68 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -56,6 +56,7 @@
bool InitDevices();
protected:
+ ListenerAction HandleBlockDevice(const std::string& name, const Uevent&);
bool InitRequiredDevices();
bool InitVerityDevice(const std::string& verity_device);
bool MountPartitions();
@@ -209,6 +210,24 @@
return true;
}
+ListenerAction FirstStageMount::HandleBlockDevice(const std::string& name, const Uevent& uevent) {
+ // Matches partition name to create device nodes.
+ // Both required_devices_partition_names_ and uevent->partition_name have A/B
+ // suffix when A/B is used.
+ auto iter = required_devices_partition_names_.find(name);
+ if (iter != required_devices_partition_names_.end()) {
+ LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
+ required_devices_partition_names_.erase(iter);
+ device_handler_.HandleDeviceEvent(uevent);
+ if (required_devices_partition_names_.empty()) {
+ return ListenerAction::kStop;
+ } else {
+ return ListenerAction::kContinue;
+ }
+ }
+ return ListenerAction::kContinue;
+}
+
ListenerAction FirstStageMount::UeventCallback(const Uevent& uevent) {
// Ignores everything that is not a block device.
if (uevent.subsystem != "block") {
@@ -216,19 +235,11 @@
}
if (!uevent.partition_name.empty()) {
- // Matches partition name to create device nodes.
- // Both required_devices_partition_names_ and uevent->partition_name have A/B
- // suffix when A/B is used.
- auto iter = required_devices_partition_names_.find(uevent.partition_name);
- if (iter != required_devices_partition_names_.end()) {
- LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << *iter;
- required_devices_partition_names_.erase(iter);
- device_handler_.HandleDeviceEvent(uevent);
- if (required_devices_partition_names_.empty()) {
- return ListenerAction::kStop;
- } else {
- return ListenerAction::kContinue;
- }
+ return HandleBlockDevice(uevent.partition_name, uevent);
+ } else {
+ size_t base_idx = uevent.path.rfind('/');
+ if (base_idx != std::string::npos) {
+ return HandleBlockDevice(uevent.path.substr(base_idx + 1), uevent);
}
}
// Not found a partition or find an unneeded partition, continue to find others.
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 268873c..0f9635f 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -21,6 +21,8 @@
#include <gtest/gtest.h>
#include "action.h"
+#include "action_manager.h"
+#include "action_parser.h"
#include "builtins.h"
#include "import_parser.h"
#include "keyword_map.h"
diff --git a/init/reboot.cpp b/init/reboot.cpp
index a88a42d..242750a 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -50,6 +50,7 @@
#include <private/android_filesystem_config.h>
#include <selinux/selinux.h>
+#include "action_manager.h"
#include "capabilities.h"
#include "init.h"
#include "property_service.h"
diff --git a/init/service.cpp b/init/service.cpp
index bf780aa..35dd319 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -189,7 +189,8 @@
capabilities_(capabilities),
namespace_flags_(namespace_flags),
seclabel_(seclabel),
- onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0),
+ onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
+ "onrestart", {}),
keychord_id_(0),
ioprio_class_(IoSchedClass_NONE),
ioprio_pri_(0),
@@ -199,9 +200,7 @@
soft_limit_in_bytes_(-1),
limit_in_bytes_(-1),
start_order_(0),
- args_(args) {
- onrestart_.InitSingleTrigger("onrestart");
-}
+ args_(args) {}
void Service::NotifyStateChange(const std::string& new_state) const {
if ((flags_ & SVC_TEMPORARY) != 0) {
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 1622e30..6dcc621 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -46,7 +46,7 @@
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_));
+ dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_));
#endif
if (!stack_maps_->Parse()) {
diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h
index fcbdc9b..b2779b2 100644
--- a/libcutils/include/cutils/trace.h
+++ b/libcutils/include/cutils/trace.h
@@ -72,7 +72,8 @@
#define ATRACE_TAG_DATABASE (1<<20)
#define ATRACE_TAG_NETWORK (1<<21)
#define ATRACE_TAG_ADB (1<<22)
-#define ATRACE_TAG_LAST ATRACE_TAG_ADB
+#define ATRACE_TAG_VIBRATOR (1<<23)
+#define ATRACE_TAG_LAST ATRACE_TAG_VIBRATOR
// Reserved for initialization.
#define ATRACE_TAG_NOT_READY (1ULL<<63)
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index fc354f1..5d17698 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -55,6 +55,9 @@
*/
#define AID_ROOT 0 /* traditional unix root user */
+/* The following are for LTP and should only be used for testing */
+#define AID_DAEMON 1 /* traditional unix daemon owner */
+#define AID_BIN 2 /* traditional unix binaries owner */
#define AID_SYSTEM 1000 /* system server */
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 27255c2..4da8215 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -25,7 +25,6 @@
void atrace_set_tracing_enabled(bool enabled)
{
atomic_store_explicit(&atrace_is_enabled, enabled, memory_order_release);
- atomic_store_explicit(&atrace_is_ready, false, memory_order_release);
atrace_update_tags();
}
@@ -35,17 +34,18 @@
if (atrace_marker_fd == -1) {
ALOGE("Error opening trace file: %s (%d)", strerror(errno), errno);
atrace_enabled_tags = 0;
- return;
+ goto done;
}
+
atrace_enabled_tags = atrace_get_property();
+
+done:
+ atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
}
void atrace_setup()
{
- if (atomic_load_explicit(&atrace_is_enabled, memory_order_acquire)) {
- pthread_once(&atrace_once_control, atrace_init_once);
- }
- atomic_store_explicit(&atrace_is_ready, true, memory_order_release);
+ pthread_once(&atrace_once_control, atrace_init_once);
}
void atrace_begin_body(const char* name)
diff --git a/libcutils/trace-dev.inc b/libcutils/trace-dev.inc
index f32330a..f95c6c5 100644
--- a/libcutils/trace-dev.inc
+++ b/libcutils/trace-dev.inc
@@ -70,7 +70,7 @@
for (int i = 0; i < count; i++) {
snprintf(buf, sizeof(buf), "debug.atrace.app_%d", i);
property_get(buf, value, "");
- if (strcmp(value, cmdline) == 0) {
+ if (strcmp(value, "*") == 0 || strcmp(value, cmdline) == 0) {
return true;
}
}
diff --git a/libion/ion_test.c b/libion/ion_test.c
index b7d5583..f3874ae 100644
--- a/libion/ion_test.c
+++ b/libion/ion_test.c
@@ -250,7 +250,7 @@
case 'p':
prot = 0;
prot |= strstr(optarg, "MAP_PRIVATE") ? MAP_PRIVATE : 0;
- prot |= strstr(optarg, "MAP_SHARED") ? MAP_PRIVATE : 0;
+ prot |= strstr(optarg, "MAP_SHARED") ? MAP_SHARED : 0;
break;
case 'f':
alloc_flags = atol(optarg);
diff --git a/liblog/include_vndk/log/log_event_list.h b/liblog/include_vndk/log/log_event_list.h
new file mode 100644
index 0000000..cbd3091
--- /dev/null
+++ b/liblog/include_vndk/log/log_event_list.h
@@ -0,0 +1,73 @@
+/*
+ * 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
+
+#define __ANDROID_USE_LIBLOG_EVENT_INTERFACE 1
+
+/*
+ * 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);
+
+/* 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/liblog.map.txt b/liblog/liblog.map.txt
index 3c4c1f1..9d21e56 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -35,6 +35,17 @@
android_logger_get_statistics; # vndk
__android_log_error_write; # vndk
__android_log_is_loggable;
+ create_android_logger; #vndk
+ android_log_destroy; #vndk
+ android_log_write_list_begin; #vndk
+ android_log_write_list_end; #vndk
+ android_log_write_int32; #vndk
+ android_log_write_int64; #vndk
+ android_log_write_string8; #vndk
+ android_log_write_string8_len; #vndk
+ android_log_write_float32; #vndk
+ android_log_write_list; #vndk
+
};
LIBLOG_O {
diff --git a/libmemunreachable/PtracerThread.cpp b/libmemunreachable/PtracerThread.cpp
index aca2a82..61a1d24 100644
--- a/libmemunreachable/PtracerThread.cpp
+++ b/libmemunreachable/PtracerThread.cpp
@@ -98,6 +98,7 @@
return (*reinterpret_cast<std::function<int()>*>(arg))();
};
+ // See README.md for why we create the child process this way
child_pid_ = clone(proxy, stack_->top(), CLONE_VM | CLONE_FS | CLONE_FILES /*|CLONE_UNTRACED*/,
reinterpret_cast<void*>(&func_));
if (child_pid_ < 0) {
diff --git a/libmemunreachable/README.md b/libmemunreachable/README.md
index 61a47de..ae8fa94 100644
--- a/libmemunreachable/README.md
+++ b/libmemunreachable/README.md
@@ -36,7 +36,7 @@
1. *Original process*: Leak detection is requested by calling `GetUnreachableMemory()`
2. Allocations are disabled using `malloc_disable()`
- 3. The collection process is spawned. The collection process is similar to a normal `fork()` child process, except that it shares the address space of the parent - any writes by the original process are visible to the collection process, and vice-versa.
+ 3. The collection process is spawned. The collection process, created using clone, is similar to a normal `fork()` child process, except that it shares the address space of the parent - any writes by the original process are visible to the collection process, and vice-versa. If we forked instead of using clone, the address space might get out of sync with observed post-ptrace thread state, since it takes some time to pause the parent.
4. *Collection process*: All threads in the original process are paused with `ptrace()`.
5. Registers contents, active stack areas, and memory mapping information are collected.
6. *Original process*: Allocations are re-enabled using `malloc_enable()`, but all threads are still paused with `ptrace()`.
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 74dfaa5..a7bdd2e 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -128,6 +128,12 @@
"DexFile.cpp",
"DexFiles.cpp",
],
+ target: {
+ // Always disable optimizations for host to make it easier to debug.
+ host: {
+ cflags: ["-O0", "-g"],
+ },
+ },
shared_libs: [
"libbase",
@@ -151,8 +157,13 @@
vendor_available: false,
defaults: ["libunwindstack_flags"],
+ shared: {
+ enabled: false,
+ },
+
srcs: [
"tests/DexFileTest.cpp",
+ "tests/DexFilesTest.cpp",
],
local_include_dirs: ["include"],
allow_undefined_symbols: true,
@@ -160,6 +171,7 @@
shared_libs: [
"libbase",
"libunwindstack",
+ "libdexfile",
],
// libdexfile will eventually properly export headers, for now include
@@ -237,10 +249,11 @@
"tests/files/elf64.xz",
"tests/files/offline/bad_eh_frame_hdr_arm64/*",
"tests/files/offline/debug_frame_first_x86/*",
- "tests/files/offline/jit_debug_arm32/*",
- "tests/files/offline/jit_debug_x86_32/*",
- "tests/files/offline/gnu_debugdata_arm32/*",
- "tests/files/offline/straddle_arm32/*",
+ "tests/files/offline/eh_frame_hdr_begin_x86_64/*",
+ "tests/files/offline/jit_debug_arm/*",
+ "tests/files/offline/jit_debug_x86/*",
+ "tests/files/offline/gnu_debugdata_arm/*",
+ "tests/files/offline/straddle_arm/*",
"tests/files/offline/straddle_arm64/*",
],
}
@@ -295,6 +308,15 @@
],
}
+cc_binary {
+ name: "unwind_reg_info",
+ defaults: ["libunwindstack_tools"],
+
+ srcs: [
+ "tools/unwind_reg_info.cpp",
+ ],
+}
+
// 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 {
diff --git a/libunwindstack/ArmExidx.cpp b/libunwindstack/ArmExidx.cpp
index 65638ae..6e397e3 100644
--- a/libunwindstack/ArmExidx.cpp
+++ b/libunwindstack/ArmExidx.cpp
@@ -22,12 +22,12 @@
#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"
-#include "MachineArm.h"
namespace unwindstack {
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index be6c2f7..b18b0ce 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -24,7 +24,7 @@
#include <android-base/unique_fd.h>
-#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/code_item_accessors-inl.h>
#include <dex/compact_dex_file.h>
#include <dex/dex_file-inl.h>
#include <dex/dex_file_loader.h>
@@ -52,10 +52,20 @@
return nullptr;
}
-void DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+DexFileFromFile::~DexFileFromFile() {
+ if (size_ != 0) {
+ munmap(mapped_memory_, size_);
+ }
+}
+
+bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
uint64_t* method_offset) {
if (dex_file_ == nullptr) {
- return;
+ return false;
+ }
+
+ if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) {
+ return false; // The DEX offset is not within the bytecode of this dex file.
}
for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
@@ -82,16 +92,11 @@
if (offset <= dex_offset && dex_offset < offset + size) {
*method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false);
*method_offset = dex_offset - offset;
- return;
+ return true;
}
}
}
-}
-
-DexFileFromFile::~DexFileFromFile() {
- if (size_ != 0) {
- munmap(mapped_memory_, size_);
- }
+ return false;
}
bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) {
@@ -139,25 +144,40 @@
}
bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) {
- art::DexFile::Header header;
- if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) {
+ memory_.resize(sizeof(art::DexFile::Header));
+ if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
return false;
}
- if (!art::StandardDexFile::IsMagicValid(header.magic_) &&
- !art::CompactDexFile::IsMagicValid(header.magic_)) {
+ art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+ uint32_t file_size = header->file_size_;
+ if (art::CompactDexFile::IsMagicValid(header->magic_)) {
+ // Compact dex file store data section separately so that it can be shared.
+ // Therefore we need to extend the read memory range to include it.
+ // TODO: This might be wasteful as we might read data in between as well.
+ // In practice, this should be fine, as such sharing only happens on disk.
+ uint32_t computed_file_size;
+ if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
+ return false;
+ }
+ if (computed_file_size > file_size) {
+ file_size = computed_file_size;
+ }
+ } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
return false;
}
- memory_.resize(header.file_size_);
- if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) {
+ memory_.resize(file_size);
+ if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) {
return false;
}
+ header = reinterpret_cast<art::DexFile::Header*>(memory_.data());
+
art::DexFileLoader loader;
std::string error_msg;
auto dex =
- loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg);
+ loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg);
dex_file_.reset(dex.release());
return dex_file_ != nullptr;
}
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 22e98df..3ce2f1e 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -32,7 +32,7 @@
DexFile() = default;
virtual ~DexFile() = default;
- void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
+ bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info);
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
index fe6d3c6..c5f8138 100644
--- a/libunwindstack/DexFiles.cpp
+++ b/libunwindstack/DexFiles.cpp
@@ -24,23 +24,138 @@
#include <unwindstack/DexFiles.h>
#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include "DexFile.h"
namespace unwindstack {
+struct DEXFileEntry32 {
+ uint32_t next;
+ uint32_t prev;
+ uint32_t dex_file;
+};
+
+struct DEXFileEntry64 {
+ uint64_t next;
+ uint64_t prev;
+ uint64_t dex_file;
+};
+
DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {}
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+ : memory_(memory), search_libs_(search_libs) {}
+
DexFiles::~DexFiles() {
for (auto& entry : files_) {
delete entry.second;
}
}
+void DexFiles::SetArch(ArchEnum arch) {
+ 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;
+ if (!memory_->ReadFully(addr, &entry, sizeof(entry))) {
+ return 0;
+ }
+ return entry;
+}
+
+uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
+ uint64_t entry;
+ if (!memory_->ReadFully(addr, &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;
+}
+
+void DexFiles::Init(Maps* maps) {
+ if (initialized_) {
+ return;
+ }
+ initialized_ = true;
+ entry_addr_ = 0;
+
+ const std::string dex_debug_name("__art_debug_dexfiles");
+ for (MapInfo* info : *maps) {
+ if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
+ continue;
+ }
+
+ if (!search_libs_.empty()) {
+ bool found = false;
+ const char* lib = basename(info->name.c_str());
+ for (const std::string& name : search_libs_) {
+ if (name == lib) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ continue;
+ }
+ }
+
+ Elf* elf = info->GetElf(memory_, true);
+ uint64_t ptr;
+ // Find first non-empty list (libart might be loaded multiple times).
+ if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) {
+ entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start);
+ if (entry_addr_ != 0) {
+ break;
+ }
+ }
+ }
+}
+
DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
// Lock while processing the data.
- std::lock_guard<std::mutex> guard(files_lock_);
DexFile* dex_file;
auto entry = files_.find(dex_file_offset);
if (entry == files_.end()) {
@@ -52,14 +167,38 @@
return dex_file;
}
-void DexFiles::GetMethodInformation(uint64_t dex_file_offset, uint64_t dex_offset, MapInfo* info,
- std::string* method_name, uint64_t* method_offset) {
- DexFile* dex_file = GetDexFile(dex_file_offset, info);
- if (dex_file != nullptr) {
- dex_file->GetMethodInformation(dex_offset, method_name, method_offset);
+bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
+ if (index < addrs_.size()) {
+ *addr = addrs_[index];
+ return true;
}
+ if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
+ *addr = addrs_.back();
+ return true;
+ }
+ return false;
}
-void DexFiles::SetArch(ArchEnum) {}
+void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
+ std::string* method_name, uint64_t* method_offset) {
+ std::lock_guard<std::mutex> guard(lock_);
+ if (!initialized_) {
+ Init(maps);
+ }
+
+ size_t index = 0;
+ uint64_t addr;
+ while (GetAddr(index++, &addr)) {
+ if (addr < info->start || addr >= info->end) {
+ continue;
+ }
+
+ DexFile* dex_file = GetDexFile(addr, info);
+ if (dex_file != nullptr &&
+ dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
+ break;
+ }
+ }
+}
} // namespace unwindstack
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 2589c89..7a41e45 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -46,4 +46,4 @@
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_WITH_HDR_H
+#endif // _LIBUNWINDSTACK_DWARF_EH_FRAME_H
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index a131abe..9a49013 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -109,7 +109,7 @@
fde_info_.erase(index);
return nullptr;
}
- info->pc = value + 4;
+ info->pc = value;
return info;
}
diff --git a/libunwindstack/DwarfOp.cpp b/libunwindstack/DwarfOp.cpp
index dcf04e6..5bc60b9 100644
--- a/libunwindstack/DwarfOp.cpp
+++ b/libunwindstack/DwarfOp.cpp
@@ -36,13 +36,45 @@
constexpr typename DwarfOp<AddressType>::OpCallback DwarfOp<AddressType>::kCallbackTable[256];
template <typename AddressType>
-bool DwarfOp<AddressType>::Eval(uint64_t start, uint64_t end, uint8_t dwarf_version) {
- uint32_t iterations = 0;
+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(dwarf_version)) {
+ if (!Decode()) {
return false;
}
// To protect against a branch that creates an infinite loop,
@@ -56,7 +88,7 @@
}
template <typename AddressType>
-bool DwarfOp<AddressType>::Decode(uint8_t dwarf_version) {
+bool DwarfOp<AddressType>::Decode() {
last_error_.code = DWARF_ERROR_NONE;
if (!memory_->ReadBytes(&cur_op_, 1)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
@@ -71,12 +103,6 @@
return false;
}
- // Check for an unsupported opcode.
- if (dwarf_version < op->supported_version) {
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
// 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;
@@ -434,22 +460,22 @@
template <typename AddressType>
bool DwarfOp<AddressType>::op_breg() {
uint16_t reg = cur_op() - 0x70;
- if (reg >= regs_->total_regs()) {
+ if (reg >= regs_info_->Total()) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
- stack_.push_front((*regs_)[reg] + OperandAt(0));
+ 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_->total_regs()) {
+ if (reg >= regs_info_->Total()) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
- stack_.push_front((*regs_)[reg] + OperandAt(1));
+ stack_.push_front(regs_info_->Get(reg) + OperandAt(1));
return true;
}
diff --git a/libunwindstack/DwarfOp.h b/libunwindstack/DwarfOp.h
index 40b7b23..4c69b3d 100644
--- a/libunwindstack/DwarfOp.h
+++ b/libunwindstack/DwarfOp.h
@@ -27,16 +27,10 @@
#include <unwindstack/DwarfError.h>
#include "DwarfEncoding.h"
+#include "RegsInfo.h"
namespace unwindstack {
-enum DwarfVersion : uint8_t {
- DWARF_VERSION_2 = 2,
- DWARF_VERSION_3 = 3,
- DWARF_VERSION_4 = 4,
- DWARF_VERSION_MAX = DWARF_VERSION_4,
-};
-
// Forward declarations.
class DwarfMemory;
class Memory;
@@ -51,7 +45,6 @@
struct OpCallback {
const char* name;
bool (DwarfOp::*handle_func)();
- uint8_t supported_version;
uint8_t num_required_stack_values;
uint8_t num_operands;
uint8_t operands[2];
@@ -62,21 +55,23 @@
: memory_(memory), regular_memory_(regular_memory) {}
virtual ~DwarfOp() = default;
- bool Decode(uint8_t dwarf_version);
+ bool Decode();
- bool Eval(uint64_t start, uint64_t end, uint8_t dwarf_version);
+ 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(RegsImpl<AddressType>* regs) { regs_ = regs; }
+ 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_; }
@@ -97,7 +92,8 @@
DwarfMemory* memory_;
Memory* regular_memory_;
- RegsImpl<AddressType>* regs_;
+ RegsInfo<AddressType>* regs_info_;
+ bool dex_pc_set_ = false;
bool is_register_ = false;
DwarfErrorData last_error_{DWARF_ERROR_NONE, 0};
uint8_t cur_op_;
@@ -148,35 +144,32 @@
bool op_not_implemented();
constexpr static OpCallback kCallbackTable[256] = {
- {nullptr, nullptr, 0, 0, 0, {}}, // 0x00 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0x01 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0x02 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0x00 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0x01 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0x02 illegal op
{
// 0x03 DW_OP_addr
"DW_OP_addr",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_absptr},
},
- {nullptr, nullptr, 0, 0, 0, {}}, // 0x04 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0x05 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0x04 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0x05 illegal op
{
// 0x06 DW_OP_deref
"DW_OP_deref",
&DwarfOp::op_deref,
- DWARF_VERSION_2,
1,
0,
{},
},
- {nullptr, nullptr, 0, 0, 0, {}}, // 0x07 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0x07 illegal op
{
// 0x08 DW_OP_const1u
"DW_OP_const1u",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_udata1},
@@ -185,7 +178,6 @@
// 0x09 DW_OP_const1s
"DW_OP_const1s",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sdata1},
@@ -194,7 +186,6 @@
// 0x0a DW_OP_const2u
"DW_OP_const2u",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_udata2},
@@ -203,7 +194,6 @@
// 0x0b DW_OP_const2s
"DW_OP_const2s",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sdata2},
@@ -212,7 +202,6 @@
// 0x0c DW_OP_const4u
"DW_OP_const4u",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_udata4},
@@ -221,7 +210,6 @@
// 0x0d DW_OP_const4s
"DW_OP_const4s",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sdata4},
@@ -230,7 +218,6 @@
// 0x0e DW_OP_const8u
"DW_OP_const8u",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_udata8},
@@ -239,7 +226,6 @@
// 0x0f DW_OP_const8s
"DW_OP_const8s",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sdata8},
@@ -248,7 +234,6 @@
// 0x10 DW_OP_constu
"DW_OP_constu",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_uleb128},
@@ -257,7 +242,6 @@
// 0x11 DW_OP_consts
"DW_OP_consts",
&DwarfOp::op_push,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -266,7 +250,6 @@
// 0x12 DW_OP_dup
"DW_OP_dup",
&DwarfOp::op_dup,
- DWARF_VERSION_2,
1,
0,
{},
@@ -275,7 +258,6 @@
// 0x13 DW_OP_drop
"DW_OP_drop",
&DwarfOp::op_drop,
- DWARF_VERSION_2,
1,
0,
{},
@@ -284,7 +266,6 @@
// 0x14 DW_OP_over
"DW_OP_over",
&DwarfOp::op_over,
- DWARF_VERSION_2,
2,
0,
{},
@@ -293,7 +274,6 @@
// 0x15 DW_OP_pick
"DW_OP_pick",
&DwarfOp::op_pick,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_udata1},
@@ -302,7 +282,6 @@
// 0x16 DW_OP_swap
"DW_OP_swap",
&DwarfOp::op_swap,
- DWARF_VERSION_2,
2,
0,
{},
@@ -311,7 +290,6 @@
// 0x17 DW_OP_rot
"DW_OP_rot",
&DwarfOp::op_rot,
- DWARF_VERSION_2,
3,
0,
{},
@@ -320,7 +298,6 @@
// 0x18 DW_OP_xderef
"DW_OP_xderef",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_2,
2,
0,
{},
@@ -329,7 +306,6 @@
// 0x19 DW_OP_abs
"DW_OP_abs",
&DwarfOp::op_abs,
- DWARF_VERSION_2,
1,
0,
{},
@@ -338,7 +314,6 @@
// 0x1a DW_OP_and
"DW_OP_and",
&DwarfOp::op_and,
- DWARF_VERSION_2,
2,
0,
{},
@@ -347,7 +322,6 @@
// 0x1b DW_OP_div
"DW_OP_div",
&DwarfOp::op_div,
- DWARF_VERSION_2,
2,
0,
{},
@@ -356,7 +330,6 @@
// 0x1c DW_OP_minus
"DW_OP_minus",
&DwarfOp::op_minus,
- DWARF_VERSION_2,
2,
0,
{},
@@ -365,7 +338,6 @@
// 0x1d DW_OP_mod
"DW_OP_mod",
&DwarfOp::op_mod,
- DWARF_VERSION_2,
2,
0,
{},
@@ -374,7 +346,6 @@
// 0x1e DW_OP_mul
"DW_OP_mul",
&DwarfOp::op_mul,
- DWARF_VERSION_2,
2,
0,
{},
@@ -383,7 +354,6 @@
// 0x1f DW_OP_neg
"DW_OP_neg",
&DwarfOp::op_neg,
- DWARF_VERSION_2,
1,
0,
{},
@@ -392,7 +362,6 @@
// 0x20 DW_OP_not
"DW_OP_not",
&DwarfOp::op_not,
- DWARF_VERSION_2,
1,
0,
{},
@@ -401,7 +370,6 @@
// 0x21 DW_OP_or
"DW_OP_or",
&DwarfOp::op_or,
- DWARF_VERSION_2,
2,
0,
{},
@@ -410,7 +378,6 @@
// 0x22 DW_OP_plus
"DW_OP_plus",
&DwarfOp::op_plus,
- DWARF_VERSION_2,
2,
0,
{},
@@ -419,7 +386,6 @@
// 0x23 DW_OP_plus_uconst
"DW_OP_plus_uconst",
&DwarfOp::op_plus_uconst,
- DWARF_VERSION_2,
1,
1,
{DW_EH_PE_uleb128},
@@ -428,7 +394,6 @@
// 0x24 DW_OP_shl
"DW_OP_shl",
&DwarfOp::op_shl,
- DWARF_VERSION_2,
2,
0,
{},
@@ -437,7 +402,6 @@
// 0x25 DW_OP_shr
"DW_OP_shr",
&DwarfOp::op_shr,
- DWARF_VERSION_2,
2,
0,
{},
@@ -446,7 +410,6 @@
// 0x26 DW_OP_shra
"DW_OP_shra",
&DwarfOp::op_shra,
- DWARF_VERSION_2,
2,
0,
{},
@@ -455,7 +418,6 @@
// 0x27 DW_OP_xor
"DW_OP_xor",
&DwarfOp::op_xor,
- DWARF_VERSION_2,
2,
0,
{},
@@ -464,7 +426,6 @@
// 0x28 DW_OP_bra
"DW_OP_bra",
&DwarfOp::op_bra,
- DWARF_VERSION_2,
1,
1,
{DW_EH_PE_sdata2},
@@ -473,7 +434,6 @@
// 0x29 DW_OP_eq
"DW_OP_eq",
&DwarfOp::op_eq,
- DWARF_VERSION_2,
2,
0,
{},
@@ -482,7 +442,6 @@
// 0x2a DW_OP_ge
"DW_OP_ge",
&DwarfOp::op_ge,
- DWARF_VERSION_2,
2,
0,
{},
@@ -491,7 +450,6 @@
// 0x2b DW_OP_gt
"DW_OP_gt",
&DwarfOp::op_gt,
- DWARF_VERSION_2,
2,
0,
{},
@@ -500,7 +458,6 @@
// 0x2c DW_OP_le
"DW_OP_le",
&DwarfOp::op_le,
- DWARF_VERSION_2,
2,
0,
{},
@@ -509,7 +466,6 @@
// 0x2d DW_OP_lt
"DW_OP_lt",
&DwarfOp::op_lt,
- DWARF_VERSION_2,
2,
0,
{},
@@ -518,7 +474,6 @@
// 0x2e DW_OP_ne
"DW_OP_ne",
&DwarfOp::op_ne,
- DWARF_VERSION_2,
2,
0,
{},
@@ -527,7 +482,6 @@
// 0x2f DW_OP_skip
"DW_OP_skip",
&DwarfOp::op_skip,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sdata2},
@@ -536,7 +490,6 @@
// 0x30 DW_OP_lit0
"DW_OP_lit0",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -545,7 +498,6 @@
// 0x31 DW_OP_lit1
"DW_OP_lit1",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -554,7 +506,6 @@
// 0x32 DW_OP_lit2
"DW_OP_lit2",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -563,7 +514,6 @@
// 0x33 DW_OP_lit3
"DW_OP_lit3",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -572,7 +522,6 @@
// 0x34 DW_OP_lit4
"DW_OP_lit4",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -581,7 +530,6 @@
// 0x35 DW_OP_lit5
"DW_OP_lit5",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -590,7 +538,6 @@
// 0x36 DW_OP_lit6
"DW_OP_lit6",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -599,7 +546,6 @@
// 0x37 DW_OP_lit7
"DW_OP_lit7",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -608,7 +554,6 @@
// 0x38 DW_OP_lit8
"DW_OP_lit8",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -617,7 +562,6 @@
// 0x39 DW_OP_lit9
"DW_OP_lit9",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -626,7 +570,6 @@
// 0x3a DW_OP_lit10
"DW_OP_lit10",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -635,7 +578,6 @@
// 0x3b DW_OP_lit11
"DW_OP_lit11",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -644,7 +586,6 @@
// 0x3c DW_OP_lit12
"DW_OP_lit12",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -653,7 +594,6 @@
// 0x3d DW_OP_lit13
"DW_OP_lit13",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -662,7 +602,6 @@
// 0x3e DW_OP_lit14
"DW_OP_lit14",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -671,7 +610,6 @@
// 0x3f DW_OP_lit15
"DW_OP_lit15",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -680,7 +618,6 @@
// 0x40 DW_OP_lit16
"DW_OP_lit16",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -689,7 +626,6 @@
// 0x41 DW_OP_lit17
"DW_OP_lit17",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -698,7 +634,6 @@
// 0x42 DW_OP_lit18
"DW_OP_lit18",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -707,7 +642,6 @@
// 0x43 DW_OP_lit19
"DW_OP_lit19",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -716,7 +650,6 @@
// 0x44 DW_OP_lit20
"DW_OP_lit20",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -725,7 +658,6 @@
// 0x45 DW_OP_lit21
"DW_OP_lit21",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -734,7 +666,6 @@
// 0x46 DW_OP_lit22
"DW_OP_lit22",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -743,7 +674,6 @@
// 0x47 DW_OP_lit23
"DW_OP_lit23",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -752,7 +682,6 @@
// 0x48 DW_OP_lit24
"DW_OP_lit24",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -761,7 +690,6 @@
// 0x49 DW_OP_lit25
"DW_OP_lit25",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -770,7 +698,6 @@
// 0x4a DW_OP_lit26
"DW_OP_lit26",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -779,7 +706,6 @@
// 0x4b DW_OP_lit27
"DW_OP_lit27",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -788,7 +714,6 @@
// 0x4c DW_OP_lit28
"DW_OP_lit28",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -797,7 +722,6 @@
// 0x4d DW_OP_lit29
"DW_OP_lit29",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -806,7 +730,6 @@
// 0x4e DW_OP_lit30
"DW_OP_lit30",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -815,7 +738,6 @@
// 0x4f DW_OP_lit31
"DW_OP_lit31",
&DwarfOp::op_lit,
- DWARF_VERSION_2,
0,
0,
{},
@@ -824,7 +746,6 @@
// 0x50 DW_OP_reg0
"DW_OP_reg0",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -833,7 +754,6 @@
// 0x51 DW_OP_reg1
"DW_OP_reg1",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -842,7 +762,6 @@
// 0x52 DW_OP_reg2
"DW_OP_reg2",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -851,7 +770,6 @@
// 0x53 DW_OP_reg3
"DW_OP_reg3",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -860,7 +778,6 @@
// 0x54 DW_OP_reg4
"DW_OP_reg4",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -869,7 +786,6 @@
// 0x55 DW_OP_reg5
"DW_OP_reg5",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -878,7 +794,6 @@
// 0x56 DW_OP_reg6
"DW_OP_reg6",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -887,7 +802,6 @@
// 0x57 DW_OP_reg7
"DW_OP_reg7",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -896,7 +810,6 @@
// 0x58 DW_OP_reg8
"DW_OP_reg8",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -905,7 +818,6 @@
// 0x59 DW_OP_reg9
"DW_OP_reg9",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -914,7 +826,6 @@
// 0x5a DW_OP_reg10
"DW_OP_reg10",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -923,7 +834,6 @@
// 0x5b DW_OP_reg11
"DW_OP_reg11",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -932,7 +842,6 @@
// 0x5c DW_OP_reg12
"DW_OP_reg12",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -941,7 +850,6 @@
// 0x5d DW_OP_reg13
"DW_OP_reg13",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -950,7 +858,6 @@
// 0x5e DW_OP_reg14
"DW_OP_reg14",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -959,7 +866,6 @@
// 0x5f DW_OP_reg15
"DW_OP_reg15",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -968,7 +874,6 @@
// 0x60 DW_OP_reg16
"DW_OP_reg16",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -977,7 +882,6 @@
// 0x61 DW_OP_reg17
"DW_OP_reg17",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -986,7 +890,6 @@
// 0x62 DW_OP_reg18
"DW_OP_reg18",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -995,7 +898,6 @@
// 0x63 DW_OP_reg19
"DW_OP_reg19",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1004,7 +906,6 @@
// 0x64 DW_OP_reg20
"DW_OP_reg20",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1013,7 +914,6 @@
// 0x65 DW_OP_reg21
"DW_OP_reg21",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1022,7 +922,6 @@
// 0x66 DW_OP_reg22
"DW_OP_reg22",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1031,7 +930,6 @@
// 0x67 DW_OP_reg23
"DW_OP_reg23",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1040,7 +938,6 @@
// 0x68 DW_OP_reg24
"DW_OP_reg24",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1049,7 +946,6 @@
// 0x69 DW_OP_reg25
"DW_OP_reg25",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1058,7 +954,6 @@
// 0x6a DW_OP_reg26
"DW_OP_reg26",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1067,7 +962,6 @@
// 0x6b DW_OP_reg27
"DW_OP_reg27",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1076,7 +970,6 @@
// 0x6c DW_OP_reg28
"DW_OP_reg28",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1085,7 +978,6 @@
// 0x6d DW_OP_reg29
"DW_OP_reg29",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1094,7 +986,6 @@
// 0x6e DW_OP_reg30
"DW_OP_reg30",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1103,7 +994,6 @@
// 0x6f DW_OP_reg31
"DW_OP_reg31",
&DwarfOp::op_reg,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1112,7 +1002,6 @@
// 0x70 DW_OP_breg0
"DW_OP_breg0",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1121,7 +1010,6 @@
// 0x71 DW_OP_breg1
"DW_OP_breg1",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1130,7 +1018,6 @@
// 0x72 DW_OP_breg2
"DW_OP_breg2",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1139,7 +1026,6 @@
// 0x73 DW_OP_breg3
"DW_OP_breg3",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1148,7 +1034,6 @@
// 0x74 DW_OP_breg4
"DW_OP_breg4",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1157,7 +1042,6 @@
// 0x75 DW_OP_breg5
"DW_OP_breg5",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1166,7 +1050,6 @@
// 0x76 DW_OP_breg6
"DW_OP_breg6",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1175,7 +1058,6 @@
// 0x77 DW_OP_breg7
"DW_OP_breg7",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1184,7 +1066,6 @@
// 0x78 DW_OP_breg8
"DW_OP_breg8",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1193,7 +1074,6 @@
// 0x79 DW_OP_breg9
"DW_OP_breg9",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1202,7 +1082,6 @@
// 0x7a DW_OP_breg10
"DW_OP_breg10",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1211,7 +1090,6 @@
// 0x7b DW_OP_breg11
"DW_OP_breg11",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1220,7 +1098,6 @@
// 0x7c DW_OP_breg12
"DW_OP_breg12",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1229,7 +1106,6 @@
// 0x7d DW_OP_breg13
"DW_OP_breg13",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1238,7 +1114,6 @@
// 0x7e DW_OP_breg14
"DW_OP_breg14",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1247,7 +1122,6 @@
// 0x7f DW_OP_breg15
"DW_OP_breg15",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1256,7 +1130,6 @@
// 0x80 DW_OP_breg16
"DW_OP_breg16",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1265,7 +1138,6 @@
// 0x81 DW_OP_breg17
"DW_OP_breg17",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1274,7 +1146,6 @@
// 0x82 DW_OP_breg18
"DW_OP_breg18",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1283,7 +1154,6 @@
// 0x83 DW_OP_breg19
"DW_OP_breg19",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1292,7 +1162,6 @@
// 0x84 DW_OP_breg20
"DW_OP_breg20",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1301,7 +1170,6 @@
// 0x85 DW_OP_breg21
"DW_OP_breg21",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1310,7 +1178,6 @@
// 0x86 DW_OP_breg22
"DW_OP_breg22",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1319,7 +1186,6 @@
// 0x87 DW_OP_breg23
"DW_OP_breg23",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1328,7 +1194,6 @@
// 0x88 DW_OP_breg24
"DW_OP_breg24",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1337,7 +1202,6 @@
// 0x89 DW_OP_breg25
"DW_OP_breg25",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1346,7 +1210,6 @@
// 0x8a DW_OP_breg26
"DW_OP_breg26",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1355,7 +1218,6 @@
// 0x8b DW_OP_breg27
"DW_OP_breg27",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1364,7 +1226,6 @@
// 0x8c DW_OP_breg28
"DW_OP_breg28",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1373,7 +1234,6 @@
// 0x8d DW_OP_breg29
"DW_OP_breg29",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1382,7 +1242,6 @@
// 0x8e DW_OP_breg30
"DW_OP_breg30",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1391,7 +1250,6 @@
// 0x8f DW_OP_breg31
"DW_OP_breg31",
&DwarfOp::op_breg,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1400,7 +1258,6 @@
// 0x90 DW_OP_regx
"DW_OP_regx",
&DwarfOp::op_regx,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_uleb128},
@@ -1409,7 +1266,6 @@
// 0x91 DW_OP_fbreg
"DW_OP_fbreg",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_sleb128},
@@ -1418,7 +1274,6 @@
// 0x92 DW_OP_bregx
"DW_OP_bregx",
&DwarfOp::op_bregx,
- DWARF_VERSION_2,
0,
2,
{DW_EH_PE_uleb128, DW_EH_PE_sleb128},
@@ -1427,7 +1282,6 @@
// 0x93 DW_OP_piece
"DW_OP_piece",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_uleb128},
@@ -1436,7 +1290,6 @@
// 0x94 DW_OP_deref_size
"DW_OP_deref_size",
&DwarfOp::op_deref_size,
- DWARF_VERSION_2,
1,
1,
{DW_EH_PE_udata1},
@@ -1445,7 +1298,6 @@
// 0x95 DW_OP_xderef_size
"DW_OP_xderef_size",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_2,
0,
1,
{DW_EH_PE_udata1},
@@ -1454,7 +1306,6 @@
// 0x96 DW_OP_nop
"DW_OP_nop",
&DwarfOp::op_nop,
- DWARF_VERSION_2,
0,
0,
{},
@@ -1463,7 +1314,6 @@
// 0x97 DW_OP_push_object_address
"DW_OP_push_object_address",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_3,
0,
0,
{},
@@ -1472,7 +1322,6 @@
// 0x98 DW_OP_call2
"DW_OP_call2",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_3,
0,
1,
{DW_EH_PE_udata2},
@@ -1481,7 +1330,6 @@
// 0x99 DW_OP_call4
"DW_OP_call4",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_3,
0,
1,
{DW_EH_PE_udata4},
@@ -1490,7 +1338,6 @@
// 0x9a DW_OP_call_ref
"DW_OP_call_ref",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_3,
0,
0, // Has a different sized operand (4 bytes or 8 bytes).
{},
@@ -1499,7 +1346,6 @@
// 0x9b DW_OP_form_tls_address
"DW_OP_form_tls_address",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_3,
0,
0,
{},
@@ -1508,7 +1354,6 @@
// 0x9c DW_OP_call_frame_cfa
"DW_OP_call_frame_cfa",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_3,
0,
0,
{},
@@ -1517,7 +1362,6 @@
// 0x9d DW_OP_bit_piece
"DW_OP_bit_piece",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_3,
0,
2,
{DW_EH_PE_uleb128, DW_EH_PE_uleb128},
@@ -1526,7 +1370,6 @@
// 0x9e DW_OP_implicit_value
"DW_OP_implicit_value",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_4,
0,
1,
{DW_EH_PE_uleb128},
@@ -1535,107 +1378,106 @@
// 0x9f DW_OP_stack_value
"DW_OP_stack_value",
&DwarfOp::op_not_implemented,
- DWARF_VERSION_4,
1,
0,
{},
},
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa0 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa1 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa2 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa3 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa4 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa5 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa6 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa7 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa8 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xa9 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xaa illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xab illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xac illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xad illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xae illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xaf illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb0 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb1 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb2 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb3 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb4 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb5 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb6 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb7 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb8 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xb9 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xba illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xbb illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xbc illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xbd illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xbe illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xbf illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc0 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc1 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc2 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc3 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc4 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc5 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc6 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc7 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc8 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xc9 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xca illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xcb illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xcc illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xcd illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xce illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xcf illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd0 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd1 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd2 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd3 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd4 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd5 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd6 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd7 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd8 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xd9 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xda illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xdb illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xdc illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xdd illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xde illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xdf illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe0 DW_OP_lo_user
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe1 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe2 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe3 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe4 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe5 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe6 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe7 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe8 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xe9 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xea illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xeb illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xec illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xed illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xee illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xef illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf0 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf1 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf2 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf3 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf4 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf5 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf6 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf7 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf8 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xf9 illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xfa illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xfb illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xfc illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xfd illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xfe illegal op
- {nullptr, nullptr, 0, 0, 0, {}}, // 0xff DW_OP_hi_user
+ {nullptr, nullptr, 0, 0, {}}, // 0xa0 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa1 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa2 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa3 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa4 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa5 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa6 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa7 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa8 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xa9 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xaa illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xab illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xac illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xad illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xae illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xaf illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb0 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb1 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb2 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb3 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb4 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb5 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb6 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb7 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb8 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xb9 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xba illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xbb illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xbc illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xbd illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xbe illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xbf illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc0 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc1 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc2 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc3 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc4 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc5 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc6 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc7 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc8 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xc9 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xca illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xcb illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xcc illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xcd illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xce illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xcf illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd0 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd1 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd2 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd3 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd4 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd5 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd6 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd7 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd8 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xd9 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xda illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xdb illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xdc illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xdd illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xde illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xdf illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe0 DW_OP_lo_user
+ {nullptr, nullptr, 0, 0, {}}, // 0xe1 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe2 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe3 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe4 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe5 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe6 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe7 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe8 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xe9 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xea illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xeb illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xec illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xed illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xee illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xef illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf0 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf1 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf2 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf3 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf4 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf5 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf6 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf7 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf8 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xf9 illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xfa illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xfb illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xfc illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xfd illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xfe illegal op
+ {nullptr, nullptr, 0, 0, {}}, // 0xff DW_OP_hi_user
};
};
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index 4e94f88..7649798 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -26,16 +26,14 @@
#include <unwindstack/Regs.h>
#include "DwarfCfa.h"
-#include "DwarfEncoding.h"
-#include "DwarfOp.h"
-
#include "DwarfDebugFrame.h"
#include "DwarfEhFrame.h"
+#include "DwarfEncoding.h"
+#include "DwarfOp.h"
+#include "RegsInfo.h"
namespace unwindstack {
-constexpr uint64_t DEX_PC_REG = 0x20444558;
-
DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
@@ -75,14 +73,17 @@
}
template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, uint8_t version,
- Memory* regular_memory, AddressType* value) {
+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 start = loc.values[1];
- uint64_t end = start + loc.values[0];
- if (!op.Eval(start, end, version)) {
+ 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;
}
@@ -96,6 +97,9 @@
return false;
}
*value = op.StackAt(0);
+ if (is_dex_pc != nullptr && op.dex_pc_set()) {
+ *is_dex_pc = true;
+ }
return true;
}
@@ -103,12 +107,10 @@
struct EvalInfo {
const dwarf_loc_regs_t* loc_regs;
const DwarfCie* cie;
- RegsImpl<AddressType>* cur_regs;
Memory* regular_memory;
AddressType cfa;
bool return_address_undefined = false;
- uint64_t reg_map = 0;
- AddressType reg_values[64];
+ RegsInfo<AddressType> regs_info;
};
template <typename AddressType>
@@ -129,32 +131,18 @@
break;
case DWARF_LOCATION_REGISTER: {
uint32_t cur_reg = loc->values[0];
- if (cur_reg >= eval_info->cur_regs->total_regs()) {
+ if (cur_reg >= eval_info->regs_info.Total()) {
last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
return false;
}
- AddressType* cur_reg_ptr = &(*eval_info->cur_regs)[cur_reg];
- const auto& entry = eval_info->loc_regs->find(cur_reg);
- if (entry != eval_info->loc_regs->end()) {
- if (!(eval_info->reg_map & (1 << cur_reg))) {
- eval_info->reg_map |= 1 << cur_reg;
- eval_info->reg_values[cur_reg] = *cur_reg_ptr;
- if (!EvalRegister(&entry->second, cur_reg, cur_reg_ptr, eval_info)) {
- return false;
- }
- }
-
- // Use the register value from before any evaluations.
- *reg_ptr = eval_info->reg_values[cur_reg] + loc->values[1];
- } else {
- *reg_ptr = *cur_reg_ptr + loc->values[1];
- }
+ *reg_ptr = eval_info->regs_info.Get(cur_reg) + loc->values[1];
break;
}
case DWARF_LOCATION_EXPRESSION:
case DWARF_LOCATION_VAL_EXPRESSION: {
AddressType value;
- if (!EvalExpression(*loc, eval_info->cie->version, regular_memory, &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) {
@@ -165,6 +153,9 @@
}
} else {
*reg_ptr = value;
+ if (is_dex_pc) {
+ eval_info->regs_info.regs->set_dex_pc(value);
+ }
}
break;
}
@@ -201,8 +192,10 @@
AddressType prev_cfa = regs->sp();
- EvalInfo<AddressType> eval_info{
- .loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, .cur_regs = cur_regs};
+ 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) {
@@ -224,7 +217,7 @@
case DWARF_LOCATION_EXPRESSION:
case DWARF_LOCATION_VAL_EXPRESSION: {
AddressType value;
- if (!EvalExpression(*loc, cie->version, regular_memory, &value)) {
+ if (!EvalExpression(*loc, regular_memory, &value, &eval_info.regs_info, nullptr)) {
return false;
}
if (loc->type == DWARF_LOCATION_EXPRESSION) {
@@ -249,28 +242,15 @@
if (reg == CFA_REG) continue;
AddressType* reg_ptr;
- AddressType dex_pc = 0;
- if (reg == DEX_PC_REG) {
- // Special register that indicates this is a dex pc.
- dex_pc = 0;
- reg_ptr = &dex_pc;
- } else if (reg >= cur_regs->total_regs() || eval_info.reg_map & (1 << reg)) {
- // Skip this unknown register, or a register that has already been
- // processed.
+ if (reg >= cur_regs->total_regs()) {
+ // Skip this unknown register.
continue;
- } else {
- reg_ptr = &(*cur_regs)[reg];
- eval_info.reg_map |= 1 << reg;
- eval_info.reg_values[reg] = *reg_ptr;
}
+ reg_ptr = eval_info.regs_info.Save(reg);
if (!EvalRegister(&entry.second, reg, reg_ptr, &eval_info)) {
return false;
}
-
- if (reg == DEX_PC_REG) {
- cur_regs->set_dex_pc(dex_pc);
- }
}
// Find the return address location.
diff --git a/libunwindstack/ElfInterfaceArm.cpp b/libunwindstack/ElfInterfaceArm.cpp
index 616d1b1..dfb8e8f 100644
--- a/libunwindstack/ElfInterfaceArm.cpp
+++ b/libunwindstack/ElfInterfaceArm.cpp
@@ -17,12 +17,12 @@
#include <elf.h>
#include <stdint.h>
+#include <unwindstack/MachineArm.h>
#include <unwindstack/Memory.h>
#include <unwindstack/RegsArm.h>
#include "ArmExidx.h"
#include "ElfInterfaceArm.h"
-#include "MachineArm.h"
namespace unwindstack {
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index d1dc0e6..0c319ec 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -172,7 +172,7 @@
// Regardless of what happens below, consider the init finished.
initialized_ = true;
- std::string descriptor_name("__jit_debug_descriptor");
+ const std::string descriptor_name("__jit_debug_descriptor");
for (MapInfo* info : *maps) {
if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) {
continue;
diff --git a/libunwindstack/Regs.cpp b/libunwindstack/Regs.cpp
index 7feafad..c7dec52 100644
--- a/libunwindstack/Regs.cpp
+++ b/libunwindstack/Regs.cpp
@@ -25,17 +25,16 @@
#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 "UserArm.h"
-#include "UserArm64.h"
-#include "UserX86.h"
-#include "UserX86_64.h"
-#include "UserMips.h"
-#include "UserMips64.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 {
diff --git a/libunwindstack/RegsArm.cpp b/libunwindstack/RegsArm.cpp
index d05c3e2..7f16146 100644
--- a/libunwindstack/RegsArm.cpp
+++ b/libunwindstack/RegsArm.cpp
@@ -19,13 +19,12 @@
#include <functional>
#include <unwindstack/Elf.h>
+#include <unwindstack/MachineArm.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
#include <unwindstack/RegsArm.h>
-
-#include "MachineArm.h"
-#include "UcontextArm.h"
-#include "UserArm.h"
+#include <unwindstack/UcontextArm.h>
+#include <unwindstack/UserArm.h>
namespace unwindstack {
diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp
index 2077bc5..d6b467a 100644
--- a/libunwindstack/RegsArm64.cpp
+++ b/libunwindstack/RegsArm64.cpp
@@ -19,13 +19,12 @@
#include <functional>
#include <unwindstack/Elf.h>
+#include <unwindstack/MachineArm64.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
#include <unwindstack/RegsArm64.h>
-
-#include "MachineArm64.h"
-#include "UcontextArm64.h"
-#include "UserArm64.h"
+#include <unwindstack/UcontextArm64.h>
+#include <unwindstack/UserArm64.h>
namespace unwindstack {
diff --git a/libunwindstack/RegsInfo.h b/libunwindstack/RegsInfo.h
new file mode 100644
index 0000000..47825f5
--- /dev/null
+++ b/libunwindstack/RegsInfo.h
@@ -0,0 +1,66 @@
+/*
+ * 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 {
+ RegsInfo(RegsImpl<AddressType>* regs) : regs(regs) {}
+
+ RegsImpl<AddressType>* regs = nullptr;
+ uint64_t saved_reg_map = 0;
+ AddressType saved_regs[64];
+
+ inline AddressType Get(uint32_t reg) {
+ if (IsSaved(reg)) {
+ return saved_regs[reg];
+ }
+ return (*regs)[reg];
+ }
+
+ inline AddressType* Save(uint32_t reg) {
+ if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
+ // This should never happen as since all currently supported
+ // architectures have the total number of registers < 64.
+ abort();
+ }
+ saved_reg_map |= 1 << reg;
+ saved_regs[reg] = (*regs)[reg];
+ return &(*regs)[reg];
+ }
+
+ inline bool IsSaved(uint32_t reg) {
+ if (reg > sizeof(saved_regs) / sizeof(AddressType)) {
+ // This should never happen as since all currently supported
+ // architectures have the total number of registers < 64.
+ abort();
+ }
+ return saved_reg_map & (1 << 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
index 44cde05..6751f52 100644
--- a/libunwindstack/RegsMips.cpp
+++ b/libunwindstack/RegsMips.cpp
@@ -19,13 +19,12 @@
#include <functional>
#include <unwindstack/Elf.h>
+#include <unwindstack/MachineMips.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
#include <unwindstack/RegsMips.h>
-
-#include "MachineMips.h"
-#include "UcontextMips.h"
-#include "UserMips.h"
+#include <unwindstack/UcontextMips.h>
+#include <unwindstack/UserMips.h>
namespace unwindstack {
diff --git a/libunwindstack/RegsMips64.cpp b/libunwindstack/RegsMips64.cpp
index b4e5246..97082bd 100644
--- a/libunwindstack/RegsMips64.cpp
+++ b/libunwindstack/RegsMips64.cpp
@@ -19,13 +19,12 @@
#include <functional>
#include <unwindstack/Elf.h>
+#include <unwindstack/MachineMips64.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
#include <unwindstack/RegsMips64.h>
-
-#include "MachineMips64.h"
-#include "UcontextMips64.h"
-#include "UserMips64.h"
+#include <unwindstack/UcontextMips64.h>
+#include <unwindstack/UserMips64.h>
namespace unwindstack {
diff --git a/libunwindstack/RegsX86.cpp b/libunwindstack/RegsX86.cpp
index ef2f3de..27476b7 100644
--- a/libunwindstack/RegsX86.cpp
+++ b/libunwindstack/RegsX86.cpp
@@ -19,13 +19,12 @@
#include <functional>
#include <unwindstack/Elf.h>
+#include <unwindstack/MachineX86.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
#include <unwindstack/RegsX86.h>
-
-#include "MachineX86.h"
-#include "UcontextX86.h"
-#include "UserX86.h"
+#include <unwindstack/UcontextX86.h>
+#include <unwindstack/UserX86.h>
namespace unwindstack {
diff --git a/libunwindstack/RegsX86_64.cpp b/libunwindstack/RegsX86_64.cpp
index 70921f8..0f66943 100644
--- a/libunwindstack/RegsX86_64.cpp
+++ b/libunwindstack/RegsX86_64.cpp
@@ -19,13 +19,12 @@
#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 "MachineX86_64.h"
-#include "UcontextX86_64.h"
-#include "UserX86_64.h"
+#include <unwindstack/UcontextX86_64.h>
+#include <unwindstack/UserX86_64.h>
namespace unwindstack {
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index db8278e..d52a0bf 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -48,54 +48,33 @@
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();
- auto it = maps_->begin();
- uint64_t rel_dex_pc;
- MapInfo* info;
- for (; it != maps_->end(); ++it) {
- auto entry = *it;
- if (dex_pc >= entry->start && dex_pc < entry->end) {
- info = entry;
- rel_dex_pc = dex_pc - entry->start;
- frame->map_start = entry->start;
- frame->map_end = entry->end;
- frame->map_offset = entry->offset;
- frame->map_load_bias = entry->load_bias;
- frame->map_flags = entry->flags;
- frame->map_name = entry->name;
- frame->rel_pc = rel_dex_pc;
- break;
- }
- }
-
- if (it == maps_->end() || ++it == maps_->end()) {
- return;
- }
-
- auto entry = *it;
- unwindstack::Elf* elf = entry->GetElf(process_memory_, true);
- if (!elf->valid()) {
- return;
- }
-
- // Adjust the relative dex by the offset.
- rel_dex_pc += entry->elf_offset;
-
- uint64_t dex_offset;
- if (!elf->GetFunctionName(rel_dex_pc, &frame->function_name, &dex_offset)) {
- return;
- }
- frame->function_offset = dex_offset;
- if (frame->function_name != "$dexfile") {
+ MapInfo* info = maps_->Find(dex_pc);
+ if (info != nullptr) {
+ frame->map_start = info->start;
+ frame->map_end = info->end;
+ frame->map_offset = info->offset;
+ frame->map_load_bias = info->load_bias;
+ frame->map_flags = info->flags;
+ frame->map_name = info->name;
+ frame->rel_pc = dex_pc - info->start;
+ } else {
+ frame->rel_pc = dex_pc;
return;
}
#if !defined(NO_LIBDEXFILE_SUPPORT)
- dex_files_->GetMethodInformation(dex_pc - dex_offset, dex_offset, info, &frame->function_name,
+ if (dex_files_ == nullptr) {
+ return;
+ }
+
+ // dex_files_->GetMethodInformation(dex_pc - dex_offset, dex_offset, info, &frame->function_name,
+ dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
&frame->function_offset);
#endif
}
@@ -113,7 +92,7 @@
return;
}
- frame->pc = map_info->start + adjusted_rel_pc;
+ frame->pc = map_info->start + adjusted_rel_pc - elf->GetLoadBias() - map_info->elf_offset;
frame->map_name = map_info->name;
frame->map_offset = map_info->offset;
frame->map_start = map_info->start;
@@ -197,6 +176,8 @@
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);
}
FillInFrame(map_info, elf, adjusted_rel_pc, adjusted_pc);
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
index 50c9c32..26f5d35 100644
--- a/libunwindstack/include/unwindstack/DexFiles.h
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -23,6 +23,7 @@
#include <mutex>
#include <string>
#include <unordered_map>
+#include <vector>
namespace unwindstack {
@@ -36,19 +37,40 @@
class DexFiles {
public:
explicit DexFiles(std::shared_ptr<Memory>& memory);
+ DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
~DexFiles();
DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
- void GetMethodInformation(uint64_t dex_file_offset, uint64_t dex_offset, MapInfo* info,
- std::string* method_name, uint64_t* method_offset);
+ void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
+ uint64_t* method_offset);
void SetArch(ArchEnum arch);
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();
+
std::shared_ptr<Memory> memory_;
- std::mutex files_lock_;
+ std::vector<std::string> search_libs_;
+
+ std::mutex lock_;
+ bool initialized_ = false;
std::unordered_map<uint64_t, 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
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 03f40d6..da91fd0 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -32,6 +32,8 @@
// Forward declarations.
class Memory;
class Regs;
+template <typename AddressType>
+struct RegsInfo;
class DwarfSection {
public:
@@ -149,8 +151,8 @@
bool Log(uint8_t indent, uint64_t pc, uint64_t load_bias, const DwarfFde* fde) override;
protected:
- bool EvalExpression(const DwarfLocation& loc, uint8_t version, Memory* regular_memory,
- AddressType* value);
+ bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
+ RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
bool GetCieInfo(uint8_t* segment_size, uint8_t* encoding);
diff --git a/libunwindstack/MachineArm.h b/libunwindstack/include/unwindstack/MachineArm.h
similarity index 100%
rename from libunwindstack/MachineArm.h
rename to libunwindstack/include/unwindstack/MachineArm.h
diff --git a/libunwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h
similarity index 100%
rename from libunwindstack/MachineArm64.h
rename to libunwindstack/include/unwindstack/MachineArm64.h
diff --git a/libunwindstack/MachineMips.h b/libunwindstack/include/unwindstack/MachineMips.h
similarity index 100%
rename from libunwindstack/MachineMips.h
rename to libunwindstack/include/unwindstack/MachineMips.h
diff --git a/libunwindstack/MachineMips64.h b/libunwindstack/include/unwindstack/MachineMips64.h
similarity index 100%
rename from libunwindstack/MachineMips64.h
rename to libunwindstack/include/unwindstack/MachineMips64.h
diff --git a/libunwindstack/MachineX86.h b/libunwindstack/include/unwindstack/MachineX86.h
similarity index 100%
rename from libunwindstack/MachineX86.h
rename to libunwindstack/include/unwindstack/MachineX86.h
diff --git a/libunwindstack/MachineX86_64.h b/libunwindstack/include/unwindstack/MachineX86_64.h
similarity index 100%
rename from libunwindstack/MachineX86_64.h
rename to libunwindstack/include/unwindstack/MachineX86_64.h
diff --git a/libunwindstack/UcontextArm.h b/libunwindstack/include/unwindstack/UcontextArm.h
similarity index 98%
rename from libunwindstack/UcontextArm.h
rename to libunwindstack/include/unwindstack/UcontextArm.h
index 8c94166..7d1ec3b 100644
--- a/libunwindstack/UcontextArm.h
+++ b/libunwindstack/include/unwindstack/UcontextArm.h
@@ -31,7 +31,7 @@
#include <stdint.h>
-#include "MachineArm.h"
+#include <unwindstack/MachineArm.h>
namespace unwindstack {
diff --git a/libunwindstack/UcontextArm64.h b/libunwindstack/include/unwindstack/UcontextArm64.h
similarity index 98%
rename from libunwindstack/UcontextArm64.h
rename to libunwindstack/include/unwindstack/UcontextArm64.h
index 655719f..a68be3b 100644
--- a/libunwindstack/UcontextArm64.h
+++ b/libunwindstack/include/unwindstack/UcontextArm64.h
@@ -31,7 +31,7 @@
#include <stdint.h>
-#include "MachineArm64.h"
+#include <unwindstack/MachineArm64.h>
namespace unwindstack {
diff --git a/libunwindstack/UcontextMips.h b/libunwindstack/include/unwindstack/UcontextMips.h
similarity index 97%
rename from libunwindstack/UcontextMips.h
rename to libunwindstack/include/unwindstack/UcontextMips.h
index 27185e7..02e33b6 100644
--- a/libunwindstack/UcontextMips.h
+++ b/libunwindstack/include/unwindstack/UcontextMips.h
@@ -31,7 +31,7 @@
#include <stdint.h>
-#include "MachineMips.h"
+#include <unwindstack/MachineMips.h>
namespace unwindstack {
diff --git a/libunwindstack/UcontextMips64.h b/libunwindstack/include/unwindstack/UcontextMips64.h
similarity index 96%
rename from libunwindstack/UcontextMips64.h
rename to libunwindstack/include/unwindstack/UcontextMips64.h
index 623bf3a..5b92a55 100644
--- a/libunwindstack/UcontextMips64.h
+++ b/libunwindstack/include/unwindstack/UcontextMips64.h
@@ -31,7 +31,7 @@
#include <stdint.h>
-#include "MachineMips64.h"
+#include <unwindstack/MachineMips64.h>
namespace unwindstack {
@@ -66,4 +66,4 @@
} // namespace unwindstack
-#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS6464_H
+#endif // _LIBUNWINDSTACK_UCONTEXT_MIPS64_H
diff --git a/libunwindstack/UcontextX86.h b/libunwindstack/include/unwindstack/UcontextX86.h
similarity index 98%
rename from libunwindstack/UcontextX86.h
rename to libunwindstack/include/unwindstack/UcontextX86.h
index f79d92b..c96ebb7 100644
--- a/libunwindstack/UcontextX86.h
+++ b/libunwindstack/include/unwindstack/UcontextX86.h
@@ -31,7 +31,7 @@
#include <stdint.h>
-#include "MachineX86.h"
+#include <unwindstack/MachineX86.h>
namespace unwindstack {
diff --git a/libunwindstack/UcontextX86_64.h b/libunwindstack/include/unwindstack/UcontextX86_64.h
similarity index 98%
rename from libunwindstack/UcontextX86_64.h
rename to libunwindstack/include/unwindstack/UcontextX86_64.h
index 2b8bdc4..4e163e5 100644
--- a/libunwindstack/UcontextX86_64.h
+++ b/libunwindstack/include/unwindstack/UcontextX86_64.h
@@ -31,7 +31,7 @@
#include <stdint.h>
-#include "MachineX86_64.h"
+#include <unwindstack/MachineX86_64.h>
namespace unwindstack {
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index e8af8b4..ebe7b0a 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -45,14 +45,14 @@
uint64_t sp;
std::string function_name;
- uint64_t function_offset;
+ uint64_t function_offset = 0;
std::string map_name;
- uint64_t map_offset;
- uint64_t map_start;
- uint64_t map_end;
- uint64_t map_load_bias;
- int map_flags;
+ uint64_t map_offset = 0;
+ uint64_t map_start = 0;
+ uint64_t map_end = 0;
+ uint64_t map_load_bias = 0;
+ int map_flags = 0;
};
class Unwinder {
diff --git a/libunwindstack/UserArm.h b/libunwindstack/include/unwindstack/UserArm.h
similarity index 100%
rename from libunwindstack/UserArm.h
rename to libunwindstack/include/unwindstack/UserArm.h
diff --git a/libunwindstack/UserArm64.h b/libunwindstack/include/unwindstack/UserArm64.h
similarity index 100%
rename from libunwindstack/UserArm64.h
rename to libunwindstack/include/unwindstack/UserArm64.h
diff --git a/libunwindstack/UserMips.h b/libunwindstack/include/unwindstack/UserMips.h
similarity index 100%
rename from libunwindstack/UserMips.h
rename to libunwindstack/include/unwindstack/UserMips.h
diff --git a/libunwindstack/UserMips64.h b/libunwindstack/include/unwindstack/UserMips64.h
similarity index 100%
rename from libunwindstack/UserMips64.h
rename to libunwindstack/include/unwindstack/UserMips64.h
diff --git a/libunwindstack/UserX86.h b/libunwindstack/include/unwindstack/UserX86.h
similarity index 100%
rename from libunwindstack/UserX86.h
rename to libunwindstack/include/unwindstack/UserX86.h
diff --git a/libunwindstack/UserX86_64.h b/libunwindstack/include/unwindstack/UserX86_64.h
similarity index 100%
rename from libunwindstack/UserX86_64.h
rename to libunwindstack/include/unwindstack/UserX86_64.h
diff --git a/libunwindstack/tests/DexFileData.h b/libunwindstack/tests/DexFileData.h
new file mode 100644
index 0000000..6975c68
--- /dev/null
+++ b/libunwindstack/tests/DexFileData.h
@@ -0,0 +1,45 @@
+/*
+ * 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
index d1338cb..0b02c5b 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -25,38 +25,18 @@
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
-#include <dex/code_item_accessors-no_art-inl.h>
+#include <dex/code_item_accessors-inl.h>
#include <dex/standard_dex_file.h>
#include <gtest/gtest.h>
#include "DexFile.h"
+#include "DexFileData.h"
#include "MemoryFake.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,
-};
-
TEST(DexFileTest, from_file_open_non_exist) {
DexFileFromFile dex_file;
ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist"));
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
new file mode 100644
index 0000000..dca5605
--- /dev/null
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -0,0 +1,311 @@
+/*
+ * 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 SetUp() override {
+ memory_ = new MemoryFake;
+ process_memory_.reset(memory_);
+
+ dex_files_.reset(new DexFiles(process_memory_));
+ dex_files_->SetArch(ARCH_ARM);
+
+ maps_.reset(
+ new BufferMaps("1000-4000 ---s 00000000 00:00 0\n"
+ "4000-6000 r--s 00000000 00:00 0\n"
+ "6000-8000 -w-s 00000000 00:00 0\n"
+ "a000-c000 r-xp 00000000 00:00 0\n"
+ "c000-f000 rwxp 00000000 00:00 0\n"
+ "f000-11000 r-xp 00000000 00:00 0\n"
+ "100000-110000 rw-p 0000000 00:00 0\n"
+ "200000-210000 rw-p 0000000 00:00 0\n"
+ "300000-400000 rw-p 0000000 00:00 0\n"));
+ ASSERT_TRUE(maps_->Parse());
+
+ // Global variable in a section that is not readable/executable.
+ MapInfo* map_info = maps_->Get(kMapGlobalNonReadableExectable);
+ ASSERT_TRUE(map_info != nullptr);
+ MemoryFake* memory = new MemoryFake;
+ ElfFake* elf = new ElfFake(memory);
+ elf->FakeSetValid(true);
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
+ elf->FakeSetInterface(interface);
+ interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+ map_info->elf.reset(elf);
+
+ // Global variable not set by default.
+ map_info = maps_->Get(kMapGlobalSetToZero);
+ ASSERT_TRUE(map_info != nullptr);
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
+ elf->FakeSetValid(true);
+ interface = new ElfInterfaceFake(memory);
+ elf->FakeSetInterface(interface);
+ interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+ map_info->elf.reset(elf);
+
+ // Global variable set in this map.
+ map_info = maps_->Get(kMapGlobal);
+ ASSERT_TRUE(map_info != nullptr);
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
+ elf->FakeSetValid(true);
+ interface = new ElfInterfaceFake(memory);
+ elf->FakeSetInterface(interface);
+ interface->FakeSetGlobalVariable("__art_debug_dexfiles", 0x800);
+ map_info->elf.reset(elf);
+ }
+
+ 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 kMapGlobalNonReadableExectable = 3;
+ static constexpr size_t kMapGlobalSetToZero = 4;
+ static constexpr size_t kMapGlobal = 5;
+ static constexpr size_t kMapDexFileEntries = 7;
+ static constexpr size_t kMapDexFiles = 8;
+
+ std::shared_ptr<Memory> process_memory_;
+ MemoryFake* memory_;
+ std::unique_ptr<DexFiles> dex_files_;
+ std::unique_ptr<BufferMaps> maps_;
+};
+
+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);
+
+ memory_->SetData32(0xf800, 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) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ dex_files_->SetArch(ARCH_ARM64);
+ memory_->SetData64(0xf800, 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);
+
+ memory_->SetData32(0xf800, 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) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ dex_files_->SetArch(ARCH_ARM64);
+ memory_->SetData64(0xf800, 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);
+
+ memory_->SetData32(0xf800, 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);
+
+ memory_->SetData32(0xf800, 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);
+ // 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.
+ memory_->SetData32(0xc800, 0);
+
+ memory_->SetData32(0xf800, 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;
+ memory_->SetData32(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) {
+ std::string method_name = "nothing";
+ uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
+
+ // First global variable found, but value is zero.
+ memory_->SetData64(0xc800, 0);
+
+ memory_->SetData64(0xf800, 0x200000);
+ WriteEntry64(0x200000, 0, 0, 0x300000);
+ WriteDex(0x300000);
+
+ dex_files_->SetArch(ARCH_ARM64);
+ 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;
+ memory_->SetData32(0xc800, 0x100000);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
+ EXPECT_EQ("fail", method_name);
+ EXPECT_EQ(0x123U, method_offset);
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index a2ae5eb..4240419 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -134,7 +134,7 @@
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x1384U, info->pc);
+ EXPECT_EQ(0x1380U, info->pc);
EXPECT_EQ(0x1540U, info->offset);
}
@@ -149,7 +149,7 @@
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x3344U, info->pc);
+ EXPECT_EQ(0x3340U, info->pc);
EXPECT_EQ(0x3500U, info->offset);
}
@@ -163,7 +163,7 @@
auto info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x344U, info->pc);
+ 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.
@@ -171,7 +171,7 @@
info = this->eh_frame_->GetFdeInfoFromIndex(2);
ASSERT_TRUE(info != nullptr);
- EXPECT_EQ(0x344U, info->pc);
+ EXPECT_EQ(0x340U, info->pc);
EXPECT_EQ(0x500U, info->offset);
}
diff --git a/libunwindstack/tests/DwarfOpTest.cpp b/libunwindstack/tests/DwarfOpTest.cpp
index 036226d..6e15227 100644
--- a/libunwindstack/tests/DwarfOpTest.cpp
+++ b/libunwindstack/tests/DwarfOpTest.cpp
@@ -52,14 +52,14 @@
TYPED_TEST_P(DwarfOpTest, decode) {
// Memory error.
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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());
@@ -67,14 +67,14 @@
TYPED_TEST_P(DwarfOpTest, eval) {
// Memory error.
- ASSERT_FALSE(this->op_->Eval(0, 2, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ 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());
@@ -85,7 +85,7 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Eval(0, 8, DWARF_VERSION_MAX));
+ 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());
@@ -97,7 +97,7 @@
// Infinite loop.
this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x2f, 0xfd, 0xff});
- ASSERT_FALSE(this->op_->Eval(0, 4, DWARF_VERSION_MAX));
+ 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());
@@ -112,29 +112,7 @@
this->op_memory_.SetMemory(0, opcode_buffer);
for (size_t i = 0; i < opcode_buffer.size(); i++) {
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
- ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, illegal_in_version3) {
- std::vector<uint8_t> opcode_buffer = {0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d};
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- for (size_t i = 0; i < opcode_buffer.size(); i++) {
- ASSERT_FALSE(this->op_->Decode(2));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
- ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
- }
-}
-
-TYPED_TEST_P(DwarfOpTest, illegal_in_version4) {
- std::vector<uint8_t> opcode_buffer = {0x9e, 0x9f};
- this->op_memory_.SetMemory(0, opcode_buffer);
-
- for (size_t i = 0; i < opcode_buffer.size(); i++) {
- ASSERT_FALSE(this->op_->Decode(3));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
ASSERT_EQ(opcode_buffer[i], this->op_->cur_op());
}
@@ -174,12 +152,12 @@
this->op_memory_.SetMemory(0, opcode_buffer);
// Push the stack values.
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_NOT_IMPLEMENTED, this->op_->LastErrorCode());
}
}
@@ -194,7 +172,7 @@
}
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x03, this->op_->cur_op());
ASSERT_EQ(1U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -217,17 +195,17 @@
TypeParam value = 0x12345678;
this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
ASSERT_EQ(0x12345678U, this->op_->LastErrorAddress());
}
@@ -237,14 +215,14 @@
TypeParam value = 0x12345678;
this->regular_memory_.SetMemory(0x2010, &value, sizeof(value));
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX)) << "Failed at size " << 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;
@@ -254,17 +232,17 @@
// Zero byte read.
this->op_memory_.SetMemory(0, std::vector<uint8_t>{0x0a, 0x10, 0x20, 0x94, 0x00});
- ASSERT_FALSE(this->op_->Eval(0, 5, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Eval(0, 5));
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->op_->LastErrorCode());
EXPECT_EQ(0x4010U, this->op_->LastErrorAddress());
}
@@ -284,40 +262,40 @@
this->op_memory_.SetMemory(0, opcode_buffer);
// const1u
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x0e, this->op_->cur_op());
ASSERT_EQ(7U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -326,7 +304,7 @@
ASSERT_EQ(0x0102030405060708ULL, this->op_->StackAt(0));
}
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x0e, this->op_->cur_op());
ASSERT_EQ(8U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -351,40 +329,40 @@
this->op_memory_.SetMemory(0, opcode_buffer);
// const1s
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x0f, this->op_->cur_op());
ASSERT_EQ(7U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -393,7 +371,7 @@
ASSERT_EQ(0x1223344556677889ULL, this->op_->StackAt(0));
}
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x0f, this->op_->cur_op());
ASSERT_EQ(8U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -414,28 +392,28 @@
this->op_memory_.SetMemory(0, opcode_buffer);
// Single byte ULEB128
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x10, this->op_->cur_op());
ASSERT_EQ(5U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -444,7 +422,7 @@
ASSERT_EQ(0x9101c305080c101ULL, this->op_->StackAt(0));
}
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x10, this->op_->cur_op());
ASSERT_EQ(6U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -480,28 +458,28 @@
this->op_memory_.SetMemory(0, opcode_buffer);
// Single byte SLEB128
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x11, this->op_->cur_op());
ASSERT_EQ(5U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -510,7 +488,7 @@
ASSERT_EQ(0x9101c305080c101ULL, this->op_->StackAt(0));
}
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x11, this->op_->cur_op());
ASSERT_EQ(6U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -531,21 +509,21 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -565,21 +543,21 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x13, this->op_->cur_op());
ASSERT_EQ(0U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(0x13, this->op_->cur_op());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
@@ -597,24 +575,24 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(0x14, this->op_->cur_op());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
@@ -632,14 +610,14 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -647,7 +625,7 @@
ASSERT_EQ(0xedU, this->op_->StackAt(2));
ASSERT_EQ(0x1aU, this->op_->StackAt(3));
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -656,7 +634,7 @@
ASSERT_EQ(0xedU, this->op_->StackAt(3));
ASSERT_EQ(0x1aU, this->op_->StackAt(4));
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(0x15, this->op_->cur_op());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
@@ -672,23 +650,23 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(0x16, this->op_->cur_op());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
}
@@ -706,28 +684,28 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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));
@@ -756,30 +734,30 @@
opcode_buffer.push_back(0x19);
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
ASSERT_EQ(0x10U, this->op_->StackAt(0));
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x19, this->op_->cur_op());
ASSERT_EQ(3U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -808,56 +786,56 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
// Two positive values.
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(4U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(5U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
}
@@ -874,19 +852,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -905,19 +883,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -938,29 +916,29 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(3U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
}
@@ -977,19 +955,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1006,21 +984,21 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1037,21 +1015,21 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1070,19 +1048,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1101,19 +1079,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1128,13 +1106,13 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1153,19 +1131,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1184,19 +1162,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x25, this->op_->cur_op());
ASSERT_EQ(1U, this->op_->StackSize());
if (sizeof(TypeParam) == 4) {
@@ -1219,19 +1197,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1250,19 +1228,19 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Decode());
ASSERT_EQ(DWARF_ERROR_STACK_INDEX_NOT_VALID, this->op_->LastErrorCode());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(2U, this->op_->StackSize());
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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));
@@ -1283,48 +1261,48 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
uint64_t offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(1U, this->op_->StackSize());
offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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());
@@ -1344,11 +1322,11 @@
opcode_buffer[3] = opcode;
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_FALSE(this->op_->Eval(0, 1, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ 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());
@@ -1387,7 +1365,7 @@
opcode_buffer[14] = expected[i];
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Eval(0, 15, DWARF_VERSION_MAX))
+ ASSERT_TRUE(this->op_->Eval(0, 15))
<< "Op: 0x" << std::hex << static_cast<uint32_t>(expected[i]) << " failed";
ASSERT_EQ(3U, this->op_->StackSize());
@@ -1407,14 +1385,14 @@
this->op_memory_.SetMemory(0, opcode_buffer);
uint64_t offset = this->mem_->cur_offset() + 3;
- ASSERT_TRUE(this->op_->Decode(DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ 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());
@@ -1431,7 +1409,7 @@
for (size_t i = 0; i < opcode_buffer.size(); i++) {
uint32_t op = opcode_buffer[i];
- ASSERT_TRUE(this->op_->Eval(i, i + 1, DWARF_VERSION_MAX)) << "Failed op: 0x" << std::hex << op;
+ 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;
@@ -1449,7 +1427,7 @@
for (size_t i = 0; i < opcode_buffer.size(); i++) {
uint32_t op = opcode_buffer[i];
- ASSERT_TRUE(this->op_->Eval(i, i + 1, DWARF_VERSION_MAX)) << "Failed op: 0x" << std::hex << op;
+ 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;
@@ -1463,13 +1441,13 @@
};
this->op_memory_.SetMemory(0, opcode_buffer);
- ASSERT_TRUE(this->op_->Eval(0, 2, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ 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());
@@ -1494,21 +1472,20 @@
for (size_t i = 0; i < 32; i++) {
regs[i] = i + 10;
}
- this->op_->set_regs(®s);
+ 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, DWARF_VERSION_MAX)) << "Failed op: 0x"
- << std::hex << op;
+ 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, DWARF_VERSION_MAX)) << "Failed op: 0x"
- << std::hex << op;
+ 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;
@@ -1526,16 +1503,17 @@
for (size_t i = 0; i < 16; i++) {
regs[i] = i + 10;
}
- this->op_->set_regs(®s);
+ 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, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ ASSERT_FALSE(this->op_->Eval(2, 4));
ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->op_->LastErrorCode());
}
@@ -1551,38 +1529,55 @@
RegsImplFake<TypeParam> regs(10, 10);
regs[5] = 0x45;
regs[6] = 0x190;
- this->op_->set_regs(®s);
+ RegsInfo<TypeParam> regs_info(®s);
+ this->op_->set_regs_info(®s_info);
- ASSERT_TRUE(this->op_->Eval(0, 3, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ 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, DWARF_VERSION_MAX));
+ 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(DWARF_VERSION_MAX));
+ ASSERT_TRUE(this->op_->Decode());
ASSERT_EQ(0x96, this->op_->cur_op());
ASSERT_EQ(0U, this->op_->StackSize());
}
-REGISTER_TYPED_TEST_CASE_P(DwarfOpTest, decode, eval, illegal_opcode, illegal_in_version3,
- illegal_in_version4, 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);
+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_CASE_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_CASE_P(, DwarfOpTest, DwarfOpTestTypes);
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index 7e10935..37305b2 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -99,7 +99,7 @@
regs.set_sp(0x2000);
regs[5] = 0x20;
regs[9] = 0x3000;
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_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());
@@ -116,7 +116,7 @@
regs[5] = 0x20;
regs[9] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x96, 0x96, 0x96});
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_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());
@@ -134,7 +134,7 @@
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, 0x5000}};
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x4, 0x5004}};
bool finished;
ASSERT_TRUE(this->section_->Eval(&cie, &this->memory_, loc_regs, ®s, &finished));
EXPECT_FALSE(finished);
@@ -152,7 +152,7 @@
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, 0x5000}};
+ 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);
@@ -170,7 +170,7 @@
regs[5] = 0x20;
regs[9] = 0x3000;
this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x50, 0x96, 0x96});
- loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_EXPRESSION, {0x2, 0x5000}};
+ loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_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());
@@ -322,7 +322,8 @@
regs[0] = 0x10;
regs[8] = 0x20;
loc_regs[CFA_REG] = DwarfLocation{DWARF_LOCATION_REGISTER, {8, 0}};
- loc_regs[0x20444558] = DwarfLocation{DWARF_LOCATION_REGISTER, {0, 1}};
+ 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]);
@@ -462,7 +463,7 @@
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, 0x5000}};
+ 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);
@@ -480,7 +481,7 @@
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, 0x5000}};
+ 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);
diff --git a/libunwindstack/tests/ElfInterfaceArmTest.cpp b/libunwindstack/tests/ElfInterfaceArmTest.cpp
index 31d6a63..70a52ad 100644
--- a/libunwindstack/tests/ElfInterfaceArmTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceArmTest.cpp
@@ -20,10 +20,10 @@
#include <vector>
+#include <unwindstack/MachineArm.h>
#include <unwindstack/RegsArm.h>
#include "ElfInterfaceArm.h"
-#include "MachineArm.h"
#include "ElfFake.h"
#include "MemoryFake.h"
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 37628f8..c1c45f8 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -56,30 +56,30 @@
MapInfo* map_info = maps_->Get(3);
ASSERT_TRUE(map_info != nullptr);
- elf_memories_.push_back(new MemoryFake);
- ElfFake* elf = new ElfFake(elf_memories_.back());
+ MemoryFake* memory = new MemoryFake;
+ ElfFake* elf = new ElfFake(memory);
elf->FakeSetValid(true);
- ElfInterfaceFake* interface = new ElfInterfaceFake(elf_memories_.back());
+ ElfInterfaceFake* interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
map_info = maps_->Get(5);
ASSERT_TRUE(map_info != nullptr);
- elf_memories_.push_back(new MemoryFake);
- elf = new ElfFake(elf_memories_.back());
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
elf->FakeSetValid(true);
- interface = new ElfInterfaceFake(elf_memories_.back());
+ interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
map_info = maps_->Get(6);
ASSERT_TRUE(map_info != nullptr);
- elf_memories_.push_back(new MemoryFake);
- elf = new ElfFake(elf_memories_.back());
+ memory = new MemoryFake;
+ elf = new ElfFake(memory);
elf->FakeSetValid(true);
- interface = new ElfInterfaceFake(elf_memories_.back());
+ interface = new ElfInterfaceFake(memory);
elf->FakeSetInterface(interface);
interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x800);
map_info->elf.reset(elf);
@@ -171,7 +171,6 @@
std::shared_ptr<Memory> process_memory_;
MemoryFake* memory_;
- std::vector<MemoryFake*> elf_memories_;
std::unique_ptr<JitDebug> jit_debug_;
std::unique_ptr<BufferMaps> maps_;
};
diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h
index 8f7d913..cd7f2ff 100644
--- a/libunwindstack/tests/RegsFake.h
+++ b/libunwindstack/tests/RegsFake.h
@@ -56,6 +56,7 @@
void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; }
void FakeSetPc(uint64_t pc) { fake_pc_ = pc; }
void FakeSetSp(uint64_t sp) { fake_sp_ = sp; }
+ 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; }
diff --git a/libunwindstack/tests/RegsIterateTest.cpp b/libunwindstack/tests/RegsIterateTest.cpp
index 8b5b31f..9a27dbd 100644
--- a/libunwindstack/tests/RegsIterateTest.cpp
+++ b/libunwindstack/tests/RegsIterateTest.cpp
@@ -24,20 +24,19 @@
#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/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
#include <unwindstack/RegsMips.h>
#include <unwindstack/RegsMips64.h>
-
-#include "MachineArm.h"
-#include "MachineArm64.h"
-#include "MachineX86.h"
-#include "MachineX86_64.h"
-#include "MachineMips.h"
-#include "MachineMips64.h"
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
namespace unwindstack {
diff --git a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
index ef9e61c..ecd4051 100644
--- a/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
+++ b/libunwindstack/tests/RegsStepIfSignalHandlerTest.cpp
@@ -19,19 +19,18 @@
#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/RegsX86.h>
-#include <unwindstack/RegsX86_64.h>
#include <unwindstack/RegsMips.h>
#include <unwindstack/RegsMips64.h>
-
-#include "MachineArm.h"
-#include "MachineArm64.h"
-#include "MachineX86.h"
-#include "MachineX86_64.h"
-#include "MachineMips.h"
-#include "MachineMips64.h"
+#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
#include "MemoryFake.h"
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 09376ab..df262f5 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -23,24 +23,154 @@
#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/Memory.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsX86.h>
+#include <unwindstack/RegsX86_64.h>
#include <unwindstack/Unwinder.h>
-#include "MachineArm.h"
-#include "MachineArm64.h"
-#include "MachineX86.h"
-
#include "ElfTestUtils.h"
namespace unwindstack {
+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) {
+ 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());
+
+ 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());
+
+ 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);
+ regs->SetFromRaw();
+ }
+
+ 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},
+};
+
+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++) {
@@ -49,45 +179,11 @@
return str;
}
-TEST(UnwindOfflineTest, pc_straddle_arm32) {
- std::string dir(TestGetFileDirectory() + "offline/straddle_arm32/");
+TEST_F(UnwindOfflineTest, pc_straddle_arm) {
+ Init("straddle_arm/", ARCH_ARM);
- MemoryOffline* memory = new MemoryOffline;
- ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
- FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- RegsArm regs;
- uint64_t reg_value;
- ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_PC] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_SP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_LR] = reg_value;
- regs.SetFromRaw();
- fclose(fp);
-
- fp = fopen((dir + "maps.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- // The file is guaranteed to be less than 4096 bytes.
- std::vector<char> buffer(4096);
- ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
- fclose(fp);
-
- BufferMaps maps(buffer.data());
- ASSERT_TRUE(maps.Parse());
-
- ASSERT_EQ(ARCH_ARM, regs.Arch());
-
- std::shared_ptr<Memory> process_memory(memory);
-
- char* cwd = getcwd(nullptr, 0);
- ASSERT_EQ(0, chdir(dir.c_str()));
- Unwinder unwinder(128, &maps, ®s, process_memory);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- ASSERT_EQ(0, chdir(cwd));
- free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -99,43 +195,11 @@
frame_info);
}
-TEST(UnwindOfflineTest, pc_in_gnu_debugdata_arm32) {
- std::string dir(TestGetFileDirectory() + "offline/gnu_debugdata_arm32/");
+TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
+ Init("gnu_debugdata_arm/", ARCH_ARM);
- MemoryOffline* memory = new MemoryOffline;
- ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
- FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- RegsArm regs;
- uint64_t reg_value;
- ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_PC] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_SP] = reg_value;
- regs.SetFromRaw();
- fclose(fp);
-
- fp = fopen((dir + "maps.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- // The file is guaranteed to be less than 4096 bytes.
- std::vector<char> buffer(4096);
- ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
- fclose(fp);
-
- BufferMaps maps(buffer.data());
- ASSERT_TRUE(maps.Parse());
-
- ASSERT_EQ(ARCH_ARM, regs.Arch());
-
- std::shared_ptr<Memory> process_memory(memory);
-
- char* cwd = getcwd(nullptr, 0);
- ASSERT_EQ(0, chdir(dir.c_str()));
- Unwinder unwinder(128, &maps, ®s, process_memory);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- ASSERT_EQ(0, chdir(cwd));
- free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(2U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -147,47 +211,11 @@
frame_info);
}
-TEST(UnwindOfflineTest, pc_straddle_arm64) {
- std::string dir(TestGetFileDirectory() + "offline/straddle_arm64/");
+TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
+ Init("straddle_arm64/", ARCH_ARM64);
- MemoryOffline* memory = new MemoryOffline;
- ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
- FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- RegsArm64 regs;
- uint64_t reg_value;
- ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_PC] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_SP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_LR] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_R29] = reg_value;
- regs.SetFromRaw();
- fclose(fp);
-
- fp = fopen((dir + "maps.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- // The file is guaranteed to be less than 4096 bytes.
- std::vector<char> buffer(4096);
- ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
- fclose(fp);
-
- BufferMaps maps(buffer.data());
- ASSERT_TRUE(maps.Parse());
-
- ASSERT_EQ(ARCH_ARM64, regs.Arch());
-
- std::shared_ptr<Memory> process_memory(memory);
-
- char* cwd = getcwd(nullptr, 0);
- ASSERT_EQ(0, chdir(dir.c_str()));
- Unwinder unwinder(128, &maps, ®s, process_memory);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- ASSERT_EQ(0, chdir(cwd));
- free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -209,64 +237,22 @@
parts->Add(memory);
}
-TEST(UnwindOfflineTest, jit_debug_x86_32) {
- std::string dir(TestGetFileDirectory() + "offline/jit_debug_x86_32/");
+TEST_F(UnwindOfflineTest, jit_debug_x86) {
+ Init("jit_debug_x86/", ARCH_X86);
MemoryOfflineParts* memory = new MemoryOfflineParts;
- AddMemory(dir + "descriptor.data", memory);
- AddMemory(dir + "stack.data", memory);
+ 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);
+ AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+ AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
}
+ process_memory_.reset(memory);
- FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- RegsX86 regs;
- uint64_t reg_value;
- ASSERT_EQ(1, fscanf(fp, "eax: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EAX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "ebx: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EBX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "ecx: %" SCNx64 "\n", ®_value));
- regs[X86_REG_ECX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "edx: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EDX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "ebp: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EBP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "edi: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EDI] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "esi: %" SCNx64 "\n", ®_value));
- regs[X86_REG_ESI] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "esp: %" SCNx64 "\n", ®_value));
- regs[X86_REG_ESP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "eip: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EIP] = reg_value;
- regs.SetFromRaw();
- fclose(fp);
-
- fp = fopen((dir + "maps.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- // The file is guaranteed to be less than 4096 bytes.
- std::vector<char> buffer(4096);
- ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
- fclose(fp);
-
- BufferMaps maps(buffer.data());
- ASSERT_TRUE(maps.Parse());
-
- ASSERT_EQ(ARCH_X86, regs.Arch());
-
- std::shared_ptr<Memory> process_memory(memory);
-
- char* cwd = getcwd(nullptr, 0);
- ASSERT_EQ(0, chdir(dir.c_str()));
- JitDebug jit_debug(process_memory);
- Unwinder unwinder(128, &maps, ®s, process_memory);
- unwinder.SetJitDebug(&jit_debug, regs.Arch());
+ JitDebug jit_debug(process_memory_);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(&jit_debug, regs_->Arch());
unwinder.Unwind();
- ASSERT_EQ(0, chdir(cwd));
- free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(69U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -406,79 +392,23 @@
frame_info);
}
-TEST(UnwindOfflineTest, jit_debug_arm32) {
- std::string dir(TestGetFileDirectory() + "offline/jit_debug_arm32/");
+TEST_F(UnwindOfflineTest, jit_debug_arm) {
+ 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);
+ 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);
+ AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+ AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
}
+ process_memory_.reset(memory);
- FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- RegsArm regs;
- uint64_t reg_value;
- ASSERT_EQ(1, fscanf(fp, "r0: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R0] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r1: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R1] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r2: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R2] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r3: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R3] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r4: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R4] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r5: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R5] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r6: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R6] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r7: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R7] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r8: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R8] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r9: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R9] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r10: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R10] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "r11: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R11] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "ip: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_R12] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_SP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_LR] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
- regs[ARM_REG_PC] = reg_value;
- regs.SetFromRaw();
- fclose(fp);
-
- fp = fopen((dir + "maps.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- // The file is guaranteed to be less than 4096 bytes.
- std::vector<char> buffer(4096);
- ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
- fclose(fp);
-
- BufferMaps maps(buffer.data());
- ASSERT_TRUE(maps.Parse());
-
- ASSERT_EQ(ARCH_ARM, regs.Arch());
-
- std::shared_ptr<Memory> process_memory(memory);
-
- char* cwd = getcwd(nullptr, 0);
- ASSERT_EQ(0, chdir(dir.c_str()));
- JitDebug jit_debug(process_memory);
- Unwinder unwinder(128, &maps, ®s, process_memory);
- unwinder.SetJitDebug(&jit_debug, regs.Arch());
+ JitDebug jit_debug(process_memory_);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(&jit_debug, regs_->Arch());
unwinder.Unwind();
- ASSERT_EQ(0, chdir(cwd));
- free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(76U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -628,47 +558,11 @@
// 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(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
- std::string dir(TestGetFileDirectory() + "offline/bad_eh_frame_hdr_arm64/");
+TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
+ Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64);
- MemoryOffline* memory = new MemoryOffline;
- ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
- FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- RegsArm64 regs;
- uint64_t reg_value;
- ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_PC] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_SP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_LR] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", ®_value));
- regs[ARM64_REG_R29] = reg_value;
- regs.SetFromRaw();
- fclose(fp);
-
- fp = fopen((dir + "maps.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- // The file is guaranteed to be less than 4096 bytes.
- std::vector<char> buffer(4096);
- ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
- fclose(fp);
-
- BufferMaps maps(buffer.data());
- ASSERT_TRUE(maps.Parse());
-
- ASSERT_EQ(ARCH_ARM64, regs.Arch());
-
- std::shared_ptr<Memory> process_memory(memory);
-
- char* cwd = getcwd(nullptr, 0);
- ASSERT_EQ(0, chdir(dir.c_str()));
- Unwinder unwinder(128, &maps, ®s, process_memory);
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- ASSERT_EQ(0, chdir(cwd));
- free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -683,59 +577,11 @@
// 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(UnwindOfflineTest, debug_frame_first_x86) {
- std::string dir(TestGetFileDirectory() + "offline/debug_frame_first_x86/");
+TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
+ Init("debug_frame_first_x86/", ARCH_X86);
- MemoryOffline* memory = new MemoryOffline;
- ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
-
- FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- RegsX86 regs;
- uint64_t reg_value;
- ASSERT_EQ(1, fscanf(fp, "eax: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EAX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "ebx: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EBX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "ecx: %" SCNx64 "\n", ®_value));
- regs[X86_REG_ECX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "edx: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EDX] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "ebp: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EBP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "edi: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EDI] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "esi: %" SCNx64 "\n", ®_value));
- regs[X86_REG_ESI] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "esp: %" SCNx64 "\n", ®_value));
- regs[X86_REG_ESP] = reg_value;
- ASSERT_EQ(1, fscanf(fp, "eip: %" SCNx64 "\n", ®_value));
- regs[X86_REG_EIP] = reg_value;
- regs.SetFromRaw();
- fclose(fp);
-
- fp = fopen((dir + "maps.txt").c_str(), "r");
- ASSERT_TRUE(fp != nullptr);
- // The file is guaranteed to be less than 4096 bytes.
- std::vector<char> buffer(4096);
- ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
- fclose(fp);
-
- BufferMaps maps(buffer.data());
- ASSERT_TRUE(maps.Parse());
-
- ASSERT_EQ(ARCH_X86, regs.Arch());
-
- std::shared_ptr<Memory> process_memory(memory);
-
- char* cwd = getcwd(nullptr, 0);
- ASSERT_EQ(0, chdir(dir.c_str()));
- JitDebug jit_debug(process_memory);
- Unwinder unwinder(128, &maps, ®s, process_memory);
- unwinder.SetJitDebug(&jit_debug, regs.Arch());
+ Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
- ASSERT_EQ(0, chdir(cwd));
- free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(5U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
@@ -748,4 +594,22 @@
frame_info);
}
+// Make sure that a pc that is at the beginning of an fde unwinds correctly.
+TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
+ 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);
+}
+
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp
index 45cf907..7fbae4c 100644
--- a/libunwindstack/tests/UnwinderTest.cpp
+++ b/libunwindstack/tests/UnwinderTest.cpp
@@ -98,6 +98,26 @@
info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");
maps_.FakeAddMapInfo(info);
+ info = new MapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
+ info->load_bias = 0;
+ maps_.FakeAddMapInfo(info);
+
+ info = new MapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/fake/fake_load_bias.so");
+ elf = new ElfFake(new MemoryFake);
+ info->elf.reset(elf);
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ elf->FakeSetLoadBias(0x5000);
+ maps_.FakeAddMapInfo(info);
+
+ info = new MapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
+ "/fake/fake_offset.oat");
+ elf = new ElfFake(new MemoryFake);
+ info->elf.reset(elf);
+ elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
+ info->elf_offset = 0x8000;
+ maps_.FakeAddMapInfo(info);
+
process_memory_.reset(new MemoryFake);
}
@@ -176,6 +196,62 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+TEST_F(UnwinderTest, non_zero_load_bias) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+
+ regs_.FakeSetPc(0xa5500);
+ regs_.FakeSetSp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ 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_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_.FakeSetPc(0xa7500);
+ regs_.FakeSetSp(0x10000);
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ 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_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));
@@ -666,6 +742,146 @@
EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags);
}
+TEST_F(UnwinderTest, dex_pc_in_map) {
+ ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
+ regs_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ regs_.FakeSetDexPc(0xa3400);
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ 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_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_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_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ regs_.FakeSetDexPc(0x50000);
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ 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_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_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_.FakeSetPc(0x1000);
+ regs_.FakeSetSp(0x10000);
+ regs_.FakeSetDexPc(0xa3400);
+ ElfInterfaceFake::FakePushStepData(StepData(0x33402, 0x10010, false));
+ ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));
+
+ Unwinder unwinder(64, &maps_, ®s_, process_memory_);
+ unwinder.Unwind();
+ EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
+
+ 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_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_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_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);
+}
+
// Verify format frame code.
TEST_F(UnwinderTest, format_frame_static) {
FrameData frame;
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
new file mode 100644
index 0000000..46b6f45
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/libc.so
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
new file mode 100644
index 0000000..ac2e564
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/maps.txt
@@ -0,0 +1,2 @@
+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
new file mode 100644
index 0000000..38af274
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/regs.txt
@@ -0,0 +1,11 @@
+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
new file mode 100644
index 0000000..cc7882b
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/stack.data
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
new file mode 100644
index 0000000..ab0ef8f
--- /dev/null
+++ b/libunwindstack/tests/files/offline/eh_frame_hdr_begin_x86_64/unwind_test64
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/libandroid_runtime.so b/libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/libandroid_runtime.so
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/libandroid_runtime.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/maps.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/maps.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/regs.txt b/libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/regs.txt
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/gnu_debugdata_arm32/stack.data b/libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/gnu_debugdata_arm32/stack.data
rename to libunwindstack/tests/files/offline/gnu_debugdata_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/137-cfi.odex
rename to libunwindstack/tests/files/offline/jit_debug_arm/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/dalvikvm32
rename to libunwindstack/tests/files/offline/jit_debug_arm/dalvikvm32
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/descriptor1.data b/libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/descriptor1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/descriptor1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry0.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry1.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry2.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry3.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry4.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry5.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/entry6.data b/libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/entry6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit0.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit1.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit2.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit3.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit4.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit5.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/jit6.data b/libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/jit6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libart.so b/libunwindstack/tests/files/offline/jit_debug_arm/libart.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libart.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libart.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libartd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libartd.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libartd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libarttestd.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/libc.so b/libunwindstack/tests/files/offline/jit_debug_arm/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/libc.so
rename to libunwindstack/tests/files/offline/jit_debug_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/maps.txt b/libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/regs.txt b/libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_arm32/stack.data b/libunwindstack/tests/files/offline/jit_debug_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_arm32/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/137-cfi.odex b/libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/137-cfi.odex
rename to libunwindstack/tests/files/offline/jit_debug_x86/137-cfi.odex
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/dalvikvm32 b/libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/dalvikvm32
rename to libunwindstack/tests/files/offline/jit_debug_x86/dalvikvm32
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/descriptor.data b/libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/descriptor.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/descriptor.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry0.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry1.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry2.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry3.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry4.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry5.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/entry6.data b/libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/entry6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/entry6.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit0.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit0.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit0.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit1.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit1.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit1.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit2.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit2.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit2.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit3.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit3.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit3.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit4.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit4.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit4.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit5.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit5.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit5.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/jit6.data b/libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/jit6.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/jit6.data
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
new file mode 100644
index 0000000..92ed991
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libartd.so
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
new file mode 100644
index 0000000..5efae02
--- /dev/null
+++ b/libunwindstack/tests/files/offline/jit_debug_x86/libarttestd.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so b/libunwindstack/tests/files/offline/jit_debug_x86/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/libc.so
rename to libunwindstack/tests/files/offline/jit_debug_x86/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/maps.txt b/libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/maps.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/maps.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/regs.txt b/libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/regs.txt
rename to libunwindstack/tests/files/offline/jit_debug_x86/regs.txt
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/stack.data b/libunwindstack/tests/files/offline/jit_debug_x86/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/jit_debug_x86_32/stack.data
rename to libunwindstack/tests/files/offline/jit_debug_x86/stack.data
Binary files differ
diff --git a/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so b/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
deleted file mode 100644
index e72e673..0000000
--- a/libunwindstack/tests/files/offline/jit_debug_x86_32/libarttestd.so
+++ /dev/null
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libbase.so b/libunwindstack/tests/files/offline/straddle_arm/libbase.so
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/libbase.so
rename to libunwindstack/tests/files/offline/straddle_arm/libbase.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/libc.so b/libunwindstack/tests/files/offline/straddle_arm/libc.so
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/libc.so
rename to libunwindstack/tests/files/offline/straddle_arm/libc.so
Binary files differ
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/maps.txt b/libunwindstack/tests/files/offline/straddle_arm/maps.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/maps.txt
rename to libunwindstack/tests/files/offline/straddle_arm/maps.txt
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/regs.txt b/libunwindstack/tests/files/offline/straddle_arm/regs.txt
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/regs.txt
rename to libunwindstack/tests/files/offline/straddle_arm/regs.txt
diff --git a/libunwindstack/tests/files/offline/straddle_arm32/stack.data b/libunwindstack/tests/files/offline/straddle_arm/stack.data
similarity index 100%
rename from libunwindstack/tests/files/offline/straddle_arm32/stack.data
rename to libunwindstack/tests/files/offline/straddle_arm/stack.data
Binary files differ
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index 07e48af..22ca7bf 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
@@ -91,8 +92,13 @@
auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
unwindstack::Unwinder unwinder(128, &remote_maps, regs, process_memory);
+
unwindstack::JitDebug jit_debug(process_memory);
unwinder.SetJitDebug(&jit_debug, regs->Arch());
+
+ unwindstack::DexFiles dex_files(process_memory);
+ unwinder.SetDexFiles(&dex_files, regs->Arch());
+
unwinder.Unwind();
// Print the frames.
diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp
new file mode 100644
index 0000000..4d89087
--- /dev/null
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -0,0 +1,237 @@
+/*
+ * 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 "DwarfOp.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) {
+ 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)) {
+ 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_UNDEFINED:
+ printf("undefine\n");
+ break;
+
+ case DWARF_LOCATION_INVALID:
+ printf("INVALID\n");
+ break;
+ }
+ }
+}
+
+int GetInfo(const char* file, uint64_t pc) {
+ MemoryFileAtOffset* memory = new MemoryFileAtOffset;
+ if (!memory->Init(file, 0)) {
+ // Initializatation failed.
+ printf("Failed to init\n");
+ return 1;
+ }
+
+ Elf elf(memory);
+ if (!elf.Init(true) || !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;
+ }
+
+ printf("PC 0x%" PRIx64 ":\n", pc);
+
+ DwarfSection* section = interface->eh_frame();
+ if (section != nullptr) {
+ printf("\neh_frame:\n");
+ PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
+ } else {
+ printf("\nno eh_frame information\n");
+ }
+
+ section = interface->debug_frame();
+ if (section != nullptr) {
+ printf("\ndebug_frame:\n");
+ PrintRegInformation(section, memory, pc - load_bias, elf.class_type());
+ 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());
+ 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());
+ 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) {
+ printf("Usage: unwind_reg_info ELF_FILE PC\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");
+ 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;
+ }
+
+ return unwindstack::GetInfo(argv[1], pc);
+}
diff --git a/libusbhost/usbhost.c b/libusbhost/usbhost.c
index fa0191b..cb8d430 100644
--- a/libusbhost/usbhost.c
+++ b/libusbhost/usbhost.c
@@ -64,10 +64,6 @@
// Some devices fail to send string descriptors if we attempt reading > 255 bytes
#define MAX_STRING_DESCRIPTOR_LENGTH 255
-// From drivers/usb/core/devio.c
-// I don't know why this isn't in a kernel header
-#define MAX_USBFS_BUFFER_SIZE 16384
-
#define MAX_USBFS_WD_COUNT 10
struct usb_host_context {
@@ -664,10 +660,6 @@
{
struct usbdevfs_bulktransfer ctrl;
- // need to limit request size to avoid EINVAL
- if (length > MAX_USBFS_BUFFER_SIZE)
- length = MAX_USBFS_BUFFER_SIZE;
-
memset(&ctrl, 0, sizeof(ctrl));
ctrl.ep = endpoint;
ctrl.len = length;
@@ -727,11 +719,7 @@
urb->status = -1;
urb->buffer = req->buffer;
- // need to limit request size to avoid EINVAL
- if (req->buffer_length > MAX_USBFS_BUFFER_SIZE)
- urb->buffer_length = MAX_USBFS_BUFFER_SIZE;
- else
- urb->buffer_length = req->buffer_length;
+ urb->buffer_length = req->buffer_length;
do {
res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb);
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index b486a17..15471e0 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -615,11 +615,11 @@
pid_remove(pid);
if (r) {
- ALOGE("kill(%d): errno=%d", procp->pid, errno);
+ ALOGE("kill(%d): errno=%d", pid, errno);
return -1;
- } else {
- return tasksize;
}
+
+ return tasksize;
}
/*
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index d8163ab..feb100e 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -145,13 +145,21 @@
# $(1): Input source file (ld.config.txt)
# $(2): Output built module
# $(3): VNDK version suffix
+# $(4): true if libz must be included in llndk not in vndk-sp
define update_and_install_ld_config
+# If $(4) is true, move libz to llndk from vndk-sp.
+$(if $(filter true,$(4)),\
+ $(eval llndk_libraries_list := $(LLNDK_LIBRARIES) libz) \
+ $(eval vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES))),\
+ $(eval llndk_libraries_list := $(LLNDK_LIBRARIES)) \
+ $(eval vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES)))
+
llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
+ $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list))))
private_llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(filter $(VNDK_PRIVATE_LIBRARIES),$(LLNDK_LIBRARIES))))
+ $(filter $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list))))
vndk_sameprocess_libraries := $(call normalize-path-list,$(addsuffix .so,\
- $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_SAMEPROCESS_LIBRARIES))))
+ $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(vndksp_libraries_list))))
vndk_core_libraries := $(call normalize-path-list,$(addsuffix .so,\
$(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_CORE_LIBRARIES))))
sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\
@@ -180,6 +188,8 @@
$$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $$@
$$(hide) sed -i -e 's?%VNDK_VER%?$$(PRIVATE_VNDK_VERSION)?g' $$@
+llndk_libraries_list :=
+vndksp_libraries_list :=
llndk_libraries :=
private_llndk_libraries :=
vndk_sameprocess_libraries :=
@@ -192,11 +202,12 @@
# ld.config.txt
#
# For VNDK enforced devices that have defined BOARD_VNDK_VERSION, use
-# "ld.config.txt.in" as a source file. This configuration includes strict VNDK
+# "ld.config.txt" as a source file. This configuration includes strict VNDK
# run-time restrictions for vendor process.
# Other treblized devices, that have not defined BOARD_VNDK_VERSION or that
-# have set BOARD_VNDK_RUNTIME_DISABLE to true, use "ld.config.txt" as a source
-# file. This configuration does not have strict VNDK run-time restrictions.
+# have set BOARD_VNDK_RUNTIME_DISABLE to true, use "ld.config.vndk_lite.txt"
+# as a source file. This configuration does not have strict VNDK run-time
+# restrictions.
# If the device is not treblized, use "ld.config.legacy.txt" for legacy
# namespace configuration.
include $(CLEAR_VARS)
@@ -216,7 +227,7 @@
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.txt.in,\
+ $(LOCAL_PATH)/etc/ld.config.txt,\
$(LOCAL_BUILT_MODULE),\
$(PLATFORM_VNDK_VERSION)))
@@ -225,9 +236,10 @@
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.txt,\
+ $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
$(LOCAL_BUILT_MODULE),\
- $(if $(BOARD_VNDK_VERSION),$(PLATFORM_VNDK_VERSION))))
+ $(if $(BOARD_VNDK_VERSION),$(PLATFORM_VNDK_VERSION)),\
+ true))
else
# for legacy non-treblized devices
@@ -244,9 +256,9 @@
#
# This file is a temporary configuration file only for GSI. Originally GSI has
# BOARD_VNDK_VERSION defined and has strict VNDK enforcing rule based on
-# "ld.config.txt.in". However for the devices, that have not defined
+# "ld.config.txt". However for the devices, that have not defined
# BOARD_VNDK_VERSION, GSI provides this configuration file which is based on
-# "ld.config.txt".
+# "ld.config.vndk_lite.txt".
# Do not install this file for the devices other than GSI.
include $(CLEAR_VARS)
LOCAL_MODULE := ld.config.noenforce.txt
@@ -255,9 +267,10 @@
LOCAL_MODULE_STEM := $(LOCAL_MODULE)
include $(BUILD_SYSTEM)/base_rules.mk
$(eval $(call update_and_install_ld_config,\
- $(LOCAL_PATH)/etc/ld.config.txt,\
+ $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\
$(LOCAL_BUILT_MODULE),\
- $(PLATFORM_VNDK_VERSION)))
+ $(PLATFORM_VNDK_VERSION),\
+ true))
#######################################
# llndk.libraries.txt
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index 5d97a73..c8d87c8 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -30,21 +30,55 @@
###############################################################################
# "default" namespace
#
-# Framework-side code runs in this namespace. However, libs from other
-# partitions are also allowed temporarily.
+# Framework-side code runs in this namespace. Libs from /vendor partition
+# can't be loaded in this namespace.
###############################################################################
-namespace.default.isolated = false
+namespace.default.isolated = true
-namespace.default.search.paths = /system/${LIB}
-namespace.default.search.paths += /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
+namespace.default.search.paths = /system/${LIB}
+
+# We can't have entire /system/${LIB} as permitted paths because doing so
+# makes it possible to load libs in /system/${LIB}/vndk* directories by
+# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
+# VNDK libs are built with previous versions of Android and thus must not be
+# loaded into this namespace where libs built with the current version of
+# Android are loaded. Mixing the two types of libs in the same namespace can
+# cause unexpected problem.
+namespace.default.permitted.paths = /system/${LIB}/drm
+namespace.default.permitted.paths += /system/${LIB}/extractors
+namespace.default.permitted.paths += /system/${LIB}/hw
+# These are where odex files are located. libart has to be able to dlopen the files
+namespace.default.permitted.paths += /system/framework
+namespace.default.permitted.paths += /system/app
+namespace.default.permitted.paths += /system/priv-app
+namespace.default.permitted.paths += /vendor/framework
+namespace.default.permitted.paths += /vendor/app
+namespace.default.permitted.paths += /vendor/priv-app
+namespace.default.permitted.paths += /oem/app
+namespace.default.permitted.paths += /product/framework
+namespace.default.permitted.paths += /product/app
+namespace.default.permitted.paths += /product/priv-app
+namespace.default.permitted.paths += /data
+namespace.default.permitted.paths += /mnt/expand
namespace.default.asan.search.paths = /data/asan/system/${LIB}
namespace.default.asan.search.paths += /system/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths += /vendor/${LIB}
+
+namespace.default.asan.permitted.paths = /data
+namespace.default.asan.permitted.paths += /system/${LIB}/drm
+namespace.default.asan.permitted.paths += /system/${LIB}/extractors
+namespace.default.asan.permitted.paths += /system/${LIB}/hw
+namespace.default.asan.permitted.paths += /system/framework
+namespace.default.asan.permitted.paths += /system/app
+namespace.default.asan.permitted.paths += /system/priv-app
+namespace.default.asan.permitted.paths += /vendor/framework
+namespace.default.asan.permitted.paths += /vendor/app
+namespace.default.asan.permitted.paths += /vendor/priv-app
+namespace.default.asan.permitted.paths += /oem/app
+namespace.default.asan.permitted.paths += /product/framework
+namespace.default.asan.permitted.paths += /product/app
+namespace.default.asan.permitted.paths += /product/priv-app
+namespace.default.asan.permitted.paths += /mnt/expand
###############################################################################
# "sphal" namespace
@@ -82,35 +116,10 @@
# libs listed here can be used.
namespace.sphal.links = default,vndk,rs
-# WARNING: only NDK libs can be listed here.
-namespace.sphal.link.default.shared_libs = libc.so
-namespace.sphal.link.default.shared_libs += libEGL.so
-namespace.sphal.link.default.shared_libs += libGLESv1_CM.so
-namespace.sphal.link.default.shared_libs += libGLESv2.so
-namespace.sphal.link.default.shared_libs += libdl.so
-namespace.sphal.link.default.shared_libs += liblog.so
-namespace.sphal.link.default.shared_libs += libm.so
-namespace.sphal.link.default.shared_libs += libnativewindow.so
-namespace.sphal.link.default.shared_libs += libstdc++.so
-namespace.sphal.link.default.shared_libs += libsync.so
-namespace.sphal.link.default.shared_libs += libvndksupport.so
-namespace.sphal.link.default.shared_libs += libz.so
+namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-# WARNING: only VNDK-SP libs can be listed here. DO NOT EDIT this line.
-namespace.sphal.link.vndk.shared_libs = android.hardware.renderscript@1.0.so
-namespace.sphal.link.vndk.shared_libs += android.hardware.graphics.common@1.0.so
-namespace.sphal.link.vndk.shared_libs += android.hardware.graphics.mapper@2.0.so
-namespace.sphal.link.vndk.shared_libs += android.hidl.memory@1.0.so
-namespace.sphal.link.vndk.shared_libs += libbase.so
-namespace.sphal.link.vndk.shared_libs += libc++.so
-namespace.sphal.link.vndk.shared_libs += libcutils.so
-namespace.sphal.link.vndk.shared_libs += libhardware.so
-namespace.sphal.link.vndk.shared_libs += libhidlbase.so
-namespace.sphal.link.vndk.shared_libs += libhidlmemory.so
-namespace.sphal.link.vndk.shared_libs += libhidltransport.so
-namespace.sphal.link.vndk.shared_libs += libhwbinder.so
-namespace.sphal.link.vndk.shared_libs += libion.so
-namespace.sphal.link.vndk.shared_libs += libutils.so
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
# Renderscript gets separate namespace
namespace.sphal.link.rs.shared_libs = libRS_internal.so
@@ -155,38 +164,13 @@
namespace.rs.links = default,vndk
-namespace.rs.link.default.shared_libs = libc.so
-namespace.rs.link.default.shared_libs += libEGL.so
-namespace.rs.link.default.shared_libs += libGLESv1_CM.so
-namespace.rs.link.default.shared_libs += libGLESv2.so
-namespace.rs.link.default.shared_libs += libdl.so
-namespace.rs.link.default.shared_libs += liblog.so
-namespace.rs.link.default.shared_libs += libm.so
-namespace.rs.link.default.shared_libs += libnativewindow.so
-namespace.rs.link.default.shared_libs += libstdc++.so
-namespace.rs.link.default.shared_libs += libsync.so
-namespace.rs.link.default.shared_libs += libvndksupport.so
-namespace.rs.link.default.shared_libs += libz.so
-# These two libs are private LLNDK libs but are exceptionally visible
-# in this 'rs' namespace because RenderScript framework libraries
-# which are loaded into this namespace are using them.
-namespace.rs.link.default.shared_libs += libft2.so
-namespace.rs.link.default.shared_libs += libmediandk.so
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-namespace.rs.link.vndk.shared_libs = android.hardware.renderscript@1.0.so
-namespace.rs.link.vndk.shared_libs += android.hardware.graphics.common@1.0.so
-namespace.rs.link.vndk.shared_libs += android.hardware.graphics.mapper@2.0.so
-namespace.rs.link.vndk.shared_libs += android.hidl.memory@1.0.so
-namespace.rs.link.vndk.shared_libs += libbase.so
-namespace.rs.link.vndk.shared_libs += libc++.so
-namespace.rs.link.vndk.shared_libs += libcutils.so
-namespace.rs.link.vndk.shared_libs += libhardware.so
-namespace.rs.link.vndk.shared_libs += libhidlbase.so
-namespace.rs.link.vndk.shared_libs += libhidlmemory.so
-namespace.rs.link.vndk.shared_libs += libhidltransport.so
-namespace.rs.link.vndk.shared_libs += libhwbinder.so
-namespace.rs.link.vndk.shared_libs += libion.so
-namespace.rs.link.vndk.shared_libs += libutils.so
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
###############################################################################
# "vndk" namespace
@@ -204,6 +188,8 @@
namespace.vndk.permitted.paths += /odm/${LIB}/egl
namespace.vndk.permitted.paths += /vendor/${LIB}/hw
namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
@@ -221,21 +207,15 @@
namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
namespace.vndk.asan.permitted.paths += /vendor/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
+namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
# When these NDK libs are required inside this namespace, then it is redirected
# to the default namespace. This is possible since their ABI is stable across
# Android releases.
namespace.vndk.links = default
-namespace.vndk.link.default.shared_libs = android.hidl.memory@1.0-impl.so
-namespace.vndk.link.default.shared_libs += libEGL.so
-namespace.vndk.link.default.shared_libs += libc.so
-namespace.vndk.link.default.shared_libs += libdl.so
-namespace.vndk.link.default.shared_libs += liblog.so
-namespace.vndk.link.default.shared_libs += libm.so
-namespace.vndk.link.default.shared_libs += libnativewindow.so
-namespace.vndk.link.default.shared_libs += libstdc++.so
-namespace.vndk.link.default.shared_libs += libsync.so
-namespace.vndk.link.default.shared_libs += libvndksupport.so
-namespace.vndk.link.default.shared_libs += libz.so
+namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
###############################################################################
# Namespace config for vendor processes. In O, no restriction is enforced for
@@ -244,35 +224,88 @@
# (LL-NDK only) access.
###############################################################################
[vendor]
-namespace.default.isolated = false
+additional.namespaces = system,vndk
+
+###############################################################################
+# "default" namespace
+#
+# This is the default linker namespace for a vendor process (a process started
+# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
+# are loaded directly into this namespace. However, other libs under the system
+# partition (VNDK and LLNDK libraries) are not loaded here but from the
+# separate namespace 'system'. The delegation to the system namespace is done
+# via the 'namespace.default.link.system.shared_libs' property below.
+###############################################################################
+namespace.default.isolated = true
+namespace.default.visible = true
namespace.default.search.paths = /odm/${LIB}
-namespace.default.search.paths += /odm/${LIB}/vndk
-namespace.default.search.paths += /odm/${LIB}/vndk-sp
namespace.default.search.paths += /vendor/${LIB}
-namespace.default.search.paths += /vendor/${LIB}/vndk
-namespace.default.search.paths += /vendor/${LIB}/vndk-sp
-# Access to system libraries are allowed
-namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
-namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.search.paths += /system/${LIB}
+namespace.default.permitted.paths = /odm
+namespace.default.permitted.paths += /vendor
namespace.default.asan.search.paths = /data/asan/odm/${LIB}
namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
-namespace.default.asan.search.paths += /odm/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /odm/${LIB}/vndk-sp
namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
namespace.default.asan.search.paths += /vendor/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /vendor/${LIB}/vndk
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
-namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.default.asan.search.paths += /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /system/${LIB}
+
+namespace.default.asan.permitted.paths = /data/asan/odm
+namespace.default.asan.permitted.paths += /odm
+namespace.default.asan.permitted.paths += /data/asan/vendor
+namespace.default.asan.permitted.paths += /vendor
+
+namespace.default.links = system,vndk
+namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is where VNDK and VNDK-SP libraries are loaded for
+# a vendor process.
+###############################################################################
+namespace.vndk.isolated = false
+
+namespace.vndk.search.paths = /odm/${LIB}/vndk
+namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.search.paths += /vendor/${LIB}/vndk
+namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
+
+namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the system namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = system,default
+namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
+namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.vndk.link.default.allow_all_shared_libs = true
+
+###############################################################################
+# "system" namespace
+#
+# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
+# a vendor process.
+###############################################################################
+namespace.system.isolated = false
+
+namespace.system.search.paths = /system/${LIB}
+
+namespace.system.asan.search.paths = /data/asan/system/${LIB}
+namespace.system.asan.search.paths += /system/${LIB}
diff --git a/rootdir/etc/ld.config.txt.in b/rootdir/etc/ld.config.txt.in
deleted file mode 100644
index c8d87c8..0000000
--- a/rootdir/etc/ld.config.txt.in
+++ /dev/null
@@ -1,311 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Bionic loader config file.
-#
-
-# Don't change the order here. The first pattern that matches with the
-# absolute path of an executable is selected.
-dir.system = /system/bin/
-dir.system = /system/xbin/
-
-dir.vendor = /odm/bin/
-dir.vendor = /vendor/bin/
-dir.vendor = /data/nativetest/odm
-dir.vendor = /data/nativetest64/odm
-dir.vendor = /data/benchmarktest/odm
-dir.vendor = /data/benchmarktest64/odm
-dir.vendor = /data/nativetest/vendor
-dir.vendor = /data/nativetest64/vendor
-dir.vendor = /data/benchmarktest/vendor
-dir.vendor = /data/benchmarktest64/vendor
-
-dir.system = /data/nativetest
-dir.system = /data/nativetest64
-dir.system = /data/benchmarktest
-dir.system = /data/benchmarktest64
-
-[system]
-additional.namespaces = sphal,vndk,rs
-
-###############################################################################
-# "default" namespace
-#
-# Framework-side code runs in this namespace. Libs from /vendor partition
-# can't be loaded in this namespace.
-###############################################################################
-namespace.default.isolated = true
-
-namespace.default.search.paths = /system/${LIB}
-
-# We can't have entire /system/${LIB} as permitted paths because doing so
-# makes it possible to load libs in /system/${LIB}/vndk* directories by
-# their absolute paths (e.g. dlopen("/system/lib/vndk/libbase.so");).
-# VNDK libs are built with previous versions of Android and thus must not be
-# loaded into this namespace where libs built with the current version of
-# Android are loaded. Mixing the two types of libs in the same namespace can
-# cause unexpected problem.
-namespace.default.permitted.paths = /system/${LIB}/drm
-namespace.default.permitted.paths += /system/${LIB}/extractors
-namespace.default.permitted.paths += /system/${LIB}/hw
-# These are where odex files are located. libart has to be able to dlopen the files
-namespace.default.permitted.paths += /system/framework
-namespace.default.permitted.paths += /system/app
-namespace.default.permitted.paths += /system/priv-app
-namespace.default.permitted.paths += /vendor/framework
-namespace.default.permitted.paths += /vendor/app
-namespace.default.permitted.paths += /vendor/priv-app
-namespace.default.permitted.paths += /oem/app
-namespace.default.permitted.paths += /product/framework
-namespace.default.permitted.paths += /product/app
-namespace.default.permitted.paths += /product/priv-app
-namespace.default.permitted.paths += /data
-namespace.default.permitted.paths += /mnt/expand
-
-namespace.default.asan.search.paths = /data/asan/system/${LIB}
-namespace.default.asan.search.paths += /system/${LIB}
-
-namespace.default.asan.permitted.paths = /data
-namespace.default.asan.permitted.paths += /system/${LIB}/drm
-namespace.default.asan.permitted.paths += /system/${LIB}/extractors
-namespace.default.asan.permitted.paths += /system/${LIB}/hw
-namespace.default.asan.permitted.paths += /system/framework
-namespace.default.asan.permitted.paths += /system/app
-namespace.default.asan.permitted.paths += /system/priv-app
-namespace.default.asan.permitted.paths += /vendor/framework
-namespace.default.asan.permitted.paths += /vendor/app
-namespace.default.asan.permitted.paths += /vendor/priv-app
-namespace.default.asan.permitted.paths += /oem/app
-namespace.default.asan.permitted.paths += /product/framework
-namespace.default.asan.permitted.paths += /product/app
-namespace.default.asan.permitted.paths += /product/priv-app
-namespace.default.asan.permitted.paths += /mnt/expand
-
-###############################################################################
-# "sphal" namespace
-#
-# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
-# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
-# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
-#
-# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
-# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
-# that they should be searched and loaded from this namespace.
-#
-# Note that there is no link from the default namespace to this namespace.
-###############################################################################
-namespace.sphal.isolated = true
-namespace.sphal.visible = true
-
-namespace.sphal.search.paths = /odm/${LIB}
-namespace.sphal.search.paths += /vendor/${LIB}
-
-namespace.sphal.permitted.paths = /odm/${LIB}
-namespace.sphal.permitted.paths += /vendor/${LIB}
-
-namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}
-namespace.sphal.asan.search.paths += /odm/${LIB}
-namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.search.paths += /vendor/${LIB}
-
-namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}
-namespace.sphal.asan.permitted.paths += /odm/${LIB}
-namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.sphal.asan.permitted.paths += /vendor/${LIB}
-
-# Once in this namespace, access to libraries in /system/lib is restricted. Only
-# libs listed here can be used.
-namespace.sphal.links = default,vndk,rs
-
-namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-# Renderscript gets separate namespace
-namespace.sphal.link.rs.shared_libs = libRS_internal.so
-
-###############################################################################
-# "rs" namespace
-#
-# This namespace is exclusively for Renderscript internal libraries.
-# This namespace has slightly looser restriction than the vndk namespace because
-# of the genuine characteristics of Renderscript; /data is in the permitted path
-# to load the compiled *.so file and libmediandk.so can be used here.
-###############################################################################
-namespace.rs.isolated = true
-namespace.rs.visible = true
-
-namespace.rs.search.paths = /odm/${LIB}/vndk-sp
-namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.search.paths += /odm/${LIB}
-namespace.rs.search.paths += /vendor/${LIB}
-
-namespace.rs.permitted.paths = /odm/${LIB}
-namespace.rs.permitted.paths += /vendor/${LIB}
-namespace.rs.permitted.paths += /data
-
-namespace.rs.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
-namespace.rs.asan.search.paths += /odm/${LIB}
-namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.search.paths += /vendor/${LIB}
-
-namespace.rs.asan.permitted.paths = /data/asan/odm/${LIB}
-namespace.rs.asan.permitted.paths += /odm/${LIB}
-namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
-namespace.rs.asan.permitted.paths += /vendor/${LIB}
-namespace.rs.asan.permitted.paths += /data
-
-namespace.rs.links = default,vndk
-
-namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
-# namespace because RS framework libs are using them.
-namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
-
-namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is exclusively for vndk-sp libs.
-###############################################################################
-namespace.vndk.isolated = true
-namespace.vndk.visible = true
-
-namespace.vndk.search.paths = /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.permitted.paths = /odm/${LIB}/hw
-namespace.vndk.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.permitted.paths += /vendor/${LIB}/egl
-# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
-namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-
-namespace.vndk.asan.permitted.paths = /data/asan/odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /odm/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /odm/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /vendor/${LIB}/hw
-namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
-namespace.vndk.asan.permitted.paths += /vendor/${LIB}/egl
-
-namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
-namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the default namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = default
-namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
-namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-###############################################################################
-# Namespace config for vendor processes. In O, no restriction is enforced for
-# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
-# the default namespace. 'system' namespace will be added to give limited
-# (LL-NDK only) access.
-###############################################################################
-[vendor]
-additional.namespaces = system,vndk
-
-###############################################################################
-# "default" namespace
-#
-# This is the default linker namespace for a vendor process (a process started
-# from /vendor/bin/*). The main executable and the libs under /vendor/lib[64]
-# are loaded directly into this namespace. However, other libs under the system
-# partition (VNDK and LLNDK libraries) are not loaded here but from the
-# separate namespace 'system'. The delegation to the system namespace is done
-# via the 'namespace.default.link.system.shared_libs' property below.
-###############################################################################
-namespace.default.isolated = true
-namespace.default.visible = true
-
-namespace.default.search.paths = /odm/${LIB}
-namespace.default.search.paths += /vendor/${LIB}
-
-namespace.default.permitted.paths = /odm
-namespace.default.permitted.paths += /vendor
-
-namespace.default.asan.search.paths = /data/asan/odm/${LIB}
-namespace.default.asan.search.paths += /odm/${LIB}
-namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
-namespace.default.asan.search.paths += /vendor/${LIB}
-
-namespace.default.asan.permitted.paths = /data/asan/odm
-namespace.default.asan.permitted.paths += /odm
-namespace.default.asan.permitted.paths += /data/asan/vendor
-namespace.default.asan.permitted.paths += /vendor
-
-namespace.default.links = system,vndk
-namespace.default.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.default.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
-namespace.default.link.vndk.shared_libs += %VNDK_CORE_LIBRARIES%
-
-###############################################################################
-# "vndk" namespace
-#
-# This namespace is where VNDK and VNDK-SP libraries are loaded for
-# a vendor process.
-###############################################################################
-namespace.vndk.isolated = false
-
-namespace.vndk.search.paths = /odm/${LIB}/vndk
-namespace.vndk.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk
-namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
-namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
-namespace.vndk.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
-
-# When these NDK libs are required inside this namespace, then it is redirected
-# to the system namespace. This is possible since their ABI is stable across
-# Android releases.
-namespace.vndk.links = system,default
-namespace.vndk.link.system.shared_libs = %LLNDK_LIBRARIES%
-namespace.vndk.link.system.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-
-namespace.vndk.link.default.allow_all_shared_libs = true
-
-###############################################################################
-# "system" namespace
-#
-# This namespace is where system libs (VNDK and LLNDK libs) are loaded for
-# a vendor process.
-###############################################################################
-namespace.system.isolated = false
-
-namespace.system.search.paths = /system/${LIB}
-
-namespace.system.asan.search.paths = /data/asan/system/${LIB}
-namespace.system.asan.search.paths += /system/${LIB}
diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt
new file mode 100644
index 0000000..5256cb1
--- /dev/null
+++ b/rootdir/etc/ld.config.vndk_lite.txt
@@ -0,0 +1,224 @@
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Bionic loader config file.
+#
+
+# Don't change the order here. The first pattern that matches with the
+# absolute path of an executable is selected.
+dir.system = /system/bin/
+dir.system = /system/xbin/
+
+dir.vendor = /odm/bin/
+dir.vendor = /vendor/bin/
+dir.vendor = /data/nativetest/odm
+dir.vendor = /data/nativetest64/odm
+dir.vendor = /data/benchmarktest/odm
+dir.vendor = /data/benchmarktest64/odm
+dir.vendor = /data/nativetest/vendor
+dir.vendor = /data/nativetest64/vendor
+dir.vendor = /data/benchmarktest/vendor
+dir.vendor = /data/benchmarktest64/vendor
+
+dir.system = /data/nativetest
+dir.system = /data/nativetest64
+dir.system = /data/benchmarktest
+dir.system = /data/benchmarktest64
+
+[system]
+additional.namespaces = sphal,vndk,rs
+
+###############################################################################
+# "default" namespace
+#
+# Framework-side code runs in this namespace. However, libs from other
+# partitions are also allowed temporarily.
+###############################################################################
+namespace.default.isolated = false
+
+namespace.default.search.paths = /system/${LIB}
+namespace.default.search.paths += /odm/${LIB}
+namespace.default.search.paths += /vendor/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/system/${LIB}
+namespace.default.asan.search.paths += /system/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}
+namespace.default.asan.search.paths += /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths += /vendor/${LIB}
+
+###############################################################################
+# "sphal" namespace
+#
+# SP-HAL(Sameprocess-HAL)s are the only vendor libraries that are allowed to be
+# loaded inside system processes. libEGL_<chipset>.so, libGLESv2_<chipset>.so,
+# android.hardware.graphics.mapper@2.0-impl.so, etc are SP-HALs.
+#
+# This namespace is exclusivly for SP-HALs. When the framework tries to dynami-
+# cally load SP-HALs, android_dlopen_ext() is used to explicitly specifying
+# that they should be searched and loaded from this namespace.
+#
+# Note that there is no link from the default namespace to this namespace.
+###############################################################################
+namespace.sphal.isolated = true
+namespace.sphal.visible = true
+
+namespace.sphal.search.paths = /odm/${LIB}
+namespace.sphal.search.paths += /vendor/${LIB}
+
+namespace.sphal.permitted.paths = /odm/${LIB}
+namespace.sphal.permitted.paths += /vendor/${LIB}
+
+namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}
+namespace.sphal.asan.search.paths += /odm/${LIB}
+namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.search.paths += /vendor/${LIB}
+
+namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}
+namespace.sphal.asan.permitted.paths += /odm/${LIB}
+namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.sphal.asan.permitted.paths += /vendor/${LIB}
+
+# Once in this namespace, access to libraries in /system/lib is restricted. Only
+# libs listed here can be used.
+namespace.sphal.links = default,vndk,rs
+
+namespace.sphal.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.sphal.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+namespace.sphal.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+# Renderscript gets separate namespace
+namespace.sphal.link.rs.shared_libs = libRS_internal.so
+
+###############################################################################
+# "rs" namespace
+#
+# This namespace is exclusively for Renderscript internal libraries.
+# This namespace has slightly looser restriction than the vndk namespace because
+# of the genuine characteristics of Renderscript; /data is in the permitted path
+# to load the compiled *.so file and libmediandk.so can be used here.
+###############################################################################
+namespace.rs.isolated = true
+namespace.rs.visible = true
+
+namespace.rs.search.paths = /odm/${LIB}/vndk-sp
+namespace.rs.search.paths += /vendor/${LIB}/vndk-sp
+namespace.rs.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.search.paths += /odm/${LIB}
+namespace.rs.search.paths += /vendor/${LIB}
+
+namespace.rs.permitted.paths = /odm/${LIB}
+namespace.rs.permitted.paths += /vendor/${LIB}
+namespace.rs.permitted.paths += /data
+
+namespace.rs.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.rs.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.rs.asan.search.paths += /data/asan/odm/${LIB}
+namespace.rs.asan.search.paths += /odm/${LIB}
+namespace.rs.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.rs.asan.search.paths += /vendor/${LIB}
+
+namespace.rs.asan.permitted.paths = /data/asan/odm/${LIB}
+namespace.rs.asan.permitted.paths += /odm/${LIB}
+namespace.rs.asan.permitted.paths += /data/asan/vendor/${LIB}
+namespace.rs.asan.permitted.paths += /vendor/${LIB}
+namespace.rs.asan.permitted.paths += /data
+
+namespace.rs.links = default,vndk
+
+namespace.rs.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.rs.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+# Private LLNDK libs (e.g. libft2.so) are exceptionally allowed to this
+# namespace because RS framework libs are using them.
+namespace.rs.link.default.shared_libs += %PRIVATE_LLNDK_LIBRARIES%
+
+namespace.rs.link.vndk.shared_libs = %VNDK_SAMEPROCESS_LIBRARIES%
+
+###############################################################################
+# "vndk" namespace
+#
+# This namespace is exclusively for vndk-sp libs.
+###############################################################################
+namespace.vndk.isolated = true
+namespace.vndk.visible = true
+
+namespace.vndk.search.paths = /odm/${LIB}/vndk-sp
+namespace.vndk.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+
+namespace.vndk.permitted.paths = /odm/${LIB}/hw
+namespace.vndk.permitted.paths += /odm/${LIB}/egl
+namespace.vndk.permitted.paths += /vendor/${LIB}/hw
+namespace.vndk.permitted.paths += /vendor/${LIB}/egl
+# This is exceptionally required since android.hidl.memory@1.0-impl.so is here
+namespace.vndk.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
+namespace.vndk.asan.search.paths = /data/asan/odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.vndk.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.vndk.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+
+namespace.vndk.asan.permitted.paths = /data/asan/odm/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /odm/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /data/asan/odm/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /odm/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /vendor/${LIB}/hw
+namespace.vndk.asan.permitted.paths += /data/asan/vendor/${LIB}/egl
+namespace.vndk.asan.permitted.paths += /vendor/${LIB}/egl
+
+namespace.vndk.asan.permitted.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%/hw
+namespace.vndk.asan.permitted.paths += /system/${LIB}/vndk-sp%VNDK_VER%/hw
+
+# When these NDK libs are required inside this namespace, then it is redirected
+# to the default namespace. This is possible since their ABI is stable across
+# Android releases.
+namespace.vndk.links = default
+namespace.vndk.link.default.shared_libs = %LLNDK_LIBRARIES%
+namespace.vndk.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
+
+###############################################################################
+# Namespace config for vendor processes. In O, no restriction is enforced for
+# them. However, in O-MR1, access to /system/${LIB} will not be allowed to
+# the default namespace. 'system' namespace will be added to give limited
+# (LL-NDK only) access.
+###############################################################################
+[vendor]
+namespace.default.isolated = false
+
+namespace.default.search.paths = /odm/${LIB}
+namespace.default.search.paths += /odm/${LIB}/vndk
+namespace.default.search.paths += /odm/${LIB}/vndk-sp
+namespace.default.search.paths += /vendor/${LIB}
+namespace.default.search.paths += /vendor/${LIB}/vndk
+namespace.default.search.paths += /vendor/${LIB}/vndk-sp
+
+# Access to system libraries are allowed
+namespace.default.search.paths += /system/${LIB}/vndk%VNDK_VER%
+namespace.default.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.search.paths += /system/${LIB}
+
+namespace.default.asan.search.paths = /data/asan/odm/${LIB}
+namespace.default.asan.search.paths += /odm/${LIB}
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk
+namespace.default.asan.search.paths += /odm/${LIB}/vndk
+namespace.default.asan.search.paths += /data/asan/odm/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /odm/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}
+namespace.default.asan.search.paths += /vendor/${LIB}
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk
+namespace.default.asan.search.paths += /vendor/${LIB}/vndk
+namespace.default.asan.search.paths += /data/asan/vendor/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /vendor/${LIB}/vndk-sp
+namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk%VNDK_VER%
+namespace.default.asan.search.paths += /system/${LIB}/vndk%VNDK_VER%
+namespace.default.asan.search.paths += /data/asan/system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.asan.search.paths += /system/${LIB}/vndk-sp%VNDK_VER%
+namespace.default.asan.search.paths += /data/asan/system/${LIB}
+namespace.default.asan.search.paths += /system/${LIB}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 6a1872f..a213ffb 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -28,12 +28,12 @@
restorecon /postinstall
# Mount cgroup mount point for cpu accounting
- mount cgroup none /acct cpuacct
+ mount cgroup none /acct nodev noexec nosuid cpuacct
mkdir /acct/uid
# root memory control cgroup, used by lmkd
mkdir /dev/memcg 0700 root system
- mount cgroup none /dev/memcg memory
+ mount cgroup none /dev/memcg nodev noexec nosuid memory
# app mem cgroups, used by activity manager, lmkd and zygote
mkdir /dev/memcg/apps/ 0755 system system
# cgroup for system_server and surfaceflinger
@@ -59,7 +59,7 @@
# Create energy-aware scheduler tuning nodes
mkdir /dev/stune
- mount cgroup none /dev/stune schedtune
+ mount cgroup none /dev/stune nodev noexec nosuid schedtune
mkdir /dev/stune/foreground
mkdir /dev/stune/background
mkdir /dev/stune/top-app
@@ -82,10 +82,10 @@
# Mount staging areas for devices managed by vold
# See storage config details at http://source.android.com/tech/storage/
- mount tmpfs tmpfs /mnt mode=0755,uid=0,gid=1000
+ mount tmpfs tmpfs /mnt nodev noexec nosuid mode=0755,uid=0,gid=1000
restorecon_recursive /mnt
- mount configfs none /config
+ mount configfs none /config nodev noexec nosuid
chmod 0775 /config/sdcardfs
chown system package_info /config/sdcardfs
@@ -155,7 +155,7 @@
# Create cgroup mount points for process groups
mkdir /dev/cpuctl
- mount cgroup none /dev/cpuctl cpu
+ mount cgroup none /dev/cpuctl nodev noexec nosuid cpu
chown system system /dev/cpuctl
chown system system /dev/cpuctl/tasks
chmod 0666 /dev/cpuctl/tasks
@@ -164,7 +164,7 @@
# sets up initial cpusets for ActivityManager
mkdir /dev/cpuset
- mount cpuset none /dev/cpuset
+ mount cpuset none /dev/cpuset nodev noexec nosuid
# this ensures that the cpusets are present and usable, but the device's
# init.rc must actually set the correct cpus
@@ -219,17 +219,17 @@
chmod 0644 /dev/xt_qtaguid
mkdir /dev/cg2_bpf
- mount cgroup2 cg2_bpf /dev/cg2_bpf
+ mount cgroup2 cg2_bpf /dev/cg2_bpf nodev noexec nosuid
chown root root /dev/cg2_bpf
chmod 0600 /dev/cg2_bpf
- mount bpf bpf /sys/fs/bpf
+ mount bpf bpf /sys/fs/bpf nodev noexec nosuid
# Create location for fs_mgr to store abbreviated output from filesystem
# checker programs.
mkdir /dev/fscklogs 0770 root system
# pstore/ramoops previous console log
- mount pstore pstore /sys/fs/pstore
+ mount pstore pstore /sys/fs/pstore nodev noexec nosuid
chown system log /sys/fs/pstore/console-ramoops
chmod 0440 /sys/fs/pstore/console-ramoops
chown system log /sys/fs/pstore/console-ramoops-0
@@ -318,8 +318,9 @@
start hwservicemanager
start vndservicemanager
- # once everything is setup, no need to modify /
- mount rootfs rootfs / ro remount
+ # Once everything is setup, no need to modify /.
+ # The bind+ro combination avoids modifying any other mount flags.
+ mount rootfs rootfs / remount bind ro
# Mount shared so changes propagate into child namespaces
mount rootfs rootfs / shared rec
# Mount default storage into root namespace
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index 3168f40..f0681d2 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -18,10 +18,6 @@
disabled
seclabel u:r:adbd:s0
-# adbd on at boot in emulator
-on property:ro.kernel.qemu=1
- start adbd
-
on boot
setprop sys.usb.configfs 0