Merge "Add support for new defines in v4.17.3 headers."
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 7f0801f..aea6ce6 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -487,21 +487,14 @@
// Note: to print the pointer, use "<< static_cast<const void*>(string_pointer)" instead.
// Note: a not-recommended alternative is to let Clang ignore the warning by adding
// -Wno-user-defined-warnings to CPPFLAGS.
-#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgcc-compat"
#define OSTREAM_STRING_POINTER_USAGE_WARNING \
__attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning")))
-#else
-#define OSTREAM_STRING_POINTER_USAGE_WARNING /* empty */
-#endif
inline std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer)
OSTREAM_STRING_POINTER_USAGE_WARNING {
return stream << static_cast<const void*>(string_pointer);
}
-#ifdef __clang__
#pragma clang diagnostic pop
-#endif
-#undef OSTREAM_STRING_POINTER_USAGE_WARNING
} // namespace std
diff --git a/base/include/android-base/macros.h b/base/include/android-base/macros.h
index 0c8eac0..49cc0c9 100644
--- a/base/include/android-base/macros.h
+++ b/base/include/android-base/macros.h
@@ -170,17 +170,7 @@
//
// In either case this macro has no effect on runtime behavior and performance
// of code.
-#if defined(__clang__) && defined(__has_warning)
-#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
-#endif
-#endif
-
-#ifndef FALLTHROUGH_INTENDED
-#define FALLTHROUGH_INTENDED \
- do { \
- } while (0)
-#endif
// Current ABI string
#if defined(__arm__)
diff --git a/base/include/android-base/parseint.h b/base/include/android-base/parseint.h
index b0fc7c3..fc68d56 100644
--- a/base/include/android-base/parseint.h
+++ b/base/include/android-base/parseint.h
@@ -26,9 +26,9 @@
namespace android {
namespace base {
-// Parses the unsigned decimal integer in the string 's' and sets 'out' to
-// that value. Optionally allows the caller to define a 'max' beyond which
-// otherwise valid values will be rejected. Returns boolean success; 'out'
+// Parses the unsigned decimal or hexadecimal integer in the string 's' and sets
+// 'out' to that value. Optionally allows the caller to define a 'max' beyond
+// which otherwise valid values will be rejected. Returns boolean success; 'out'
// is untouched if parsing fails.
template <typename T>
bool ParseUint(const char* s, T* out, T max = std::numeric_limits<T>::max(),
@@ -42,9 +42,7 @@
const char* suffixes = "bkmgtpe";
const char* suffix;
if (!allow_suffixes || (suffix = strchr(suffixes, tolower(*end))) == nullptr) return false;
-#if __clang__ // TODO: win32 still builds with GCC :-(
if (__builtin_mul_overflow(result, 1ULL << (10 * (suffix - suffixes)), &result)) return false;
-#endif
}
if (max < result) {
return false;
@@ -71,8 +69,8 @@
return ParseByteCount(s.c_str(), out, max);
}
-// Parses the signed decimal integer in the string 's' and sets 'out' to
-// that value. Optionally allows the caller to define a 'min' and 'max
+// Parses the signed decimal or hexadecimal integer in the string 's' and sets
+// 'out' to that value. Optionally allows the caller to define a 'min' and 'max'
// beyond which otherwise valid values will be rejected. Returns boolean
// success; 'out' is untouched if parsing fails.
template <typename T>
diff --git a/base/include/android-base/thread_annotations.h b/base/include/android-base/thread_annotations.h
index d56e935..5c55e63 100644
--- a/base/include/android-base/thread_annotations.h
+++ b/base/include/android-base/thread_annotations.h
@@ -16,11 +16,7 @@
#pragma once
-#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
-#endif
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#define CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index d334e30..6cfcd3f 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -142,10 +142,4 @@
template <typename T>
int close(const android::base::unique_fd_impl<T>&)
-#if defined(__clang__)
- __attribute__((__unavailable__(
-#else
- __attribute__((__error__(
-#endif
- "close called on unique_fd"
- )));
+ __attribute__((__unavailable__("close called on unique_fd")));
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index ddd1caf..71d3ecb 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -24,6 +24,7 @@
NORMAL="${ESCAPE}[0m"
# Best guess to an average device's reboot time, refined as tests return
DURATION_DEFAULT=45
+STOP_ON_FAILURE=false
# Helper functions
@@ -50,11 +51,18 @@
fi
}
+[ "USAGE: get_property <prop>
+
+Returns the property value" ]
+get_property() {
+ adb shell getprop ${1} 2>&1 </dev/null
+}
+
[ "USAGE: isDebuggable
Returns: true if device is (likely) a debug build" ]
isDebuggable() {
- if inAdb && [ 1 -ne `adb shell getprop ro.debuggable` ]; then
+ if inAdb && [ 1 -ne `get_property ro.debuggable` ]; then
false
fi
}
@@ -93,7 +101,7 @@
return 1
fi
adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null
- test_reason="`adb shell getprop persist.test.boot.reason 2>/dev/null`"
+ test_reason="`get_property persist.test.boot.reason`"
if [ X"${test_reason}" != X"${1}" ]; then
echo "ERROR: can not set persist.test.boot.reason to '${1}'." >&2
return 1
@@ -188,9 +196,9 @@
if [ 0 != ${counter} ]; then
adb wait-for-device </dev/null >/dev/null 2>/dev/null
fi
- if [ -n "`adb shell getprop sys.boot.reason </dev/null 2>/dev/null`" ]
+ if [ -n "`get_property sys.boot.reason`" ]
then
- vals=`adb shell getprop </dev/null 2>/dev/null |
+ vals=`get_property |
sed -n 's/[[]sys[.]\(boot_completed\|logbootcomplete\)[]]: [[]\([01]\)[]]$/\1=\2/p'`
if [ "${vals}" = "`echo boot_completed=1 ; echo logbootcomplete=1`" ]
then
@@ -223,15 +231,38 @@
rval="${2}"
shift 2
if ! ( echo X"${rval}" | grep '^X'"${lval}"'$' >/dev/null 2>/dev/null ); then
- echo "ERROR: expected \"${lval}\" got \"${rval}\"" >&2
- if [ -n "${*}" ] ; then
- echo " ${*}" >&2
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 50 -o "${rval}" != "${rval%
+*}" ]; then
+ echo "ERROR: expected \"${lval}\"" >&2
+ echo " got \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "ERROR: expected \"${lval}\" got \"${rval}\" ${*}" >&2
fi
return 1
fi
if [ -n "${*}" ] ; then
if [ X"${lval}" != X"${rval}" ]; then
- echo "INFO: ok \"${lval}\"(=\"${rval}\") ${*}" >&2
+ if [ `echo ${lval}${rval}${*} | wc -c` -gt 60 -o "${rval}" != "${rval%
+*}" ]; then
+ echo "INFO: ok \"${lval}\"" >&2
+ echo " = \"${rval}\"" |
+ sed ': again
+ N
+ s/\(\n\)\([^ ]\)/\1 \2/
+ t again' >&2
+ if [ -n "${*}" ] ; then
+ echo " ${*}" >&2
+ fi
+ else
+ echo "INFO: ok \"${lval}\" = \"${rval}\" ${*}" >&2
+ fi
else
echo "INFO: ok \"${lval}\" ${*}" >&2
fi
@@ -250,7 +281,7 @@
property="${1}"
value="${2}"
shift 2
- val=`adb shell getprop ${property} 2>&1`
+ val=`get_property ${property}`
EXPECT_EQ "${value}" "${val}" for Android property ${property}
local_ret=${?}
if [ 0 != ${local_ret} -a "ro.boot.bootreason" = "${property}" ]; then
@@ -317,6 +348,7 @@
init : Command 'exec - system log -- /system/bin/bootstat --record_boot_complete' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
init : Command 'exec - system log -- /system/bin/bootstat --record_boot_reason' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
init : Command 'exec - system log -- /system/bin/bootstat --record_time_since_factory_reset' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc:
+init : Command 'exec_background - system log -- /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l' action=sys.boot_completed=1 && sys.logbootcomplete=1 (/system/etc/init/bootstat.rc
(/system/bin/bootstat --record_boot_complete)'...
(/system/bin/bootstat --record_boot_complete)' (pid${SPACE}
(/system/bin/bootstat --record_boot_reason)'...
@@ -392,6 +424,9 @@
echo "${GREEN}[ OK ]${NORMAL} ${TEST} ${*}"
else
echo "${RED}[ FAILED ]${NORMAL} ${TEST} ${*}"
+ if ${STOP_ON_FAILURE}; then
+ exit ${save_ret}
+ fi
fi
return ${save_ret}
}
@@ -462,7 +497,7 @@
NB: must also roughly match heuristics in system/core/bootstat/bootstat.cpp" ]
validate_property() {
- val="`adb shell getprop ${1} 2>&1`"
+ val=`get_property ${1}`
ret=`validate_reason "${val}"`
if [ "reboot" = "${ret}" ]; then
ret=`validate_reason "reboot,${val}"`
@@ -470,6 +505,17 @@
echo ${ret}
}
+[ "USAGE: check_boilerblate_properties
+
+Check for common property values" ]
+check_boilerplate_properties() {
+ EXPECT_PROPERTY persist.sys.boot.reason ""
+ save_ret=${?}
+ reason=`validate_property sys.boot.reason`
+ ( exit ${save_ret} ) # because one can not just do ?=${save_ret}
+ EXPECT_PROPERTY persist.sys.boot.reason.history "${reason},[1-9][0-9]*\(\|[^0-9].*\)"
+}
+
#
# Actual test frames
#
@@ -487,6 +533,7 @@
duration_test 1
wait_for_screen
retval=0
+ # sys.boot.reason is last for a reason
check_set="ro.boot.bootreason sys.boot.reason.last sys.boot.reason"
bootloader=""
# NB: this test could fail if performed _after_ optional_factory_reset test
@@ -498,12 +545,11 @@
check_set="ro.boot.bootreason sys.boot.reason"
bootloader="bootloader"
fi
- EXPECT_PROPERTY persist.sys.boot.reason ""
for prop in ${check_set}; do
reason=`validate_property ${prop}`
EXPECT_PROPERTY ${prop} ${reason} || retval=${?}
done
- # sys.boot.reason is last for a reason
+ check_boilerplate_properties || retval=${?}
report_bootstat_logs ${reason} ${bootloader}
return ${retval}
}
@@ -557,7 +603,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason "\(reboot,ota\|bootloader\)"
EXPECT_PROPERTY sys.boot.reason.last bootloader
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,ota bootloader
}
@@ -572,7 +618,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,ota
EXPECT_PROPERTY sys.boot.reason.last reboot,ota
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,ota
}
@@ -604,7 +650,7 @@
fi
EXPECT_PROPERTY sys.boot.reason ${reasons}
EXPECT_PROPERTY sys.boot.reason.last ${reason}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs ${reason} ${bootloader_reason}
}
@@ -638,7 +684,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
EXPECT_PROPERTY sys.boot.reason.last "reboot,.*"
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,factory_reset reboot, reboot,adb \
"-bootstat: Failed to read /data/misc/bootstat/build_date: No such file or directory" \
"-bootstat: Failed to parse boot time record: /data/misc/bootstat/build_date"
@@ -670,7 +716,7 @@
( exit ${save_ret} ) # because one can not just do ?=${save_ret}
EXPECT_PROPERTY sys.boot.reason reboot,factory_reset
EXPECT_PROPERTY sys.boot.reason.last ""
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,factory_reset bootloader \
"-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \
"-bootstat: Failed to parse boot time record: /data/misc/bootstat/last_boot_time_utc" \
@@ -744,7 +790,7 @@
EXPECT_PROPERTY sys.boot.reason shutdown,battery
EXPECT_PROPERTY sys.boot.reason.last cold
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,battery "-bootstat: Battery level at shutdown 2%"
exitPstore
}
@@ -766,7 +812,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,battery
EXPECT_PROPERTY sys.boot.reason.last shutdown,battery
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,battery
}
@@ -787,7 +833,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,thermal,battery
EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal,battery
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,thermal,battery
}
@@ -824,7 +870,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs kernel_panic,sysrq
exitPstore
}
@@ -852,7 +898,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs kernel_panic,sysrq,test \
"-bootstat: Unknown boot reason: kernel_panic,sysrq,test"
exitPstore
@@ -883,7 +929,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason ${panic_msg}
EXPECT_PROPERTY sys.boot.reason.last ${panic_msg}
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs kernel_panic,hung
exitPstore
}
@@ -916,7 +962,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,thermal
EXPECT_PROPERTY sys.boot.reason.last shutdown,thermal
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,thermal
}
@@ -937,7 +983,7 @@
wait_for_screen -n >&2
EXPECT_PROPERTY sys.boot.reason shutdown,userrequested
EXPECT_PROPERTY sys.boot.reason.last shutdown,userrequested
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs shutdown,userrequested
}
@@ -954,7 +1000,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,shell
EXPECT_PROPERTY sys.boot.reason.last reboot,shell
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,shell
}
@@ -971,7 +1017,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,adb
EXPECT_PROPERTY sys.boot.reason.last reboot,adb
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,adb
}
@@ -1007,7 +1053,7 @@
wait_for_screen
EXPECT_PROPERTY sys.boot.reason reboot,its_just_so_hard
EXPECT_PROPERTY sys.boot.reason.last reboot,its_just_so_hard
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs reboot,its_just_so_hard
}
@@ -1057,7 +1103,7 @@
EXPECT_PROPERTY ro.boot.bootreason "${bootloader_expected}"
EXPECT_PROPERTY sys.boot.reason "${sys_expected}"
EXPECT_PROPERTY sys.boot.reason.last "${last_expected}"
- EXPECT_PROPERTY persist.sys.boot.reason ""
+ check_boilerplate_properties
report_bootstat_logs "${sys_expected}"
}
@@ -1111,88 +1157,98 @@
shift 2
fi
-if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
- echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
- echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
- exit 0
-fi
+# Helpful for debugging, allows us to import the functions.
+if [ X"--macros" != X"${1}" ]; then
-# Check if all conditions for the script are sane
+ if [ X"--help" = X"${1}" -o X"-h" = X"${1}" -o X"-?" = X"${1}" ]; then
+ echo "USAGE: ${0##*/} [-s SERIAL] [tests]"
+ echo tests - `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+ exit 0
+ fi
-if [ -z "${ANDROID_SERIAL}" ]; then
- ndev=`(
- adb devices | grep -v 'List of devices attached'
- fastboot devices
- ) |
- grep -v "^[${SPACE}${TAB}]*\$" |
- wc -l`
- if [ ${ndev} -gt 1 ]; then
- echo "ERROR: no target device specified, ${ndev} connected" >&2
- echo "${RED}[ FAILED ]${NORMAL}"
- exit 1
+ if [ X"--stop" = X"${1}" ]; then
+ STOP_ON_FAILURE=true
+ shift
fi
- echo "WARNING: no target device specified" >&2
-fi
-ret=0
+ # Check if all conditions for the script are sane
-# Test Series
-if [ X"all" = X"${*}" ]; then
- # automagically pick up all test_<function>s.
- eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
- if [ X"nothing" = X"${1}" ]; then
- shift 1
- fi
-fi
-if [ -z "$*" ]; then
- # automagically pick up all test_<function>, except test_optional_<function>.
- eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
- grep -v '^optional_'`
- if [ -z "${2}" ]; then
- # Hard coded should shell fail to find them above (search/permission issues)
- eval set properties ota cold factory_reset hard battery unknown \
- kernel_panic kernel_panic_subreason kernel_panic_hung warm \
- thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
- Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
- bootloader_kernel_panic bootloader_oem_powerkey \
- bootloader_wdog_reset bootloader_wdog_reset bootloader_wdog_reset \
- bootloader_hard bootloader_recovery
- fi
- if [ X"nothing" = X"${1}" ]; then
- shift 1
- fi
-fi
-echo "INFO: selected test(s): ${@}" >&2
-echo
-# Prepare device
-setBootloaderBootReason 2>/dev/null
-# Start pouring through the tests.
-failures=
-successes=
-for t in "${@}"; do
- wrap_test ${t}
- retval=${?}
- if [ 0 = ${retval} ]; then
- if [ -z "${successes}" ]; then
- successes=${t}
- else
- successes="${successes} ${t}"
+ if [ -z "${ANDROID_SERIAL}" ]; then
+ ndev=`(
+ adb devices | grep -v 'List of devices attached'
+ fastboot devices
+ ) |
+ grep -v "^[${SPACE}${TAB}]*\$" |
+ wc -l`
+ if [ ${ndev} -gt 1 ]; then
+ echo "ERROR: no target device specified, ${ndev} connected" >&2
+ echo "${RED}[ FAILED ]${NORMAL}"
+ exit 1
fi
- else
- ret=${retval}
- if [ -z "${failures}" ]; then
- failures=${t}
- else
- failures="${failures} ${t}"
+ echo "WARNING: no target device specified" >&2
+ fi
+
+ ret=0
+
+ # Test Series
+ if [ X"all" = X"${*}" ]; then
+ # automagically pick up all test_<function>s.
+ eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null`
+ if [ X"nothing" = X"${1}" ]; then
+ shift 1
fi
fi
+ if [ -z "$*" ]; then
+ # automagically pick up all test_<function>, except test_optional_<function>.
+ eval set nothing `sed -n 's/^test_\([^ ()]*\)() {/\1/p' $0 </dev/null |
+ grep -v '^optional_'`
+ if [ -z "${2}" ]; then
+ # Hard coded should shell fail to find them (search/permission issues)
+ eval set properties ota cold factory_reset hard battery unknown \
+ kernel_panic kernel_panic_subreason kernel_panic_hung warm \
+ thermal_shutdown userrequested_shutdown shell_reboot adb_reboot \
+ Its_Just_So_Hard_reboot bootloader_normal bootloader_watchdog \
+ bootloader_kernel_panic bootloader_oem_powerkey \
+ bootloader_wdog_reset bootloader_cold bootloader_warm \
+ bootloader_hard bootloader_recovery
+ fi
+ if [ X"nothing" = X"${1}" ]; then
+ shift 1
+ fi
+ fi
+ echo "INFO: selected test(s): ${@}" >&2
echo
-done
+ # Prepare device
+ setBootloaderBootReason 2>/dev/null
+ # Start pouring through the tests.
+ failures=
+ successes=
+ for t in "${@}"; do
+ wrap_test ${t}
+ retval=${?}
+ if [ 0 = ${retval} ]; then
+ if [ -z "${successes}" ]; then
+ successes=${t}
+ else
+ successes="${successes} ${t}"
+ fi
+ else
+ ret=${retval}
+ if [ -z "${failures}" ]; then
+ failures=${t}
+ else
+ failures="${failures} ${t}"
+ fi
+ fi
+ echo
+ done
-if [ -n "${successes}" ]; then
- echo "${GREEN}[ PASSED ]${NORMAL} ${successes}"
+ if [ -n "${successes}" ]; then
+ echo "${GREEN}[ PASSED ]${NORMAL} ${successes}"
+ fi
+ if [ -n "${failures}" ]; then
+ echo "${RED}[ FAILED ]${NORMAL} ${failures}"
+ fi
+ exit ${ret}
+
fi
-if [ -n "${failures}" ]; then
- echo "${RED}[ FAILED ]${NORMAL} ${failures}"
-fi
-exit ${ret}
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index 7ec57ec..4d9f1ac 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -27,6 +27,7 @@
#include <cstddef>
#include <cstdio>
#include <ctime>
+#include <iterator>
#include <map>
#include <memory>
#include <regex>
@@ -123,12 +124,12 @@
return std::string(&temp[0], len);
}
-void SetProperty(const char* key, const std::string& val) {
- property_set(key, val.c_str());
+bool SetProperty(const char* key, const std::string& val) {
+ return property_set(key, val.c_str()) == 0;
}
-void SetProperty(const char* key, const char* val) {
- property_set(key, val);
+bool SetProperty(const char* key, const char* val) {
+ return property_set(key, val) == 0;
}
constexpr int32_t kEmptyBootReason = 0;
@@ -735,8 +736,49 @@
const char system_reboot_reason_property[] = "sys.boot.reason";
const char last_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY;
const char last_last_reboot_reason_property[] = "sys.boot.reason.last";
+constexpr size_t history_reboot_reason_size = 4;
+const char history_reboot_reason_property[] = LAST_REBOOT_REASON_PROPERTY ".history";
const char bootloader_reboot_reason_property[] = "ro.boot.bootreason";
+// Land system_boot_reason into system_reboot_reason_property.
+// Shift system_boot_reason into history_reboot_reason_property.
+void BootReasonAddToHistory(const std::string& system_boot_reason) {
+ if (system_boot_reason.empty()) return;
+ LOG(INFO) << "Canonical boot reason: " << system_boot_reason;
+ auto old_system_boot_reason = GetProperty(system_reboot_reason_property);
+ if (!SetProperty(system_reboot_reason_property, system_boot_reason)) {
+ SetProperty(system_reboot_reason_property, system_boot_reason.substr(0, PROPERTY_VALUE_MAX - 1));
+ }
+ auto reason_history = android::base::Split(GetProperty(history_reboot_reason_property), "\n");
+ static auto mark = time(nullptr);
+ auto mark_str = std::string(",") + std::to_string(mark);
+ auto marked_system_boot_reason = system_boot_reason + mark_str;
+ if (!reason_history.empty()) {
+ // delete any entries that we just wrote in a previous
+ // call and leveraging duplicate line handling
+ auto last = old_system_boot_reason + mark_str;
+ // trim the list to (history_reboot_reason_size - 1)
+ ssize_t max = history_reboot_reason_size;
+ for (auto it = reason_history.begin(); it != reason_history.end();) {
+ if (it->empty() || (last == *it) || (marked_system_boot_reason == *it) || (--max <= 0)) {
+ it = reason_history.erase(it);
+ } else {
+ last = *it;
+ ++it;
+ }
+ }
+ }
+ // insert at the front, concatenating mark (<epoch time>) detail to the value.
+ reason_history.insert(reason_history.begin(), marked_system_boot_reason);
+ // If the property string is too long ( > PROPERTY_VALUE_MAX)
+ // we get an error, so trim out last entry and try again.
+ while (!(SetProperty(history_reboot_reason_property, android::base::Join(reason_history, '\n')))) {
+ auto it = std::prev(reason_history.end());
+ if (it == reason_history.end()) break;
+ reason_history.erase(it);
+ }
+}
+
// Scrub, Sanitize, Standardize and Enhance the boot reason string supplied.
std::string BootReasonStrToReason(const std::string& boot_reason) {
std::string ret(GetProperty(system_reboot_reason_property));
@@ -795,6 +837,8 @@
{"!warm", "wdt_by_pass_pwk"}, // change flavour of blunt
{"!reboot", "^wdt$"}, // change flavour of blunt
{"reboot,tool", "tool_by_pass_pwk"},
+ {"!reboot,longkey", "reboot_longkey"},
+ {"!reboot,longkey", "kpdpwr"},
{"bootloader", ""},
};
@@ -930,13 +974,11 @@
if (!boot_event_store.GetBootEvent(kBuildDateKey, &record)) {
boot_complete_prefix = "factory_reset_" + boot_complete_prefix;
boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
- LOG(INFO) << "Canonical boot reason: reboot,factory_reset";
- SetProperty(system_reboot_reason_property, "reboot,factory_reset");
+ BootReasonAddToHistory("reboot,factory_reset");
} else if (build_date != record.second) {
boot_complete_prefix = "ota_" + boot_complete_prefix;
boot_event_store.AddBootEventWithValue(kBuildDateKey, build_date);
- LOG(INFO) << "Canonical boot reason: reboot,ota";
- SetProperty(system_reboot_reason_property, "reboot,ota");
+ BootReasonAddToHistory("reboot,ota");
}
return boot_complete_prefix;
@@ -1034,7 +1076,7 @@
const std::string bootloader_boot_reason(GetProperty(bootloader_reboot_reason_property));
const std::string system_boot_reason(BootReasonStrToReason(bootloader_boot_reason));
// Record the scrubbed system_boot_reason to the property
- SetProperty(system_reboot_reason_property, system_boot_reason);
+ BootReasonAddToHistory(system_boot_reason);
// Shift last_reboot_reason_property to last_last_reboot_reason_property
std::string last_boot_reason(GetProperty(last_reboot_reason_property));
if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 6417a5c..b3df811 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -31,6 +31,7 @@
#include <time.h>
#include <unistd.h>
+#include <functional>
#include <memory>
#include <string>
#include <thread>
@@ -1356,7 +1357,7 @@
return true;
}
-bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback) {
+bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback) {
if (!callback) {
return false;
}
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index a14dba3..a5b3fe8 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -235,41 +235,46 @@
* If not found, the loop exits with fl[i].name being null.
*/
for (i = 0; fl[i].name; i++) {
- if (!strncmp(p, fl[i].name, strlen(fl[i].name))) {
+ auto name = fl[i].name;
+ auto len = strlen(name);
+ auto end = len;
+ if (name[end - 1] == '=') --end;
+ if (!strncmp(p, name, len) && (p[end] == name[end])) {
f |= fl[i].flag;
- if ((fl[i].flag == MF_CRYPT) && flag_vals) {
+ if (!flag_vals) break;
+ if (p[end] != '=') break;
+ char* arg = p + end + 1;
+ auto flag = fl[i].flag;
+ if (flag == MF_CRYPT) {
/* The encryptable flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_VERIFY) && flag_vals) {
+ flag_vals->key_loc = strdup(arg);
+ } else if (flag == MF_VERIFY) {
/* If the verify flag is followed by an = and the
* location for the verity state, get it and return it.
*/
- char *start = strchr(p, '=');
- if (start) {
- flag_vals->verity_loc = strdup(start + 1);
- }
- } else if ((fl[i].flag == MF_FORCECRYPT) && flag_vals) {
+ flag_vals->verity_loc = strdup(arg);
+ } else if (flag == MF_FORCECRYPT) {
/* The forceencrypt flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_FORCEFDEORFBE) && flag_vals) {
+ flag_vals->key_loc = strdup(arg);
+ } else if (flag == MF_FORCEFDEORFBE) {
/* The forcefdeorfbe flag is followed by an = and the
* location of the keys. Get it and return it.
*/
- flag_vals->key_loc = strdup(strchr(p, '=') + 1);
+ flag_vals->key_loc = strdup(arg);
flag_vals->file_contents_mode = EM_AES_256_XTS;
flag_vals->file_names_mode = EM_AES_256_CTS;
- } else if ((fl[i].flag == MF_FILEENCRYPTION) && flag_vals) {
+ } else if (flag == MF_FILEENCRYPTION) {
/* The fileencryption flag is followed by an = and
* the mode of contents encryption, then optionally a
* : and the mode of filenames encryption (defaults
* to aes-256-cts). Get it and return it.
*/
- char *mode = strchr(p, '=') + 1;
- char *colon = strchr(mode, ':');
+ auto mode = arg;
+ auto colon = strchr(mode, ':');
if (colon) {
*colon = '\0';
}
@@ -283,33 +288,30 @@
} else {
flag_vals->file_names_mode = EM_AES_256_CTS;
}
- } else if ((fl[i].flag == MF_KEYDIRECTORY) && flag_vals) {
+ } else if (flag == MF_KEYDIRECTORY) {
/* The metadata flag is followed by an = and the
* directory for the keys. Get it and return it.
*/
- flag_vals->key_dir = strdup(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_LENGTH) && flag_vals) {
+ flag_vals->key_dir = strdup(arg);
+ } else if (flag == MF_LENGTH) {
/* The length flag is followed by an = and the
* size of the partition. Get it and return it.
*/
- flag_vals->part_length = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_VOLDMANAGED) && flag_vals) {
+ flag_vals->part_length = strtoll(arg, NULL, 0);
+ } else if (flag == MF_VOLDMANAGED) {
/* The voldmanaged flag is followed by an = and the
* label, a colon and the partition number or the
* word "auto", e.g.
* voldmanaged=sdcard:3
* Get and return them.
*/
- char *label_start;
- char *label_end;
- char *part_start;
+ auto label_start = arg;
+ auto label_end = strchr(label_start, ':');
- label_start = strchr(p, '=') + 1;
- label_end = strchr(p, ':');
if (label_end) {
flag_vals->label = strndup(label_start,
(int) (label_end - label_start));
- part_start = strchr(p, ':') + 1;
+ auto part_start = label_end + 1;
if (!strcmp(part_start, "auto")) {
flag_vals->partnum = -1;
} else {
@@ -318,41 +320,41 @@
} else {
LERROR << "Warning: voldmanaged= flag malformed";
}
- } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) {
- flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_MAX_COMP_STREAMS) && flag_vals) {
- flag_vals->max_comp_streams = strtoll(strchr(p, '=') + 1, NULL, 0);
- } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) {
- int is_percent = !!strrchr(p, '%');
- unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0);
+ } else if (flag == MF_SWAPPRIO) {
+ flag_vals->swap_prio = strtoll(arg, NULL, 0);
+ } else if (flag == MF_MAX_COMP_STREAMS) {
+ flag_vals->max_comp_streams = strtoll(arg, NULL, 0);
+ } else if (flag == MF_ZRAMSIZE) {
+ auto is_percent = !!strrchr(arg, '%');
+ auto val = strtoll(arg, NULL, 0);
if (is_percent)
flag_vals->zram_size = calculate_zram_size(val);
else
flag_vals->zram_size = val;
- } else if ((fl[i].flag == MF_RESERVEDSIZE) && flag_vals) {
+ } else if (flag == MF_RESERVEDSIZE) {
/* The reserved flag is followed by an = and the
* reserved size of the partition. Get it and return it.
*/
- flag_vals->reserved_size = parse_size(strchr(p, '=') + 1);
- } else if ((fl[i].flag == MF_ERASEBLKSIZE) && flag_vals) {
+ flag_vals->reserved_size = parse_size(arg);
+ } else if (flag == MF_ERASEBLKSIZE) {
/* The erase block size flag is followed by an = and the flash
* erase block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
- unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+ auto val = strtoul(arg, NULL, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->erase_blk_size = val;
- } else if ((fl[i].flag == MF_LOGICALBLKSIZE) && flag_vals) {
+ } else if (flag == MF_LOGICALBLKSIZE) {
/* The logical block size flag is followed by an = and the flash
* logical block size. Get it, check that it is a power of 2 and
* at least 4096, and return it.
*/
- unsigned int val = strtoul(strchr(p, '=') + 1, NULL, 0);
+ auto val = strtoul(arg, NULL, 0);
if (val >= 4096 && (val & (val - 1)) == 0)
flag_vals->logical_blk_size = val;
- } else if ((fl[i].flag == MF_SYSFS) && flag_vals) {
+ } else if (flag == MF_SYSFS) {
/* The path to trigger device gc by idle-maint of vold. */
- flag_vals->sysfs_path = strdup(strchr(p, '=') + 1);
+ flag_vals->sysfs_path = strdup(arg);
}
break;
}
@@ -506,8 +508,7 @@
return false;
}
-static struct fstab *fs_mgr_read_fstab_file(FILE *fstab_file)
-{
+static struct fstab* fs_mgr_read_fstab_file(FILE* fstab_file, bool proc_mounts) {
int cnt, entries;
ssize_t len;
size_t alloc_len = 0;
@@ -607,7 +608,10 @@
fstab->recs[cnt].fs_options = NULL;
}
- if (!(p = strtok_r(NULL, delim, &save_ptr))) {
+ // For /proc/mounts, ignore everything after mnt_freq and mnt_passno
+ if (proc_mounts) {
+ p += strlen(p);
+ } else if (!(p = strtok_r(NULL, delim, &save_ptr))) {
LERROR << "Error parsing fs_mgr_options";
goto err;
}
@@ -739,7 +743,7 @@
return nullptr;
}
- fstab = fs_mgr_read_fstab_file(fstab_file);
+ fstab = fs_mgr_read_fstab_file(fstab_file, !strcmp("/proc/mounts", fstab_path));
if (!fstab) {
LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << fstab_path << "'";
}
@@ -767,7 +771,7 @@
return nullptr;
}
- struct fstab *fstab = fs_mgr_read_fstab_file(fstab_file.get());
+ struct fstab* fstab = fs_mgr_read_fstab_file(fstab_file.get(), false);
if (!fstab) {
LERROR << __FUNCTION__ << "(): failed to load fstab from kernel:"
<< std::endl << fstab_buf;
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index c1b2ed9..1049fb6 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -22,6 +22,8 @@
#include <stdbool.h>
#include <linux/dm-ioctl.h>
+#include <functional>
+
#include <fstab/fstab.h>
// Magic number at start of verity metadata
@@ -48,8 +50,8 @@
};
// Callback function for verity status
-typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
- const char *mount_point, int mode, int status);
+typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* mount_point,
+ int mode, int status);
#define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7
#define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6
@@ -73,7 +75,7 @@
struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size);
bool fs_mgr_load_verity_state(int* mode);
-bool fs_mgr_update_verity_state(fs_mgr_verity_state_callback callback);
+bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback);
int fs_mgr_swapon_all(struct fstab *fstab);
bool fs_mgr_update_logical_partition(struct fstab_rec* rec);
diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp
index 5310cab..a590037 100644
--- a/fs_mgr/liblp/utility.cpp
+++ b/fs_mgr/liblp/utility.cpp
@@ -38,7 +38,8 @@
}
if (S_ISBLK(s.st_mode)) {
- return get_block_device_size(fd);
+ *size = get_block_device_size(fd);
+ return *size != 0;
}
int64_t result = SeekFile64(fd, 0, SEEK_END);
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index 2e76752..8b1c55a 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -14,13 +14,18 @@
* limitations under the License.
*/
+#include <linux/fs.h>
+#include <mntent.h>
+
#include <algorithm>
#include <iterator>
+#include <set>
#include <string>
#include <utility>
#include <vector>
#include <android-base/strings.h>
+#include <fstab/fstab.h>
#include <gtest/gtest.h>
#include "../fs_mgr_priv_boot_config.h"
@@ -129,3 +134,70 @@
EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "nospace", &content));
EXPECT_TRUE(content.empty()) << content;
}
+
+TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) {
+ auto fstab = fs_mgr_read_fstab("/proc/mounts");
+ ASSERT_NE(fstab, nullptr);
+
+ std::unique_ptr<std::FILE, int (*)(std::FILE*)> mounts(setmntent("/proc/mounts", "r"),
+ endmntent);
+ ASSERT_NE(mounts, nullptr);
+
+ mntent* mentry;
+ int i = 0;
+ while ((mentry = getmntent(mounts.get())) != nullptr) {
+ ASSERT_LT(i, fstab->num_entries);
+ auto fsrec = &fstab->recs[i];
+
+ std::string mnt_fsname(mentry->mnt_fsname ?: "nullptr");
+ std::string blk_device(fsrec->blk_device ?: "nullptr");
+ EXPECT_EQ(mnt_fsname, blk_device);
+
+ std::string mnt_dir(mentry->mnt_dir ?: "nullptr");
+ std::string mount_point(fsrec->mount_point ?: "nullptr");
+ EXPECT_EQ(mnt_dir, mount_point);
+
+ std::string mnt_type(mentry->mnt_type ?: "nullptr");
+ std::string fs_type(fsrec->fs_type ?: "nullptr");
+ EXPECT_EQ(mnt_type, fs_type);
+
+ std::set<std::string> mnt_opts;
+ for (auto& s : android::base::Split(mentry->mnt_opts ?: "nullptr", ",")) {
+ mnt_opts.emplace(s);
+ }
+ std::set<std::string> fs_options;
+ for (auto& s : android::base::Split(fsrec->fs_options ?: "nullptr", ",")) {
+ fs_options.emplace(s);
+ }
+ // matches private content in fs_mgr_fstab.c
+ static struct flag_list {
+ const char* name;
+ unsigned int flag;
+ } mount_flags[] = {
+ {"noatime", MS_NOATIME},
+ {"noexec", MS_NOEXEC},
+ {"nosuid", MS_NOSUID},
+ {"nodev", MS_NODEV},
+ {"nodiratime", MS_NODIRATIME},
+ {"ro", MS_RDONLY},
+ {"rw", 0},
+ {"remount", MS_REMOUNT},
+ {"bind", MS_BIND},
+ {"rec", MS_REC},
+ {"unbindable", MS_UNBINDABLE},
+ {"private", MS_PRIVATE},
+ {"slave", MS_SLAVE},
+ {"shared", MS_SHARED},
+ {"defaults", 0},
+ {0, 0},
+ };
+ for (auto f = 0; mount_flags[f].name; ++f) {
+ if (mount_flags[f].flag & fsrec->flags) {
+ fs_options.emplace(mount_flags[f].name);
+ }
+ }
+ if (!(fsrec->flags & MS_RDONLY)) fs_options.emplace("rw");
+ EXPECT_EQ(mnt_opts, fs_options);
+ ++i;
+ }
+}
diff --git a/init/Android.bp b/init/Android.bp
index cf7637f..625fb94 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -179,6 +179,7 @@
"rlimit_parser_test.cpp",
"service_test.cpp",
"subcontext_test.cpp",
+ "tokenizer_test.cpp",
"ueventd_test.cpp",
"util_test.cpp",
],
diff --git a/init/init.cpp b/init/init.cpp
index 77c4fc4..686cd6e 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -647,6 +647,9 @@
// /mnt/vendor is used to mount vendor-specific partitions that can not be
// part of the vendor partition, e.g. because they are mounted read-write.
CHECKCALL(mkdir("/mnt/vendor", 0755));
+ // /mnt/product is used to mount product-specific partitions that can not be
+ // part of the product partition, e.g. because they are mounted read-write.
+ CHECKCALL(mkdir("/mnt/product", 0755));
#undef CHECKCALL
diff --git a/init/tokenizer_test.cpp b/init/tokenizer_test.cpp
new file mode 100644
index 0000000..acfc7c7
--- /dev/null
+++ b/init/tokenizer_test.cpp
@@ -0,0 +1,163 @@
+//
+// 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 "tokenizer.h"
+
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace init {
+
+namespace {
+
+void RunTest(const std::string& data, const std::vector<std::vector<std::string>>& expected_tokens) {
+ auto data_copy = std::string{data};
+ data_copy.push_back('\n'); // TODO: fix tokenizer
+ data_copy.push_back('\0');
+
+ parse_state state;
+ state.line = 0;
+ state.ptr = data_copy.data();
+ state.nexttoken = 0;
+
+ std::vector<std::string> current_line;
+ std::vector<std::vector<std::string>> tokens;
+
+ while (true) {
+ switch (next_token(&state)) {
+ case T_EOF:
+ EXPECT_EQ(expected_tokens, tokens) << data;
+ return;
+ case T_NEWLINE:
+ tokens.emplace_back(std::move(current_line));
+ break;
+ case T_TEXT:
+ current_line.emplace_back(state.text);
+ break;
+ }
+ }
+}
+
+} // namespace
+
+TEST(tokenizer, null) {
+ RunTest("", {{}});
+}
+
+TEST(tokenizer, simple_oneline) {
+ RunTest("one two\tthree\rfour", {{"one", "two", "three", "four"}});
+}
+
+TEST(tokenizer, simple_multiline) {
+ RunTest("1 2 3\n4 5 6\n7 8 9", {{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}});
+}
+
+TEST(tokenizer, preceding_space) {
+ // Preceding spaces are ignored.
+ RunTest(" 1 2 3\n\t\t\t\t4 5 6\n\r\r\r\r7 8 9",
+ {{"1", "2", "3"}, {"4", "5", "6"}, {"7", "8", "9"}});
+}
+
+TEST(tokenizer, comments) {
+ // Entirely commented lines still produce a T_NEWLINE token for tracking line count.
+ RunTest("1 2 3\n#4 5 6\n7 8 9", {{"1", "2", "3"}, {}, {"7", "8", "9"}});
+
+ RunTest("#1 2 3\n4 5 6\n7 8 9", {{}, {"4", "5", "6"}, {"7", "8", "9"}});
+
+ RunTest("1 2 3\n4 5 6\n#7 8 9", {{"1", "2", "3"}, {"4", "5", "6"}, {}});
+
+ RunTest("1 2 #3\n4 #5 6\n#7 8 9", {{"1", "2"}, {"4"}, {}});
+}
+
+TEST(tokenizer, control_chars) {
+ // Literal \n, \r, \t, and \\ produce the control characters \n, \r, \t, and \\ respectively.
+ // Literal \? produces ? for all other character '?'
+
+ RunTest(R"(1 token\ntoken 2)", {{"1", "token\ntoken", "2"}});
+ RunTest(R"(1 token\rtoken 2)", {{"1", "token\rtoken", "2"}});
+ RunTest(R"(1 token\ttoken 2)", {{"1", "token\ttoken", "2"}});
+ RunTest(R"(1 token\\token 2)", {{"1", "token\\token", "2"}});
+ RunTest(R"(1 token\btoken 2)", {{"1", "tokenbtoken", "2"}});
+
+ RunTest(R"(1 token\n 2)", {{"1", "token\n", "2"}});
+ RunTest(R"(1 token\r 2)", {{"1", "token\r", "2"}});
+ RunTest(R"(1 token\t 2)", {{"1", "token\t", "2"}});
+ RunTest(R"(1 token\\ 2)", {{"1", "token\\", "2"}});
+ RunTest(R"(1 token\b 2)", {{"1", "tokenb", "2"}});
+
+ RunTest(R"(1 \ntoken 2)", {{"1", "\ntoken", "2"}});
+ RunTest(R"(1 \rtoken 2)", {{"1", "\rtoken", "2"}});
+ RunTest(R"(1 \ttoken 2)", {{"1", "\ttoken", "2"}});
+ RunTest(R"(1 \\token 2)", {{"1", "\\token", "2"}});
+ RunTest(R"(1 \btoken 2)", {{"1", "btoken", "2"}});
+
+ RunTest(R"(1 \n 2)", {{"1", "\n", "2"}});
+ RunTest(R"(1 \r 2)", {{"1", "\r", "2"}});
+ RunTest(R"(1 \t 2)", {{"1", "\t", "2"}});
+ RunTest(R"(1 \\ 2)", {{"1", "\\", "2"}});
+ RunTest(R"(1 \b 2)", {{"1", "b", "2"}});
+}
+
+TEST(tokenizer, cr_lf) {
+ // \ before \n, \r, or \r\n is interpreted as a line continuation
+ // Extra whitespace on the next line is eaten, except \r unlike in the above tests.
+
+ RunTest("lf\\\ncont", {{"lfcont"}});
+ RunTest("lf\\\n \t\t\t\tcont", {{"lfcont"}});
+
+ RunTest("crlf\\\r\ncont", {{"crlfcont"}});
+ RunTest("crlf\\\r\n \t\t\t\tcont", {{"crlfcont"}});
+
+ RunTest("cr\\\rcont", {{"crcont"}});
+
+ RunTest("lfspace \\\ncont", {{"lfspace", "cont"}});
+ RunTest("lfspace \\\n \t\t\t\tcont", {{"lfspace", "cont"}});
+
+ RunTest("crlfspace \\\r\ncont", {{"crlfspace", "cont"}});
+ RunTest("crlfspace \\\r\n \t\t\t\tcont", {{"crlfspace", "cont"}});
+
+ RunTest("crspace \\\rcont", {{"crspace", "cont"}});
+}
+
+TEST(tokenizer, quoted) {
+ RunTest("\"quoted simple string\"", {{"quoted simple string"}});
+
+ // Unterminated quotes just return T_EOF without any T_NEWLINE.
+ RunTest("\"unterminated quoted string", {});
+
+ RunTest("\"1 2 3\"\n \"unterminated quoted string", {{"1 2 3"}});
+
+ // Escaping quotes is not allowed and are treated as an unterminated quoted string.
+ RunTest("\"quoted escaped quote\\\"\"", {});
+ RunTest("\"quoted escaped\\\" quote\"", {});
+ RunTest("\"\\\"quoted escaped quote\"", {});
+
+ RunTest("\"quoted control characters \\n \\r \\t \\\\ \\b \\\r \\\n \r \n\"",
+ {{"quoted control characters \\n \\r \\t \\\\ \\b \\\r \\\n \r \n"}});
+
+ RunTest("\"quoted simple string\" \"second quoted string\"",
+ {{"quoted simple string", "second quoted string"}});
+
+ RunTest("\"# comment quoted string\"", {{"# comment quoted string"}});
+
+ RunTest("\"Adjacent \"\"quoted strings\"", {{"Adjacent quoted strings"}});
+}
+
+} // namespace init
+} // namespace android
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 2849aa8..0cb8a4d 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -32,10 +32,6 @@
#include "android_get_control_env.h"
-#ifndef TEMP_FAILURE_RETRY
-#define TEMP_FAILURE_RETRY(exp) (exp) // KISS implementation
-#endif
-
#if defined(__ANDROID__)
/* For the socket trust (credentials) check */
#include <private/android_filesystem_config.h>
@@ -102,15 +98,15 @@
// Compare to UNIX domain socket name, must match!
struct sockaddr_un addr;
socklen_t addrlen = sizeof(addr);
- int ret = TEMP_FAILURE_RETRY(getsockname(fd, (struct sockaddr *)&addr, &addrlen));
+ int ret = getsockname(fd, (struct sockaddr*)&addr, &addrlen);
if (ret < 0) return -1;
- char *path = NULL;
- if (asprintf(&path, ANDROID_SOCKET_DIR "/%s", name) < 0) return -1;
- if (!path) return -1;
- int cmp = strcmp(addr.sun_path, path);
- free(path);
- if (cmp != 0) return -1;
- // It is what we think it is
- return fd;
+ constexpr char prefix[] = ANDROID_SOCKET_DIR "/";
+ constexpr size_t prefix_size = sizeof(prefix) - sizeof('\0');
+ if ((strncmp(addr.sun_path, prefix, prefix_size) == 0) &&
+ (strcmp(addr.sun_path + prefix_size, name) == 0)) {
+ // It is what we think it is
+ return fd;
+ }
+ return -1;
}
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 635cefd..388ab0a 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -26,9 +26,9 @@
namespace unwindstack {
template <typename AddressType>
-class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
+class DwarfDebugFrame : public DwarfSectionImplNoHdr<AddressType> {
public:
- DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {
+ DwarfDebugFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {
this->cie32_value_ = static_cast<uint32_t>(-1);
this->cie64_value_ = static_cast<uint64_t>(-1);
}
diff --git a/libunwindstack/DwarfEhFrame.h b/libunwindstack/DwarfEhFrame.h
index 7a41e45..df441fb 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -25,9 +25,9 @@
namespace unwindstack {
template <typename AddressType>
-class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
+class DwarfEhFrame : public DwarfSectionImplNoHdr<AddressType> {
public:
- DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
+ DwarfEhFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {}
virtual ~DwarfEhFrame() = default;
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index fd6a457..668527a 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -39,6 +39,7 @@
memory_.clear_text_offset();
memory_.set_data_offset(offset);
memory_.set_cur_offset(offset);
+ pc_offset_ = offset;
// Read the first four bytes all at once.
uint8_t data[4];
@@ -88,12 +89,22 @@
}
template <typename AddressType>
-const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromIndex(size_t index) {
- const FdeInfo* info = GetFdeInfoFromIndex(index);
- if (info == nullptr) {
+const DwarfFde* DwarfEhFrameWithHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
+ uint64_t fde_offset;
+ if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
return nullptr;
}
- return this->GetFdeFromOffset(info->offset);
+ const DwarfFde* fde = this->GetFdeFromOffset(fde_offset);
+ if (fde == nullptr) {
+ return nullptr;
+ }
+
+ // Guaranteed pc >= pc_start, need to check pc in the fde range.
+ if (pc < fde->pc_end) {
+ return fde;
+ }
+ last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
+ return nullptr;
}
template <typename AddressType>
@@ -241,6 +252,21 @@
}
}
+template <typename AddressType>
+void DwarfEhFrameWithHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
+ for (size_t i = 0; i < fde_count_; i++) {
+ const FdeInfo* info = GetFdeInfoFromIndex(i);
+ if (info == nullptr) {
+ break;
+ }
+ const DwarfFde* fde = this->GetFdeFromOffset(info->offset);
+ if (fde == nullptr) {
+ break;
+ }
+ fdes->push_back(fde);
+ }
+}
+
// Explicitly instantiate DwarfEhFrameWithHdr
template class DwarfEhFrameWithHdr<uint32_t>;
template class DwarfEhFrameWithHdr<uint64_t>;
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index d16dd10..e3e9ca8 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -21,7 +21,7 @@
#include <unordered_map>
-#include "DwarfEhFrame.h"
+#include <unwindstack/DwarfSection.h>
namespace unwindstack {
@@ -29,12 +29,12 @@
class Memory;
template <typename AddressType>
-class DwarfEhFrameWithHdr : public DwarfEhFrame<AddressType> {
+class DwarfEhFrameWithHdr : public DwarfSectionImpl<AddressType> {
public:
// Add these so that the protected members of DwarfSectionImpl
// can be accessed without needing a this->.
using DwarfSectionImpl<AddressType>::memory_;
- using DwarfSectionImpl<AddressType>::fde_count_;
+ using DwarfSectionImpl<AddressType>::pc_offset_;
using DwarfSectionImpl<AddressType>::entries_offset_;
using DwarfSectionImpl<AddressType>::entries_end_;
using DwarfSectionImpl<AddressType>::last_error_;
@@ -45,14 +45,27 @@
uint64_t offset;
};
- DwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrame<AddressType>(memory) {}
+ DwarfEhFrameWithHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
virtual ~DwarfEhFrameWithHdr() = default;
+ uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
+ return this->memory_.cur_offset() - pointer - 4;
+ }
+
+ uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
+ return this->memory_.cur_offset() - pointer - 8;
+ }
+
+ uint64_t AdjustPcFromFde(uint64_t pc) override {
+ // The eh_frame uses relative pcs.
+ return pc + this->memory_.cur_offset() - 4;
+ }
+
bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
- bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
+ const DwarfFde* GetFdeFromPc(uint64_t pc) override;
- const DwarfFde* GetFdeFromIndex(size_t index) override;
+ bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset);
const FdeInfo* GetFdeInfoFromIndex(size_t index);
@@ -60,6 +73,8 @@
bool GetFdeOffsetBinary(uint64_t pc, uint64_t* fde_offset, uint64_t total_entries);
+ void GetFdes(std::vector<const DwarfFde*>* fdes) override;
+
protected:
uint8_t version_;
uint8_t ptr_encoding_;
@@ -71,6 +86,7 @@
uint64_t entries_data_offset_;
uint64_t cur_entries_offset_ = 0;
+ uint64_t fde_count_;
std::unordered_map<uint64_t, FdeInfo> fde_info_;
};
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index eb83949..6061f61 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -36,24 +36,6 @@
DwarfSection::DwarfSection(Memory* memory) : memory_(memory) {}
-const DwarfFde* DwarfSection::GetFdeFromPc(uint64_t pc) {
- uint64_t fde_offset;
- if (!GetFdeOffsetFromPc(pc, &fde_offset)) {
- return nullptr;
- }
- const DwarfFde* fde = GetFdeFromOffset(fde_offset);
- if (fde == nullptr) {
- return nullptr;
- }
-
- // Guaranteed pc >= pc_start, need to check pc in the fde range.
- if (pc < fde->pc_end) {
- return fde;
- }
- last_error_.code = DWARF_ERROR_ILLEGAL_STATE;
- return nullptr;
-}
-
bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* finished) {
// Lookup the pc in the cache.
auto it = loc_regs_.upper_bound(pc);
@@ -81,6 +63,314 @@
}
template <typename AddressType>
+const DwarfCie* DwarfSectionImpl<AddressType>::GetCieFromOffset(uint64_t offset) {
+ auto cie_entry = cie_entries_.find(offset);
+ if (cie_entry != cie_entries_.end()) {
+ return &cie_entry->second;
+ }
+ DwarfCie* cie = &cie_entries_[offset];
+ memory_.set_cur_offset(offset);
+ if (!FillInCieHeader(cie) || !FillInCie(cie)) {
+ // Erase the cached entry.
+ cie_entries_.erase(offset);
+ return nullptr;
+ }
+ return cie;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInCieHeader(DwarfCie* cie) {
+ cie->lsda_encoding = DW_EH_PE_omit;
+ uint32_t length32;
+ if (!memory_.ReadBytes(&length32, sizeof(length32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (length32 == static_cast<uint32_t>(-1)) {
+ // 64 bit Cie
+ uint64_t length64;
+ if (!memory_.ReadBytes(&length64, sizeof(length64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ cie->cfa_instructions_end = memory_.cur_offset() + length64;
+ cie->fde_address_encoding = DW_EH_PE_sdata8;
+
+ uint64_t cie_id;
+ if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (cie_id != cie64_value_) {
+ // This is not a Cie, something has gone horribly wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+ } else {
+ // 32 bit Cie
+ cie->cfa_instructions_end = memory_.cur_offset() + length32;
+ cie->fde_address_encoding = DW_EH_PE_sdata4;
+
+ uint32_t cie_id;
+ if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (cie_id != cie32_value_) {
+ // This is not a Cie, something has gone horribly wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
+ if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
+ // Unrecognized version.
+ last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
+ return false;
+ }
+
+ // Read the augmentation string.
+ char aug_value;
+ do {
+ if (!memory_.ReadBytes(&aug_value, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ cie->augmentation_string.push_back(aug_value);
+ } while (aug_value != '\0');
+
+ if (cie->version == 4) {
+ // Skip the Address Size field since we only use it for validation.
+ memory_.set_cur_offset(memory_.cur_offset() + 1);
+
+ // Segment Size
+ if (!memory_.ReadBytes(&cie->segment_size, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ }
+
+ // Code Alignment Factor
+ if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ // Data Alignment Factor
+ if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (cie->version == 1) {
+ // Return Address is a single byte.
+ uint8_t return_address_register;
+ if (!memory_.ReadBytes(&return_address_register, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ cie->return_address_register = return_address_register;
+ } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (cie->augmentation_string[0] != 'z') {
+ cie->cfa_instructions_offset = memory_.cur_offset();
+ return true;
+ }
+
+ uint64_t aug_length;
+ if (!memory_.ReadULEB128(&aug_length)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
+
+ for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
+ switch (cie->augmentation_string[i]) {
+ case 'L':
+ if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ break;
+ case 'P': {
+ uint8_t encoding;
+ if (!memory_.ReadBytes(&encoding, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ memory_.set_pc_offset(pc_offset_);
+ if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ } break;
+ case 'R':
+ if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ break;
+ }
+ }
+ return true;
+}
+
+template <typename AddressType>
+const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
+ auto fde_entry = fde_entries_.find(offset);
+ if (fde_entry != fde_entries_.end()) {
+ return &fde_entry->second;
+ }
+ DwarfFde* fde = &fde_entries_[offset];
+ memory_.set_cur_offset(offset);
+ if (!FillInFdeHeader(fde) || !FillInFde(fde)) {
+ fde_entries_.erase(offset);
+ return nullptr;
+ }
+ return fde;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInFdeHeader(DwarfFde* fde) {
+ uint32_t length32;
+ if (!memory_.ReadBytes(&length32, sizeof(length32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (length32 == static_cast<uint32_t>(-1)) {
+ // 64 bit Fde.
+ uint64_t length64;
+ if (!memory_.ReadBytes(&length64, sizeof(length64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ fde->cfa_instructions_end = memory_.cur_offset() + length64;
+
+ uint64_t value64;
+ if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (value64 == cie64_value_) {
+ // This is a Cie, this means something has gone wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+
+ // Get the Cie pointer, which is necessary to properly read the rest of
+ // of the Fde information.
+ fde->cie_offset = GetCieOffsetFromFde64(value64);
+ } else {
+ // 32 bit Fde.
+ fde->cfa_instructions_end = memory_.cur_offset() + length32;
+
+ uint32_t value32;
+ if (!memory_.ReadBytes(&value32, sizeof(value32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ if (value32 == cie32_value_) {
+ // This is a Cie, this means something has gone wrong.
+ last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
+ return false;
+ }
+
+ // Get the Cie pointer, which is necessary to properly read the rest of
+ // of the Fde information.
+ fde->cie_offset = GetCieOffsetFromFde32(value32);
+ }
+ return true;
+}
+
+template <typename AddressType>
+bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
+ uint64_t cur_offset = memory_.cur_offset();
+
+ const DwarfCie* cie = GetCieFromOffset(fde->cie_offset);
+ if (cie == nullptr) {
+ return false;
+ }
+ fde->cie = cie;
+
+ if (cie->segment_size != 0) {
+ // Skip over the segment selector for now.
+ cur_offset += cie->segment_size;
+ }
+ memory_.set_cur_offset(cur_offset);
+
+ // The load bias only applies to the start.
+ memory_.set_pc_offset(load_bias_);
+ bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
+ fde->pc_start = AdjustPcFromFde(fde->pc_start);
+
+ memory_.set_pc_offset(0);
+ if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ fde->pc_end += fde->pc_start;
+
+ if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
+ // Augmentation Size
+ uint64_t aug_length;
+ if (!memory_.ReadULEB128(&aug_length)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+ uint64_t cur_offset = memory_.cur_offset();
+
+ memory_.set_pc_offset(pc_offset_);
+ if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ // Set our position to after all of the augmentation data.
+ memory_.set_cur_offset(cur_offset + aug_length);
+ }
+ fde->cfa_instructions_offset = memory_.cur_offset();
+
+ return true;
+}
+
+template <typename AddressType>
bool DwarfSectionImpl<AddressType>::EvalExpression(const DwarfLocation& loc, Memory* regular_memory,
AddressType* value,
RegsInfo<AddressType>* regs_info,
@@ -260,307 +550,6 @@
}
template <typename AddressType>
-const DwarfCie* DwarfSectionImpl<AddressType>::GetCie(uint64_t offset) {
- auto cie_entry = cie_entries_.find(offset);
- if (cie_entry != cie_entries_.end()) {
- return &cie_entry->second;
- }
- DwarfCie* cie = &cie_entries_[offset];
- memory_.set_cur_offset(offset);
- if (!FillInCie(cie)) {
- // Erase the cached entry.
- cie_entries_.erase(offset);
- return nullptr;
- }
- return cie;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInCie(DwarfCie* cie) {
- uint32_t length32;
- if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- // Set the default for the lsda encoding.
- cie->lsda_encoding = DW_EH_PE_omit;
-
- if (length32 == static_cast<uint32_t>(-1)) {
- // 64 bit Cie
- uint64_t length64;
- if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- cie->cfa_instructions_end = memory_.cur_offset() + length64;
- cie->fde_address_encoding = DW_EH_PE_sdata8;
-
- uint64_t cie_id;
- if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (cie_id != cie64_value_) {
- // This is not a Cie, something has gone horribly wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- } else {
- // 32 bit Cie
- cie->cfa_instructions_end = memory_.cur_offset() + length32;
- cie->fde_address_encoding = DW_EH_PE_sdata4;
-
- uint32_t cie_id;
- if (!memory_.ReadBytes(&cie_id, sizeof(cie_id))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (cie_id != cie32_value_) {
- // This is not a Cie, something has gone horribly wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
- }
-
- if (!memory_.ReadBytes(&cie->version, sizeof(cie->version))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->version != 1 && cie->version != 3 && cie->version != 4) {
- // Unrecognized version.
- last_error_.code = DWARF_ERROR_UNSUPPORTED_VERSION;
- return false;
- }
-
- // Read the augmentation string.
- char aug_value;
- do {
- if (!memory_.ReadBytes(&aug_value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->augmentation_string.push_back(aug_value);
- } while (aug_value != '\0');
-
- if (cie->version == 4) {
- // Skip the Address Size field since we only use it for validation.
- memory_.set_cur_offset(memory_.cur_offset() + 1);
-
- // Segment Size
- if (!memory_.ReadBytes(&cie->segment_size, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- }
-
- // Code Alignment Factor
- if (!memory_.ReadULEB128(&cie->code_alignment_factor)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- // Data Alignment Factor
- if (!memory_.ReadSLEB128(&cie->data_alignment_factor)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->version == 1) {
- // Return Address is a single byte.
- uint8_t return_address_register;
- if (!memory_.ReadBytes(&return_address_register, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->return_address_register = return_address_register;
- } else if (!memory_.ReadULEB128(&cie->return_address_register)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (cie->augmentation_string[0] != 'z') {
- cie->cfa_instructions_offset = memory_.cur_offset();
- return true;
- }
-
- uint64_t aug_length;
- if (!memory_.ReadULEB128(&aug_length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- cie->cfa_instructions_offset = memory_.cur_offset() + aug_length;
-
- for (size_t i = 1; i < cie->augmentation_string.size(); i++) {
- switch (cie->augmentation_string[i]) {
- case 'L':
- if (!memory_.ReadBytes(&cie->lsda_encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- break;
- case 'P': {
- uint8_t encoding;
- if (!memory_.ReadBytes(&encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.ReadEncodedValue<AddressType>(encoding, &cie->personality_handler)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } break;
- case 'R':
- if (!memory_.ReadBytes(&cie->fde_address_encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- break;
- }
- }
- return true;
-}
-
-template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromOffset(uint64_t offset) {
- auto fde_entry = fde_entries_.find(offset);
- if (fde_entry != fde_entries_.end()) {
- return &fde_entry->second;
- }
- DwarfFde* fde = &fde_entries_[offset];
- memory_.set_cur_offset(offset);
- if (!FillInFde(fde)) {
- fde_entries_.erase(offset);
- return nullptr;
- }
- return fde;
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::FillInFde(DwarfFde* fde) {
- uint32_t length32;
- if (!memory_.ReadBytes(&length32, sizeof(length32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (length32 == static_cast<uint32_t>(-1)) {
- // 64 bit Fde.
- uint64_t length64;
- if (!memory_.ReadBytes(&length64, sizeof(length64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- fde->cfa_instructions_end = memory_.cur_offset() + length64;
-
- uint64_t value64;
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (value64 == cie64_value_) {
- // This is a Cie, this means something has gone wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Get the Cie pointer, which is necessary to properly read the rest of
- // of the Fde information.
- fde->cie_offset = GetCieOffsetFromFde64(value64);
- } else {
- // 32 bit Fde.
- fde->cfa_instructions_end = memory_.cur_offset() + length32;
-
- uint32_t value32;
- if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (value32 == cie32_value_) {
- // This is a Cie, this means something has gone wrong.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Get the Cie pointer, which is necessary to properly read the rest of
- // of the Fde information.
- fde->cie_offset = GetCieOffsetFromFde32(value32);
- }
- uint64_t cur_offset = memory_.cur_offset();
-
- const DwarfCie* cie = GetCie(fde->cie_offset);
- if (cie == nullptr) {
- return false;
- }
- fde->cie = cie;
-
- if (cie->segment_size != 0) {
- // Skip over the segment selector for now.
- cur_offset += cie->segment_size;
- }
- memory_.set_cur_offset(cur_offset);
-
- // The load bias only applies to the start.
- memory_.set_pc_offset(load_bias_);
- bool valid = memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_start);
- fde->pc_start = AdjustPcFromFde(fde->pc_start);
-
- memory_.set_pc_offset(0);
- if (!valid || !memory_.ReadEncodedValue<AddressType>(cie->fde_address_encoding, &fde->pc_end)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- fde->pc_end += fde->pc_start;
-
- if (cie->augmentation_string.size() > 0 && cie->augmentation_string[0] == 'z') {
- // Augmentation Size
- uint64_t aug_length;
- if (!memory_.ReadULEB128(&aug_length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- uint64_t cur_offset = memory_.cur_offset();
-
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.ReadEncodedValue<AddressType>(cie->lsda_encoding, &fde->lsda_address)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- // Set our position to after all of the augmentation data.
- memory_.set_cur_offset(cur_offset + aug_length);
- }
- fde->cfa_instructions_offset = memory_.cur_offset();
-
- return true;
-}
-
-template <typename AddressType>
bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde,
dwarf_loc_regs_t* loc_regs) {
DwarfCfa<AddressType> cfa(&memory_, fde);
@@ -601,9 +590,10 @@
}
template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
+bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size, uint64_t load_bias) {
load_bias_ = load_bias;
entries_offset_ = offset;
+ next_entries_offset_ = offset;
entries_end_ = offset + size;
memory_.clear_func_offset();
@@ -612,298 +602,213 @@
memory_.set_data_offset(offset);
pc_offset_ = offset;
- return CreateSortedFdeList();
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::GetCieInfo(uint8_t* segment_size, uint8_t* encoding) {
- uint8_t version;
- if (!memory_.ReadBytes(&version, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- // Read the augmentation string.
- std::vector<char> aug_string;
- char aug_value;
- bool get_encoding = false;
- do {
- if (!memory_.ReadBytes(&aug_value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (aug_value == 'R') {
- get_encoding = true;
- }
- aug_string.push_back(aug_value);
- } while (aug_value != '\0');
-
- if (version == 4) {
- // Skip the Address Size field.
- memory_.set_cur_offset(memory_.cur_offset() + 1);
-
- // Read the segment size.
- if (!memory_.ReadBytes(segment_size, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } else {
- *segment_size = 0;
- }
-
- if (aug_string[0] != 'z' || !get_encoding) {
- // No encoding
- return true;
- }
-
- // Skip code alignment factor
- uint8_t value;
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
-
- // Skip data alignment factor
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
-
- if (version == 1) {
- // Skip return address register.
- memory_.set_cur_offset(memory_.cur_offset() + 1);
- } else {
- // Skip return address register.
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
- }
-
- // Skip the augmentation length.
- do {
- if (!memory_.ReadBytes(&value, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- } while (value & 0x80);
-
- for (size_t i = 1; i < aug_string.size(); i++) {
- if (aug_string[i] == 'R') {
- if (!memory_.ReadBytes(encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- // Got the encoding, that's all we are looking for.
- return true;
- } else if (aug_string[i] == 'L') {
- memory_.set_cur_offset(memory_.cur_offset() + 1);
- } else if (aug_string[i] == 'P') {
- uint8_t encoding;
- if (!memory_.ReadBytes(&encoding, 1)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- uint64_t value;
- memory_.set_pc_offset(pc_offset_);
- if (!memory_.template ReadEncodedValue<AddressType>(encoding, &value)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- }
- }
-
- // It should be impossible to get here.
- abort();
-}
-
-template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::AddFdeInfo(uint64_t entry_offset, uint8_t segment_size,
- uint8_t encoding) {
- if (segment_size != 0) {
- memory_.set_cur_offset(memory_.cur_offset() + 1);
- }
-
- uint64_t start;
- memory_.set_pc_offset(load_bias_);
- bool valid = memory_.template ReadEncodedValue<AddressType>(encoding, &start);
- start = AdjustPcFromFde(start);
-
- uint64_t length;
- memory_.set_pc_offset(0);
- if (!valid || !memory_.template ReadEncodedValue<AddressType>(encoding, &length)) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- if (length != 0) {
- fdes_.emplace_back(entry_offset, start, length);
- }
-
return true;
}
+// Create a cached version of the fde information such that it is a std::map
+// that is indexed by end pc and contains a pair that represents the start pc
+// followed by the fde object. The fde pointers are owned by fde_entries_
+// and not by the map object.
+// It is possible for an fde to be represented by multiple entries in
+// the map. This can happen if the the start pc and end pc overlap already
+// existing entries. For example, if there is already an entry of 0x400, 0x200,
+// and an fde has a start pc of 0x100 and end pc of 0x500, two new entries
+// will be added: 0x200, 0x100 and 0x500, 0x400.
template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::CreateSortedFdeList() {
- memory_.set_cur_offset(entries_offset_);
+void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
+ uint64_t start = fde->pc_start;
+ uint64_t end = fde->pc_end;
+ auto it = fdes_.upper_bound(start);
+ bool add_element = false;
+ while (it != fdes_.end() && start < end) {
+ if (add_element) {
+ add_element = false;
+ if (end < it->second.first) {
+ if (it->first == end) {
+ return;
+ }
+ fdes_[end] = std::make_pair(start, fde);
+ return;
+ }
+ if (start != it->second.first) {
+ fdes_[it->second.first] = std::make_pair(start, fde);
+ }
+ }
+ if (start < it->first) {
+ if (end < it->second.first) {
+ if (it->first != end) {
+ fdes_[end] = std::make_pair(start, fde);
+ }
+ return;
+ }
+ add_element = true;
+ }
+ start = it->first;
+ ++it;
+ }
+ if (start < end) {
+ fdes_[end] = std::make_pair(start, fde);
+ }
+}
- // Loop through all of the entries and read just enough to create
- // a sorted list of pcs.
- // This code assumes that first comes the cie, then the fdes that
- // it applies to.
- uint64_t cie_offset = 0;
- uint8_t address_encoding;
- uint8_t segment_size;
- while (memory_.cur_offset() < entries_end_) {
- uint64_t cur_entry_offset = memory_.cur_offset();
+template <typename AddressType>
+bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
+ uint64_t start_offset = next_entries_offset_;
- // Figure out the entry length and type.
- uint32_t value32;
+ memory_.set_cur_offset(next_entries_offset_);
+ uint32_t value32;
+ if (!memory_.ReadBytes(&value32, sizeof(value32))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ uint64_t cie_offset;
+ uint8_t cie_fde_encoding;
+ bool entry_is_cie = false;
+ if (value32 == static_cast<uint32_t>(-1)) {
+ // 64 bit entry.
+ uint64_t value64;
+ if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ next_entries_offset_ = memory_.cur_offset() + value64;
+ // Read the Cie Id of a Cie or the pointer of the Fde.
+ if (!memory_.ReadBytes(&value64, sizeof(value64))) {
+ last_error_.code = DWARF_ERROR_MEMORY_INVALID;
+ last_error_.address = memory_.cur_offset();
+ return false;
+ }
+
+ if (value64 == cie64_value_) {
+ entry_is_cie = true;
+ cie_fde_encoding = DW_EH_PE_sdata8;
+ } else {
+ cie_offset = this->GetCieOffsetFromFde64(value64);
+ }
+ } else {
+ next_entries_offset_ = memory_.cur_offset() + value32;
+
+ // 32 bit Cie
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
}
- uint64_t next_entry_offset;
- if (value32 == static_cast<uint32_t>(-1)) {
- uint64_t value64;
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
- next_entry_offset = memory_.cur_offset() + value64;
-
- // Read the Cie Id of a Cie or the pointer of the Fde.
- if (!memory_.ReadBytes(&value64, sizeof(value64))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (value64 == cie64_value_) {
- // Cie 64 bit
- address_encoding = DW_EH_PE_sdata8;
- if (!GetCieInfo(&segment_size, &address_encoding)) {
- return false;
- }
- cie_offset = cur_entry_offset;
- } else {
- uint64_t last_cie_offset = GetCieOffsetFromFde64(value64);
- if (last_cie_offset != cie_offset) {
- // This means that this Fde is not following the Cie.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Fde 64 bit
- if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
- return false;
- }
- }
+ if (value32 == cie32_value_) {
+ entry_is_cie = true;
+ cie_fde_encoding = DW_EH_PE_sdata4;
} else {
- next_entry_offset = memory_.cur_offset() + value32;
-
- // Read the Cie Id of a Cie or the pointer of the Fde.
- if (!memory_.ReadBytes(&value32, sizeof(value32))) {
- last_error_.code = DWARF_ERROR_MEMORY_INVALID;
- last_error_.address = memory_.cur_offset();
- return false;
- }
-
- if (value32 == cie32_value_) {
- // Cie 32 bit
- address_encoding = DW_EH_PE_sdata4;
- if (!GetCieInfo(&segment_size, &address_encoding)) {
- return false;
- }
- cie_offset = cur_entry_offset;
- } else {
- uint64_t last_cie_offset = GetCieOffsetFromFde32(value32);
- if (last_cie_offset != cie_offset) {
- // This means that this Fde is not following the Cie.
- last_error_.code = DWARF_ERROR_ILLEGAL_VALUE;
- return false;
- }
-
- // Fde 32 bit
- if (!AddFdeInfo(cur_entry_offset, segment_size, address_encoding)) {
- return false;
- }
- }
+ cie_offset = this->GetCieOffsetFromFde32(value32);
}
-
- if (next_entry_offset < memory_.cur_offset()) {
- // Simply consider the processing done in this case.
- break;
- }
- memory_.set_cur_offset(next_entry_offset);
}
- // Sort the entries.
- std::sort(fdes_.begin(), fdes_.end(), [](const FdeInfo& a, const FdeInfo& b) {
- if (a.start == b.start) return a.end < b.end;
- return a.start < b.start;
- });
+ if (entry_is_cie) {
+ DwarfCie* cie = &cie_entries_[start_offset];
+ cie->lsda_encoding = DW_EH_PE_omit;
+ cie->cfa_instructions_end = next_entries_offset_;
+ cie->fde_address_encoding = cie_fde_encoding;
- fde_count_ = fdes_.size();
+ if (!this->FillInCie(cie)) {
+ cie_entries_.erase(start_offset);
+ return false;
+ }
+ *fde_entry = nullptr;
+ } else {
+ DwarfFde* fde = &fde_entries_[start_offset];
+ fde->cfa_instructions_end = next_entries_offset_;
+ fde->cie_offset = cie_offset;
+ if (!this->FillInFde(fde)) {
+ fde_entries_.erase(start_offset);
+ return false;
+ }
+ *fde_entry = fde;
+ }
return true;
}
template <typename AddressType>
-bool DwarfSectionImpl<AddressType>::GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) {
- if (fde_count_ == 0) {
- return false;
- }
-
- size_t first = 0;
- size_t last = fde_count_;
- while (first < last) {
- size_t current = (first + last) / 2;
- const FdeInfo* info = &fdes_[current];
- if (pc >= info->start && pc < info->end) {
- *fde_offset = info->offset;
- return true;
- }
-
- if (pc < info->start) {
- last = current;
+void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
+ // Loop through the already cached entries.
+ uint64_t entry_offset = entries_offset_;
+ while (entry_offset < next_entries_offset_) {
+ auto cie_it = cie_entries_.find(entry_offset);
+ if (cie_it != cie_entries_.end()) {
+ entry_offset = cie_it->second.cfa_instructions_end;
} else {
- first = current + 1;
+ auto fde_it = fde_entries_.find(entry_offset);
+ if (fde_it == fde_entries_.end()) {
+ // No fde or cie at this entry, should not be possible.
+ return;
+ }
+ entry_offset = fde_it->second.cfa_instructions_end;
+ fdes->push_back(&fde_it->second);
}
}
- return false;
+
+ while (next_entries_offset_ < entries_end_) {
+ DwarfFde* fde;
+ if (!GetNextCieOrFde(&fde)) {
+ break;
+ }
+ if (fde != nullptr) {
+ InsertFde(fde);
+ fdes->push_back(fde);
+ }
+
+ if (next_entries_offset_ < memory_.cur_offset()) {
+ // Simply consider the processing done in this case.
+ break;
+ }
+ }
}
template <typename AddressType>
-const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromIndex(size_t index) {
- if (index >= fdes_.size()) {
- return nullptr;
+const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
+ // Search in the list of fdes we already have.
+ auto it = fdes_.upper_bound(pc);
+ if (it != fdes_.end()) {
+ if (pc >= it->second.first) {
+ return it->second.second;
+ }
}
- return this->GetFdeFromOffset(fdes_[index].offset);
+
+ // The section might have overlapping pcs in fdes, so it is necessary
+ // to do a linear search of the fdes by pc. As fdes are read, a cached
+ // search map is created.
+ while (next_entries_offset_ < entries_end_) {
+ DwarfFde* fde;
+ if (!GetNextCieOrFde(&fde)) {
+ return nullptr;
+ }
+ if (fde != nullptr) {
+ InsertFde(fde);
+ if (pc >= fde->pc_start && pc < fde->pc_end) {
+ return fde;
+ }
+ }
+
+ if (next_entries_offset_ < memory_.cur_offset()) {
+ // Simply consider the processing done in this case.
+ break;
+ }
+ }
+ return nullptr;
}
// Explicitly instantiate DwarfSectionImpl
template class DwarfSectionImpl<uint32_t>;
template class DwarfSectionImpl<uint64_t>;
+// Explicitly instantiate DwarfSectionImplNoHdr
+template class DwarfSectionImplNoHdr<uint32_t>;
+template class DwarfSectionImplNoHdr<uint64_t>;
+
// Explicitly instantiate DwarfDebugFrame
template class DwarfDebugFrame<uint32_t>;
template class DwarfDebugFrame<uint64_t>;
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 847f382..e9942de 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -43,7 +43,12 @@
class iterator : public std::iterator<std::bidirectional_iterator_tag, DwarfFde*> {
public:
- iterator(DwarfSection* section, size_t index) : section_(section), index_(index) {}
+ iterator(DwarfSection* section, size_t index) : index_(index) {
+ section->GetFdes(&fdes_);
+ if (index_ == static_cast<size_t>(-1)) {
+ index_ = fdes_.size();
+ }
+ }
iterator& operator++() {
index_++;
@@ -65,15 +70,18 @@
bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; }
bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; }
- const DwarfFde* operator*() { return section_->GetFdeFromIndex(index_); }
+ const DwarfFde* operator*() {
+ if (index_ > fdes_.size()) return nullptr;
+ return fdes_[index_];
+ }
private:
- DwarfSection* section_ = nullptr;
+ std::vector<const DwarfFde*> fdes_;
size_t index_ = 0;
};
iterator begin() { return iterator(this, 0); }
- iterator end() { return iterator(this, fde_count_); }
+ iterator end() { return iterator(this, static_cast<size_t>(-1)); }
DwarfErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
@@ -82,15 +90,11 @@
virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0;
- virtual bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) = 0;
-
virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) = 0;
- virtual const DwarfFde* GetFdeFromIndex(size_t index) = 0;
+ virtual void GetFdes(std::vector<const DwarfFde*>* fdes) = 0;
- const DwarfFde* GetFdeFromPc(uint64_t pc);
-
- virtual const DwarfFde* GetFdeFromOffset(uint64_t fde_offset) = 0;
+ virtual const DwarfFde* GetFdeFromPc(uint64_t pc) = 0;
virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) = 0;
@@ -109,7 +113,6 @@
uint32_t cie32_value_ = 0;
uint64_t cie64_value_ = 0;
- uint64_t fde_count_ = 0;
std::unordered_map<uint64_t, DwarfFde> fde_entries_;
std::unordered_map<uint64_t, DwarfCie> cie_entries_;
std::unordered_map<uint64_t, dwarf_loc_regs_t> cie_loc_regs_;
@@ -119,55 +122,73 @@
template <typename AddressType>
class DwarfSectionImpl : public DwarfSection {
public:
- struct FdeInfo {
- FdeInfo(uint64_t offset, uint64_t start, uint64_t length)
- : offset(offset), start(start), end(start + length) {}
-
- uint64_t offset;
- AddressType start;
- AddressType end;
- };
-
DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {}
virtual ~DwarfSectionImpl() = default;
- bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
+ const DwarfCie* GetCieFromOffset(uint64_t offset);
- bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) override;
-
- const DwarfFde* GetFdeFromIndex(size_t index) override;
+ const DwarfFde* GetFdeFromOffset(uint64_t offset);
bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
Regs* regs, bool* finished) override;
- const DwarfCie* GetCie(uint64_t offset);
- bool FillInCie(DwarfCie* cie);
-
- const DwarfFde* GetFdeFromOffset(uint64_t offset) override;
- bool FillInFde(DwarfFde* fde);
-
bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) override;
bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override;
protected:
+ bool FillInCieHeader(DwarfCie* cie);
+
+ bool FillInCie(DwarfCie* cie);
+
+ bool FillInFdeHeader(DwarfFde* fde);
+
+ bool FillInFde(DwarfFde* fde);
+
bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
- bool GetCieInfo(uint8_t* segment_size, uint8_t* encoding);
-
- bool AddFdeInfo(uint64_t entry_offset, uint8_t segment_size, uint8_t encoding);
-
- bool CreateSortedFdeList();
-
uint64_t load_bias_ = 0;
+ uint64_t entries_offset_ = 0;
+ uint64_t entries_end_ = 0;
uint64_t pc_offset_ = 0;
+};
- std::vector<FdeInfo> fdes_;
- uint64_t entries_offset_;
- uint64_t entries_end_;
+template <typename AddressType>
+class DwarfSectionImplNoHdr : public DwarfSectionImpl<AddressType> {
+ public:
+ // Add these so that the protected members of DwarfSectionImpl
+ // can be accessed without needing a this->.
+ using DwarfSectionImpl<AddressType>::memory_;
+ using DwarfSectionImpl<AddressType>::pc_offset_;
+ using DwarfSectionImpl<AddressType>::entries_offset_;
+ using DwarfSectionImpl<AddressType>::entries_end_;
+ using DwarfSectionImpl<AddressType>::last_error_;
+ using DwarfSectionImpl<AddressType>::load_bias_;
+ using DwarfSectionImpl<AddressType>::cie_entries_;
+ using DwarfSectionImpl<AddressType>::fde_entries_;
+ using DwarfSectionImpl<AddressType>::cie32_value_;
+ using DwarfSectionImpl<AddressType>::cie64_value_;
+
+ DwarfSectionImplNoHdr(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
+ virtual ~DwarfSectionImplNoHdr() = default;
+
+ bool Init(uint64_t offset, uint64_t size, uint64_t load_bias) override;
+
+ const DwarfFde* GetFdeFromPc(uint64_t pc) override;
+
+ void GetFdes(std::vector<const DwarfFde*>* fdes) override;
+
+ protected:
+ bool GetNextCieOrFde(DwarfFde** fde_entry);
+
+ void InsertFde(const DwarfFde* fde);
+
+ uint64_t next_entries_offset_ = 0;
+
+ std::map<uint64_t, std::pair<uint64_t, const DwarfFde*>> fdes_;
};
} // namespace unwindstack
diff --git a/libunwindstack/tests/DwarfDebugFrameTest.cpp b/libunwindstack/tests/DwarfDebugFrameTest.cpp
index 3a52044..d620934 100644
--- a/libunwindstack/tests/DwarfDebugFrameTest.cpp
+++ b/libunwindstack/tests/DwarfDebugFrameTest.cpp
@@ -16,7 +16,8 @@
#include <stdint.h>
-#include <gmock/gmock.h>
+#include <vector>
+
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
@@ -30,480 +31,377 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfDebugFrame : public DwarfDebugFrame<TypeParam> {
- public:
- MockDwarfDebugFrame(Memory* memory) : DwarfDebugFrame<TypeParam>(memory) {}
- ~MockDwarfDebugFrame() = default;
-
- void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
- void TestSetOffset(uint64_t offset) { this->entries_offset_ = offset; }
- void TestSetEndOffset(uint64_t offset) { this->entries_end_ = offset; }
- void TestPushFdeInfo(const typename DwarfDebugFrame<TypeParam>::FdeInfo& info) {
- this->fdes_.push_back(info);
- }
-
- uint64_t TestGetFdeCount() { return this->fde_count_; }
- uint8_t TestGetOffset() { return this->offset_; }
- uint8_t TestGetEndOffset() { return this->end_offset_; }
- void TestGetFdeInfo(size_t index, typename DwarfDebugFrame<TypeParam>::FdeInfo* info) {
- *info = this->fdes_[index];
- }
-};
-
-template <typename TypeParam>
class DwarfDebugFrameTest : public ::testing::Test {
protected:
void SetUp() override {
memory_.Clear();
- debug_frame_ = new MockDwarfDebugFrame<TypeParam>(&memory_);
+ debug_frame_ = new DwarfDebugFrame<TypeParam>(&memory_);
ResetLogs();
}
void TearDown() override { delete debug_frame_; }
MemoryFake memory_;
- MockDwarfDebugFrame<TypeParam>* debug_frame_ = nullptr;
+ DwarfDebugFrame<TypeParam>* debug_frame_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfDebugFrameTest);
// NOTE: All test class variables need to be referenced as this->.
-TYPED_TEST_P(DwarfDebugFrameTest, Init32) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
+static void SetCie32(MemoryFake* memory, uint64_t offset, uint32_t length,
+ std::vector<uint8_t> data) {
+ memory->SetData32(offset, length);
+ offset += 4;
+ // Indicates this is a cie.
+ memory->SetData32(offset, 0xffffffff);
+ offset += 4;
+ memory->SetMemory(offset, data);
+}
+
+static void SetCie64(MemoryFake* memory, uint64_t offset, uint64_t length,
+ std::vector<uint8_t> data) {
+ memory->SetData32(offset, 0xffffffff);
+ offset += 4;
+ memory->SetData64(offset, length);
+ offset += 8;
+ // Indicates this is a cie.
+ memory->SetData64(offset, 0xffffffffffffffffUL);
+ offset += 8;
+ memory->SetMemory(offset, data);
+}
+
+static void SetFde32(MemoryFake* memory, uint64_t offset, uint32_t length, uint64_t cie_offset,
+ uint32_t pc_start, uint32_t pc_length, uint64_t segment_length = 0,
+ std::vector<uint8_t>* data = nullptr) {
+ memory->SetData32(offset, length);
+ offset += 4;
+ memory->SetData32(offset, cie_offset);
+ offset += 4 + segment_length;
+ memory->SetData32(offset, pc_start);
+ offset += 4;
+ memory->SetData32(offset, pc_length);
+ if (data != nullptr) {
+ offset += 4;
+ memory->SetMemory(offset, *data);
+ }
+}
+
+static void SetFde64(MemoryFake* memory, uint64_t offset, uint64_t length, uint64_t cie_offset,
+ uint64_t pc_start, uint64_t pc_length, uint64_t segment_length = 0,
+ std::vector<uint8_t>* data = nullptr) {
+ memory->SetData32(offset, 0xffffffff);
+ offset += 4;
+ memory->SetData64(offset, length);
+ offset += 8;
+ memory->SetData64(offset, cie_offset);
+ offset += 8 + segment_length;
+ memory->SetData64(offset, pc_start);
+ offset += 8;
+ memory->SetData64(offset, pc_length);
+ if (data != nullptr) {
+ offset += 8;
+ memory->SetMemory(offset, *data);
+ }
+}
+
+static void SetFourFdes32(MemoryFake* memory) {
+ SetCie32(memory, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
// FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- this->memory_.SetData32(0x5200, 0xfc);
- this->memory_.SetData32(0x5204, 0);
- this->memory_.SetData32(0x5208, 0x2500);
- this->memory_.SetData32(0x520c, 0x300);
+ SetFde32(memory, 0x5100, 0xfc, 0, 0x1500, 0x200);
+ SetFde32(memory, 0x5200, 0xfc, 0, 0x2500, 0x300);
// CIE 32 information.
- this->memory_.SetData32(0x5300, 0xfc);
- this->memory_.SetData32(0x5304, 0xffffffff);
- this->memory_.SetData8(0x5308, 1);
- this->memory_.SetData8(0x5309, '\0');
+ SetCie32(memory, 0x5300, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
// FDE 32 information.
- this->memory_.SetData32(0x5400, 0xfc);
- this->memory_.SetData32(0x5404, 0x300);
- this->memory_.SetData32(0x5408, 0x3500);
- this->memory_.SetData32(0x540c, 0x400);
+ SetFde32(memory, 0x5400, 0xfc, 0x300, 0x3500, 0x400);
+ SetFde32(memory, 0x5500, 0xfc, 0x300, 0x4500, 0x500);
+}
- this->memory_.SetData32(0x5500, 0xfc);
- this->memory_.SetData32(0x5504, 0x300);
- this->memory_.SetData32(0x5508, 0x4500);
- this->memory_.SetData32(0x550c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32) {
+ SetFourFdes32(&this->memory_);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
+ ASSERT_EQ(4U, fdes.size());
- this->debug_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x2500U, info.start);
- EXPECT_EQ(0x2800U, info.end);
+ EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
+ EXPECT_EQ(0x5110U, fdes[0]->cfa_instructions_offset);
+ EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0U, fdes[0]->lsda_address);
+ EXPECT_TRUE(fdes[0]->cie != nullptr);
- this->debug_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x3500U, info.start);
- EXPECT_EQ(0x3900U, info.end);
+ EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
+ EXPECT_EQ(0x5210U, fdes[1]->cfa_instructions_offset);
+ EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0U, fdes[1]->lsda_address);
+ EXPECT_TRUE(fdes[1]->cie != nullptr);
- this->debug_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x4500U, info.start);
- EXPECT_EQ(0x4a00U, info.end);
+ EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
+ EXPECT_EQ(0x5410U, fdes[2]->cfa_instructions_offset);
+ EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0U, fdes[2]->lsda_address);
+ EXPECT_TRUE(fdes[2]->cie != nullptr);
+
+ EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
+ EXPECT_EQ(0x5510U, fdes[3]->cfa_instructions_offset);
+ EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+ EXPECT_EQ(0U, fdes[3]->lsda_address);
+ EXPECT_TRUE(fdes[3]->cie != nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init32_fde_not_following_cie) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x1000);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init32_do_not_fail_on_bad_next_entry) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- this->memory_.SetData32(0x5200, 0xfc);
- this->memory_.SetData32(0x5204, 0);
- this->memory_.SetData32(0x5208, 0x2500);
- this->memory_.SetData32(0x520c, 0x300);
-
- // CIE 32 information.
- this->memory_.SetData32(0x5300, 0);
- this->memory_.SetData32(0x5304, 0xffffffff);
- this->memory_.SetData8(0x5308, 1);
- this->memory_.SetData8(0x5309, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5400, 0xfc);
- this->memory_.SetData32(0x5404, 0x300);
- this->memory_.SetData32(0x5408, 0x3500);
- this->memory_.SetData32(0x540c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xfc);
- this->memory_.SetData32(0x5504, 0x300);
- this->memory_.SetData32(0x5508, 0x4500);
- this->memory_.SetData32(0x550c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_after_GetFdeFromPc) {
+ SetFourFdes32(&this->memory_);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+ EXPECT_EQ(0x3900U, fde->pc_end);
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+ ASSERT_EQ(4U, fdes.size());
+
+ // Verify that they got added in the correct order.
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init64) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes32_not_in_section) {
+ SetFourFdes32(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
- this->memory_.SetData32(0x5200, 0xffffffff);
- this->memory_.SetData64(0x5204, 0xf4);
- this->memory_.SetData64(0x520c, 0);
- this->memory_.SetData64(0x5214, 0x2500);
- this->memory_.SetData64(0x521c, 0x300);
+ ASSERT_EQ(3U, fdes.size());
+}
- // CIE 64 information.
- this->memory_.SetData32(0x5300, 0xffffffff);
- this->memory_.SetData64(0x5304, 0xf4);
- this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5314, 1);
- this->memory_.SetData8(0x5315, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5400, 0xffffffff);
- this->memory_.SetData64(0x5404, 0xf4);
- this->memory_.SetData64(0x540c, 0x300);
- this->memory_.SetData64(0x5414, 0x3500);
- this->memory_.SetData64(0x541c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xffffffff);
- this->memory_.SetData64(0x5504, 0xf4);
- this->memory_.SetData64(0x550c, 0x300);
- this->memory_.SetData64(0x5514, 0x4500);
- this->memory_.SetData64(0x551c, 0x500);
-
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32) {
+ SetFourFdes32(&this->memory_);
ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->debug_frame_->TestGetFdeCount());
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
-
- this->debug_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x2500U, info.start);
- EXPECT_EQ(0x2800U, info.end);
-
- this->debug_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x3500U, info.start);
- EXPECT_EQ(0x3900U, info.end);
-
- this->debug_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x4500U, info.start);
- EXPECT_EQ(0x4a00U, info.end);
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init64_fde_not_following_cie) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0x1000);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
-
- ASSERT_FALSE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->debug_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init64_do_not_fail_on_bad_next_entry) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
-
- this->memory_.SetData32(0x5200, 0xffffffff);
- this->memory_.SetData64(0x5204, 0xf4);
- this->memory_.SetData64(0x520c, 0);
- this->memory_.SetData64(0x5214, 0x2500);
- this->memory_.SetData64(0x521c, 0x300);
-
- // CIE 64 information.
- this->memory_.SetData32(0x5300, 0xffffffff);
- this->memory_.SetData64(0x5304, 0);
- this->memory_.SetData64(0x530c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x5314, 1);
- this->memory_.SetData8(0x5315, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5400, 0xffffffff);
- this->memory_.SetData64(0x5404, 0xf4);
- this->memory_.SetData64(0x540c, 0x300);
- this->memory_.SetData64(0x5414, 0x3500);
- this->memory_.SetData64(0x541c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xffffffff);
- this->memory_.SetData64(0x5504, 0xf4);
- this->memory_.SetData64(0x550c, 0x300);
- this->memory_.SetData64(0x5514, 0x4500);
- this->memory_.SetData64(0x551c, 0x500);
-
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(2U, this->debug_frame_->TestGetFdeCount());
-}
-
-TYPED_TEST_P(DwarfDebugFrameTest, Init_non_zero_load_bias) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, 'z');
- this->memory_.SetData8(0x500a, 'R');
- this->memory_.SetData8(0x500b, '\0');
- this->memory_.SetData8(0x500c, 0);
- this->memory_.SetData8(0x500d, 0);
- this->memory_.SetData8(0x500e, 0);
- this->memory_.SetData8(0x500f, 0);
- this->memory_.SetData8(0x5010, 0x1b);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
- this->memory_.SetData8(0x5110, 0);
- this->memory_.SetData8(0x5111, 0);
-
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0x1000));
- ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
-
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x2500U, info.start);
- EXPECT_EQ(0x2700U, info.end);
-
- const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2504);
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x2500U, fde->pc_start);
- EXPECT_EQ(0x2700U, fde->pc_end);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init_version1) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 1);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'R', 'P', 'L', '\0'});
- // Code alignment factor.
- this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetData8(0x5014, 0x84);
- // Augmentation length
- this->memory_.SetMemory(0x5015, std::vector<uint8_t>{0x84, 0x00});
- // R data.
- this->memory_.SetData8(0x5017, DW_EH_PE_pcrel | DW_EH_PE_udata2);
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_reverse) {
+ SetFourFdes32(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, Init_version4) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 4);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
- // Address size.
- this->memory_.SetData8(0x500e, 4);
- // Segment size.
- this->memory_.SetData8(0x500f, 0);
- // Code alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5012, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetMemory(0x5016, std::vector<uint8_t>{0x85, 0x10});
- // Augmentation length
- this->memory_.SetMemory(0x5018, std::vector<uint8_t>{0x84, 0x00});
- // L data.
- this->memory_.SetData8(0x501a, 0x10);
- // P data.
- this->memory_.SetData8(0x501b, DW_EH_PE_udata4);
- this->memory_.SetData32(0x501c, 0x100);
- // R data.
- this->memory_.SetData8(0x5020, DW_EH_PE_pcrel | DW_EH_PE_udata2);
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc32_not_in_section) {
+ SetFourFdes32(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
-
- ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->debug_frame_->TestGetFdeCount());
-
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->debug_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x1500U, info.start);
- EXPECT_EQ(0x1700U, info.end);
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde == nullptr);
}
-TYPED_TEST_P(DwarfDebugFrameTest, GetFdeOffsetFromPc) {
- typename DwarfDebugFrame<TypeParam>::FdeInfo info(0, 0, 0);
- for (size_t i = 0; i < 9; i++) {
- info.start = 0x1000 * (i + 1);
- info.end = 0x1000 * (i + 2) - 0x10;
- info.offset = 0x5000 + i * 0x20;
- this->debug_frame_->TestPushFdeInfo(info);
- }
+static void SetFourFdes64(MemoryFake* memory) {
+ // CIE 64 information.
+ SetCie64(memory, 0x5000, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
- this->debug_frame_->TestSetFdeCount(0);
- uint64_t fde_offset;
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ // FDE 64 information.
+ SetFde64(memory, 0x5100, 0xf4, 0, 0x1500, 0x200);
+ SetFde64(memory, 0x5200, 0xf4, 0, 0x2500, 0x300);
- this->debug_frame_->TestSetFdeCount(9);
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- // Odd number of elements.
- for (size_t i = 0; i < 9; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index "
- << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- }
+ // CIE 64 information.
+ SetCie64(memory, 0x5300, 0xf4, std::vector<uint8_t>{1, '\0', 0, 0, 1});
- // Even number of elements.
- this->debug_frame_->TestSetFdeCount(10);
- info.start = 0xa000;
- info.end = 0xaff0;
- info.offset = 0x5120;
- this->debug_frame_->TestPushFdeInfo(info);
+ // FDE 64 information.
+ SetFde64(memory, 0x5400, 0xf4, 0x300, 0x3500, 0x400);
+ SetFde64(memory, 0x5500, 0xf4, 0x300, 0x4500, 0x500);
+}
- for (size_t i = 0; i < 10; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index "
- << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->debug_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
- }
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+
+ ASSERT_EQ(4U, fdes.size());
+
+ EXPECT_EQ(0x5000U, fdes[0]->cie_offset);
+ EXPECT_EQ(0x5124U, fdes[0]->cfa_instructions_offset);
+ EXPECT_EQ(0x5200U, fdes[0]->cfa_instructions_end);
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0U, fdes[0]->lsda_address);
+ EXPECT_TRUE(fdes[0]->cie != nullptr);
+
+ EXPECT_EQ(0x5000U, fdes[1]->cie_offset);
+ EXPECT_EQ(0x5224U, fdes[1]->cfa_instructions_offset);
+ EXPECT_EQ(0x5300U, fdes[1]->cfa_instructions_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0U, fdes[1]->lsda_address);
+ EXPECT_TRUE(fdes[1]->cie != nullptr);
+
+ EXPECT_EQ(0x5300U, fdes[2]->cie_offset);
+ EXPECT_EQ(0x5424U, fdes[2]->cfa_instructions_offset);
+ EXPECT_EQ(0x5500U, fdes[2]->cfa_instructions_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0U, fdes[2]->lsda_address);
+ EXPECT_TRUE(fdes[2]->cie != nullptr);
+
+ EXPECT_EQ(0x5300U, fdes[3]->cie_offset);
+ EXPECT_EQ(0x5524U, fdes[3]->cfa_instructions_offset);
+ EXPECT_EQ(0x5600U, fdes[3]->cfa_instructions_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+ EXPECT_EQ(0U, fdes[3]->lsda_address);
+ EXPECT_TRUE(fdes[3]->cie != nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_after_GetFdeFromPc) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+ EXPECT_EQ(0x2800U, fde->pc_end);
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+ ASSERT_EQ(4U, fdes.size());
+
+ // Verify that they got added in the correct order.
+ EXPECT_EQ(0x1500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x1700U, fdes[0]->pc_end);
+ EXPECT_EQ(0x2500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x2800U, fdes[1]->pc_end);
+ EXPECT_EQ(0x3500U, fdes[2]->pc_start);
+ EXPECT_EQ(0x3900U, fdes[2]->pc_end);
+ EXPECT_EQ(0x4500U, fdes[3]->pc_start);
+ EXPECT_EQ(0x4a00U, fdes[3]->pc_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdes64_not_in_section) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
+
+ std::vector<const DwarfFde*> fdes;
+ this->debug_frame_->GetFdes(&fdes);
+
+ ASSERT_EQ(3U, fdes.size());
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_reverse) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x600, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x3600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x3500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x2600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x2500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0x1600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x1500U, fde->pc_start);
+
+ fde = this->debug_frame_->GetFdeFromPc(0);
+ ASSERT_TRUE(fde == nullptr);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc64_not_in_section) {
+ SetFourFdes64(&this->memory_);
+ ASSERT_TRUE(this->debug_frame_->Init(0x5000, 0x500, 0));
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde == nullptr);
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde32) {
- this->debug_frame_->TestSetOffset(0x4000);
-
- // CIE 32 information.
- this->memory_.SetData32(0xf000, 0x100);
- this->memory_.SetData32(0xf004, 0xffffffff);
- this->memory_.SetData8(0xf008, 0x1);
- this->memory_.SetData8(0xf009, '\0');
- this->memory_.SetData8(0xf00a, 4);
- this->memory_.SetData8(0xf00b, 8);
- this->memory_.SetData8(0xf00c, 0x20);
-
- // FDE 32 information.
- this->memory_.SetData32(0x14000, 0x20);
- this->memory_.SetData32(0x14004, 0xb000);
- this->memory_.SetData32(0x14008, 0x9000);
- this->memory_.SetData32(0x1400c, 0x100);
+ SetCie32(&this->memory_, 0xf000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ SetFde32(&this->memory_, 0x14000, 0x20, 0xf000, 0x9000, 0x100);
const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x14000);
ASSERT_TRUE(fde != nullptr);
@@ -530,24 +428,8 @@
}
TYPED_TEST_P(DwarfDebugFrameTest, GetCieFde64) {
- this->debug_frame_->TestSetOffset(0x2000);
-
- // CIE 64 information.
- this->memory_.SetData32(0x6000, 0xffffffff);
- this->memory_.SetData64(0x6004, 0x100);
- this->memory_.SetData64(0x600c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x6014, 0x1);
- this->memory_.SetData8(0x6015, '\0');
- this->memory_.SetData8(0x6016, 4);
- this->memory_.SetData8(0x6017, 8);
- this->memory_.SetData8(0x6018, 0x20);
-
- // FDE 64 information.
- this->memory_.SetData32(0x8000, 0xffffffff);
- this->memory_.SetData64(0x8004, 0x200);
- this->memory_.SetData64(0x800c, 0x4000);
- this->memory_.SetData64(0x8014, 0x5000);
- this->memory_.SetData64(0x801c, 0x300);
+ SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ SetFde64(&this->memory_, 0x8000, 0x200, 0x6000, 0x5000, 0x300);
const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x8000);
ASSERT_TRUE(fde != nullptr);
@@ -573,11 +455,357 @@
EXPECT_EQ(0x20U, fde->cie->return_address_register);
}
-REGISTER_TYPED_TEST_CASE_P(DwarfDebugFrameTest, Init32, Init32_fde_not_following_cie,
- Init32_do_not_fail_on_bad_next_entry, Init64,
- Init64_do_not_fail_on_bad_next_entry, Init64_fde_not_following_cie,
- Init_non_zero_load_bias, Init_version1, Init_version4,
- GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+static void VerifyCieVersion(const DwarfCie* cie, uint8_t version, uint8_t segment_size,
+ uint8_t fde_encoding, uint64_t return_address, uint64_t start_offset,
+ uint64_t end_offset) {
+ EXPECT_EQ(version, cie->version);
+ EXPECT_EQ(fde_encoding, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+ EXPECT_EQ(segment_size, cie->segment_size);
+ EXPECT_EQ(1U, cie->augmentation_string.size());
+ EXPECT_EQ('\0', cie->augmentation_string[0]);
+ EXPECT_EQ(0U, cie->personality_handler);
+ EXPECT_EQ(4U, cie->code_alignment_factor);
+ EXPECT_EQ(8, cie->data_alignment_factor);
+ EXPECT_EQ(return_address, cie->return_address_register);
+ EXPECT_EQ(0x5000U + start_offset, cie->cfa_instructions_offset);
+ EXPECT_EQ(0x5000U + end_offset, cie->cfa_instructions_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_cie_cached) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+
+ std::vector<uint8_t> zero(0x100, 0);
+ this->memory_.SetMemory(0x5000, zero);
+ cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_cie_cached) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+
+ std::vector<uint8_t> zero(0x100, 0);
+ this->memory_.SetMemory(0x5000, zero);
+ cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version1) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata4, 0x20, 0xd, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version1) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 1, 0, DW_EH_PE_sdata8, 0x20, 0x19, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version3) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata4, 0x181, 0xe, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version3) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{3, '\0', 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 3, 0, DW_EH_PE_sdata8, 0x181, 0x1a, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_version4) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata4, 0x181, 0x10, 0x104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_version4) {
+ SetCie64(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{4, '\0', 0, 10, 4, 8, 0x81, 3});
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ EXPECT_EQ(DWARF_ERROR_NONE, this->debug_frame_->LastErrorCode());
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieVersion(cie, 4, 10, DW_EH_PE_sdata8, 0x181, 0x1c, 0x10c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset_version_invalid) {
+ SetCie32(&this->memory_, 0x5000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x5000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+ SetCie64(&this->memory_, 0x6000, 0x100, std::vector<uint8_t>{0, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x6000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+
+ SetCie32(&this->memory_, 0x7000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x7000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+ SetCie64(&this->memory_, 0x8000, 0x100, std::vector<uint8_t>{5, '\0', 1, 2, 3, 4, 5, 6, 7});
+ ASSERT_TRUE(this->debug_frame_->GetCieFromOffset(0x8000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->debug_frame_->LastErrorCode());
+}
+
+static void VerifyCieAugment(const DwarfCie* cie, uint64_t inst_offset, uint64_t inst_end) {
+ EXPECT_EQ(1U, cie->version);
+ EXPECT_EQ(DW_EH_PE_udata2, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_textrel | DW_EH_PE_udata2, cie->lsda_encoding);
+ EXPECT_EQ(0U, cie->segment_size);
+ EXPECT_EQ(5U, cie->augmentation_string.size());
+ EXPECT_EQ('z', cie->augmentation_string[0]);
+ EXPECT_EQ('L', cie->augmentation_string[1]);
+ EXPECT_EQ('P', cie->augmentation_string[2]);
+ EXPECT_EQ('R', cie->augmentation_string[3]);
+ EXPECT_EQ('\0', cie->augmentation_string[4]);
+ EXPECT_EQ(0x12345678U, cie->personality_handler);
+ EXPECT_EQ(4U, cie->code_alignment_factor);
+ EXPECT_EQ(8, cie->data_alignment_factor);
+ EXPECT_EQ(0x10U, cie->return_address_register);
+ EXPECT_EQ(inst_offset, cie->cfa_instructions_offset);
+ EXPECT_EQ(inst_end, cie->cfa_instructions_end);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset32_augment) {
+ SetCie32(&this->memory_, 0x5000, 0x100,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', 'P', 'R', '\0',
+ /* code alignment factor */ 4,
+ /* data alignment factor */ 8,
+ /* return address register */ 0x10,
+ /* augment length */ 0xf,
+ /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
+ /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
+ /* R data */ DW_EH_PE_udata2});
+
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieAugment(cie, 0x5021, 0x5104);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetCieFromOffset64_augment) {
+ SetCie64(&this->memory_, 0x5000, 0x100,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', 'P', 'R', '\0',
+ /* code alignment factor */ 4,
+ /* data alignment factor */ 8,
+ /* return address register */ 0x10,
+ /* augment length */ 0xf,
+ /* L data */ DW_EH_PE_textrel | DW_EH_PE_udata2,
+ /* P data */ DW_EH_PE_udata4, 0x78, 0x56, 0x34, 0x12,
+ /* R data */ DW_EH_PE_udata2});
+
+ const DwarfCie* cie = this->debug_frame_->GetCieFromOffset(0x5000);
+ ASSERT_TRUE(cie != nullptr);
+ VerifyCieAugment(cie, 0x502d, 0x510c);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_augment) {
+ SetCie32(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 4,
+ /* augment string */ 'z', '\0',
+ /* address size */ 8,
+ /* segment size */ 0x10,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x0});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
+ SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(4U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x53a2U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_augment) {
+ SetCie64(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 4,
+ /* augment string */ 'z', '\0',
+ /* address size */ 8,
+ /* segment size */ 0x10,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x0});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3};
+ SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0x10, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(4U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x53b6U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset32_lsda_address) {
+ SetCie32(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', '\0',
+ /* address size */ 8,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x2,
+ /* L data */ DW_EH_PE_udata2});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
+ /* lsda address */ 0x20, 0x45};
+ SetFde32(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(1U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x5392U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5504U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0x4520U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromOffset64_lsda_address) {
+ SetCie64(&this->memory_, 0x5000, 0xfc,
+ std::vector<uint8_t>{/* version */ 1,
+ /* augment string */ 'z', 'L', '\0',
+ /* address size */ 8,
+ /* code alignment factor */ 16,
+ /* data alignment factor */ 32,
+ /* return address register */ 10,
+ /* augment length */ 0x2,
+ /* L data */ DW_EH_PE_udata2});
+
+ std::vector<uint8_t> data{/* augment length */ 0x80, 0x3,
+ /* lsda address */ 0x20, 0x45};
+ SetFde64(&this->memory_, 0x5200, 0x300, 0x5000, 0x4300, 0x300, 0, &data);
+
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromOffset(0x5200);
+ ASSERT_TRUE(fde != nullptr);
+ ASSERT_TRUE(fde->cie != nullptr);
+ EXPECT_EQ(1U, fde->cie->version);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x53a6U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x550cU, fde->cfa_instructions_end);
+ EXPECT_EQ(0x4300U, fde->pc_start);
+ EXPECT_EQ(0x4600U, fde->pc_end);
+ EXPECT_EQ(0x4520U, fde->lsda_address);
+}
+
+TYPED_TEST_P(DwarfDebugFrameTest, GetFdeFromPc_interleaved) {
+ SetCie32(&this->memory_, 0x5000, 0xfc, std::vector<uint8_t>{1, '\0', 0, 0, 1});
+
+ // FDE 0 (0x100 - 0x200)
+ SetFde32(&this->memory_, 0x5100, 0xfc, 0, 0x100, 0x100);
+ // FDE 1 (0x300 - 0x500)
+ SetFde32(&this->memory_, 0x5200, 0xfc, 0, 0x300, 0x200);
+ // FDE 2 (0x700 - 0x800)
+ SetFde32(&this->memory_, 0x5300, 0xfc, 0, 0x700, 0x100);
+ // FDE 3 (0xa00 - 0xb00)
+ SetFde32(&this->memory_, 0x5400, 0xfc, 0, 0xa00, 0x100);
+ // FDE 4 (0x100 - 0xb00)
+ SetFde32(&this->memory_, 0x5500, 0xfc, 0, 0x150, 0xa00);
+ // FDE 5 (0x0 - 0x50)
+ SetFde32(&this->memory_, 0x5600, 0xfc, 0, 0, 0x50);
+
+ this->debug_frame_->Init(0x5000, 0x700, 0);
+
+ // Force reading all entries so no entries are found.
+ const DwarfFde* fde = this->debug_frame_->GetFdeFromPc(0xfffff);
+ ASSERT_TRUE(fde == nullptr);
+
+ // 0x0 - 0x50 FDE 5
+ fde = this->debug_frame_->GetFdeFromPc(0x10);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0U, fde->pc_start);
+ EXPECT_EQ(0x50U, fde->pc_end);
+
+ // 0x100 - 0x200 FDE 0
+ fde = this->debug_frame_->GetFdeFromPc(0x170);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x100U, fde->pc_start);
+ EXPECT_EQ(0x200U, fde->pc_end);
+
+ // 0x200 - 0x300 FDE 4
+ fde = this->debug_frame_->GetFdeFromPc(0x210);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x150U, fde->pc_start);
+ EXPECT_EQ(0xb50U, fde->pc_end);
+
+ // 0x300 - 0x500 FDE 1
+ fde = this->debug_frame_->GetFdeFromPc(0x310);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x300U, fde->pc_start);
+ EXPECT_EQ(0x500U, fde->pc_end);
+
+ // 0x700 - 0x800 FDE 2
+ fde = this->debug_frame_->GetFdeFromPc(0x790);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x700U, fde->pc_start);
+ EXPECT_EQ(0x800U, fde->pc_end);
+
+ // 0x800 - 0x900 FDE 4
+ fde = this->debug_frame_->GetFdeFromPc(0x850);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x150U, fde->pc_start);
+ EXPECT_EQ(0xb50U, fde->pc_end);
+
+ // 0xa00 - 0xb00 FDE 3
+ fde = this->debug_frame_->GetFdeFromPc(0xa35);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0xa00U, fde->pc_start);
+ EXPECT_EQ(0xb00U, fde->pc_end);
+
+ // 0xb00 - 0xb50 FDE 4
+ fde = this->debug_frame_->GetFdeFromPc(0xb20);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x150U, fde->pc_start);
+ EXPECT_EQ(0xb50U, fde->pc_end);
+}
+
+REGISTER_TYPED_TEST_CASE_P(
+ DwarfDebugFrameTest, GetFdes32, GetFdes32_after_GetFdeFromPc, GetFdes32_not_in_section,
+ GetFdeFromPc32, GetFdeFromPc32_reverse, GetFdeFromPc32_not_in_section, GetFdes64,
+ GetFdes64_after_GetFdeFromPc, GetFdes64_not_in_section, GetFdeFromPc64, GetFdeFromPc64_reverse,
+ GetFdeFromPc64_not_in_section, GetCieFde32, GetCieFde64, GetCieFromOffset32_cie_cached,
+ GetCieFromOffset64_cie_cached, GetCieFromOffset32_version1, GetCieFromOffset64_version1,
+ GetCieFromOffset32_version3, GetCieFromOffset64_version3, GetCieFromOffset32_version4,
+ GetCieFromOffset64_version4, GetCieFromOffset_version_invalid, GetCieFromOffset32_augment,
+ GetCieFromOffset64_augment, GetFdeFromOffset32_augment, GetFdeFromOffset64_augment,
+ GetFdeFromOffset32_lsda_address, GetFdeFromOffset64_lsda_address, GetFdeFromPc_interleaved);
typedef ::testing::Types<uint32_t, uint64_t> DwarfDebugFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfDebugFrameTest, DwarfDebugFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameTest.cpp b/libunwindstack/tests/DwarfEhFrameTest.cpp
index e8d53e6..9cac6e8 100644
--- a/libunwindstack/tests/DwarfEhFrameTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameTest.cpp
@@ -16,7 +16,6 @@
#include <stdint.h>
-#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
@@ -30,50 +29,32 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfEhFrame : public DwarfEhFrame<TypeParam> {
- public:
- MockDwarfEhFrame(Memory* memory) : DwarfEhFrame<TypeParam>(memory) {}
- ~MockDwarfEhFrame() = default;
-
- void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
- void TestSetOffset(uint64_t offset) { this->entries_offset_ = offset; }
- void TestSetEndOffset(uint64_t offset) { this->entries_end_ = offset; }
- void TestPushFdeInfo(const typename DwarfEhFrame<TypeParam>::FdeInfo& info) {
- this->fdes_.push_back(info);
- }
-
- uint64_t TestGetFdeCount() { return this->fde_count_; }
- uint8_t TestGetOffset() { return this->offset_; }
- uint8_t TestGetEndOffset() { return this->end_offset_; }
- void TestGetFdeInfo(size_t index, typename DwarfEhFrame<TypeParam>::FdeInfo* info) {
- *info = this->fdes_[index];
- }
-};
-
-template <typename TypeParam>
class DwarfEhFrameTest : public ::testing::Test {
protected:
void SetUp() override {
memory_.Clear();
- eh_frame_ = new MockDwarfEhFrame<TypeParam>(&memory_);
+ eh_frame_ = new DwarfEhFrame<TypeParam>(&memory_);
ResetLogs();
}
void TearDown() override { delete eh_frame_; }
MemoryFake memory_;
- MockDwarfEhFrame<TypeParam>* eh_frame_ = nullptr;
+ DwarfEhFrame<TypeParam>* eh_frame_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfEhFrameTest);
// NOTE: All test class variables need to be referenced as this->.
-TYPED_TEST_P(DwarfEhFrameTest, Init32) {
+// Only verify different cie/fde format. All other DwarfSection corner
+// cases are tested in DwarfDebugFrameTest.cpp.
+
+TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset32) {
// CIE 32 information.
this->memory_.SetData32(0x5000, 0xfc);
+ // Indicates this is a cie for eh_frame.
this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
+ this->memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 16, 32, 1});
// FDE 32 information.
this->memory_.SetData32(0x5100, 0xfc);
@@ -81,415 +62,70 @@
this->memory_.SetData32(0x5108, 0x1500);
this->memory_.SetData32(0x510c, 0x200);
- this->memory_.SetData32(0x5200, 0xfc);
- this->memory_.SetData32(0x5204, 0x204);
- this->memory_.SetData32(0x5208, 0x2500);
- this->memory_.SetData32(0x520c, 0x300);
+ const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x5110U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5200U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x6608U, fde->pc_start);
+ EXPECT_EQ(0x6808U, fde->pc_end);
+ EXPECT_EQ(0U, fde->lsda_address);
- // CIE 32 information.
- this->memory_.SetData32(0x5300, 0xfc);
- this->memory_.SetData32(0x5304, 0);
- this->memory_.SetData8(0x5308, 1);
- this->memory_.SetData8(0x5309, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5400, 0xfc);
- this->memory_.SetData32(0x5404, 0x104);
- this->memory_.SetData32(0x5408, 0x3500);
- this->memory_.SetData32(0x540c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xfc);
- this->memory_.SetData32(0x5504, 0x204);
- this->memory_.SetData32(0x5508, 0x4500);
- this->memory_.SetData32(0x550c, 0x500);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6608U, info.start);
- EXPECT_EQ(0x6808U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x7708U, info.start);
- EXPECT_EQ(0x7a08U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x8908U, info.start);
- EXPECT_EQ(0x8d08U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x9a08U, info.start);
- EXPECT_EQ(0x9f08U, info.end);
+ const DwarfCie* cie = fde->cie;
+ ASSERT_TRUE(cie != nullptr);
+ EXPECT_EQ(1U, cie->version);
+ EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+ EXPECT_EQ(0U, cie->segment_size);
+ EXPECT_EQ('\0', cie->augmentation_string[0]);
+ EXPECT_EQ(0U, cie->personality_handler);
+ EXPECT_EQ(0x500dU, cie->cfa_instructions_offset);
+ EXPECT_EQ(0x5100U, cie->cfa_instructions_end);
+ EXPECT_EQ(16U, cie->code_alignment_factor);
+ EXPECT_EQ(32U, cie->data_alignment_factor);
+ EXPECT_EQ(1U, cie->return_address_register);
}
-TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, '\0');
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x1000);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
-
- ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init64) {
+TYPED_TEST_P(DwarfEhFrameTest, GetFdeCieFromOffset64) {
// CIE 64 information.
this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
+ this->memory_.SetData64(0x5004, 0xfc);
+ // Indicates this is a cie for eh_frame.
this->memory_.SetData64(0x500c, 0);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
+ this->memory_.SetMemory(0x5014, std::vector<uint8_t>{1, '\0', 16, 32, 1});
// FDE 64 information.
this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
+ this->memory_.SetData64(0x5104, 0xfc);
this->memory_.SetData64(0x510c, 0x10c);
this->memory_.SetData64(0x5114, 0x1500);
this->memory_.SetData64(0x511c, 0x200);
- this->memory_.SetData32(0x5200, 0xffffffff);
- this->memory_.SetData64(0x5204, 0xf4);
- this->memory_.SetData64(0x520c, 0x20c);
- this->memory_.SetData64(0x5214, 0x2500);
- this->memory_.SetData64(0x521c, 0x300);
-
- // CIE 64 information.
- this->memory_.SetData32(0x5300, 0xffffffff);
- this->memory_.SetData64(0x5304, 0xf4);
- this->memory_.SetData64(0x530c, 0);
- this->memory_.SetData8(0x5314, 1);
- this->memory_.SetData8(0x5315, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5400, 0xffffffff);
- this->memory_.SetData64(0x5404, 0xf4);
- this->memory_.SetData64(0x540c, 0x10c);
- this->memory_.SetData64(0x5414, 0x3500);
- this->memory_.SetData64(0x541c, 0x400);
-
- this->memory_.SetData32(0x5500, 0xffffffff);
- this->memory_.SetData64(0x5504, 0xf4);
- this->memory_.SetData64(0x550c, 0x20c);
- this->memory_.SetData64(0x5514, 0x4500);
- this->memory_.SetData64(0x551c, 0x500);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(4U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6618U, info.start);
- EXPECT_EQ(0x6818U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(1, &info);
- EXPECT_EQ(0x5200U, info.offset);
- EXPECT_EQ(0x7718U, info.start);
- EXPECT_EQ(0x7a18U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(2, &info);
- EXPECT_EQ(0x5400U, info.offset);
- EXPECT_EQ(0x8918U, info.start);
- EXPECT_EQ(0x8d18U, info.end);
-
- this->eh_frame_->TestGetFdeInfo(3, &info);
- EXPECT_EQ(0x5500U, info.offset);
- EXPECT_EQ(0x9a18U, info.start);
- EXPECT_EQ(0x9f18U, info.end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) {
- // CIE 64 information.
- this->memory_.SetData32(0x5000, 0xffffffff);
- this->memory_.SetData64(0x5004, 0xf4);
- this->memory_.SetData64(0x500c, 0);
- this->memory_.SetData8(0x5014, 1);
- this->memory_.SetData8(0x5015, '\0');
-
- // FDE 64 information.
- this->memory_.SetData32(0x5100, 0xffffffff);
- this->memory_.SetData64(0x5104, 0xf4);
- this->memory_.SetData64(0x510c, 0x1000);
- this->memory_.SetData64(0x5114, 0x1500);
- this->memory_.SetData64(0x511c, 0x200);
-
- ASSERT_FALSE(this->eh_frame_->Init(0x5000, 0x600, 0));
- ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->eh_frame_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init_non_zero_load_bias) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- this->memory_.SetData8(0x5009, 'z');
- this->memory_.SetData8(0x500a, 'R');
- this->memory_.SetData8(0x500b, '\0');
- this->memory_.SetData8(0x500c, 0);
- this->memory_.SetData8(0x500d, 0);
- this->memory_.SetData8(0x500e, 0);
- this->memory_.SetData8(0x500f, 0);
- this->memory_.SetData8(0x5010, 0x1b);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x104);
- this->memory_.SetData32(0x5108, 0x1500);
- this->memory_.SetData32(0x510c, 0x200);
- this->memory_.SetData8(0x5110, 0);
- this->memory_.SetData8(0x5111, 0);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0x2000));
- ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
-
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x8608U, info.start);
- EXPECT_EQ(0x8808U, info.end);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x8700);
+ const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x5100);
ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x8608U, fde->pc_start);
- EXPECT_EQ(0x8808U, fde->pc_end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 1);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'R', 'P', 'L', '\0'});
- // Code alignment factor.
- this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetData8(0x5014, 0x84);
- // Augmentation length
- this->memory_.SetMemory(0x5015, std::vector<uint8_t>{0x84, 0x00});
- // R data.
- this->memory_.SetData8(0x5017, DW_EH_PE_pcrel | DW_EH_PE_udata2);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x104);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6606U, info.start);
- EXPECT_EQ(0x6806U, info.end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
- // CIE 32 information.
- this->memory_.SetData32(0x5000, 0xfc);
- this->memory_.SetData32(0x5004, 0);
- this->memory_.SetData8(0x5008, 4);
- // Augment string.
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
- // Address size.
- this->memory_.SetData8(0x500e, 4);
- // Segment size.
- this->memory_.SetData8(0x500f, 0);
- // Code alignment factor.
- this->memory_.SetMemory(0x5010, std::vector<uint8_t>{0x80, 0x00});
- // Data alignment factor.
- this->memory_.SetMemory(0x5012, std::vector<uint8_t>{0x81, 0x80, 0x80, 0x00});
- // Return address register
- this->memory_.SetMemory(0x5016, std::vector<uint8_t>{0x85, 0x10});
- // Augmentation length
- this->memory_.SetMemory(0x5018, std::vector<uint8_t>{0x84, 0x00});
- // L data.
- this->memory_.SetData8(0x501a, 0x10);
- // P data.
- this->memory_.SetData8(0x501b, DW_EH_PE_udata4);
- this->memory_.SetData32(0x501c, 0x100);
- // R data.
- this->memory_.SetData8(0x5020, DW_EH_PE_pcrel | DW_EH_PE_udata2);
-
- // FDE 32 information.
- this->memory_.SetData32(0x5100, 0xfc);
- this->memory_.SetData32(0x5104, 0x104);
- this->memory_.SetData16(0x5108, 0x1500);
- this->memory_.SetData16(0x510a, 0x200);
-
- ASSERT_TRUE(this->eh_frame_->Init(0x5000, 0x200, 0));
- ASSERT_EQ(1U, this->eh_frame_->TestGetFdeCount());
-
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
- this->eh_frame_->TestGetFdeInfo(0, &info);
- EXPECT_EQ(0x5100U, info.offset);
- EXPECT_EQ(0x6606U, info.start);
- EXPECT_EQ(0x6806U, info.end);
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) {
- typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
- for (size_t i = 0; i < 9; i++) {
- info.start = 0x1000 * (i + 1);
- info.end = 0x1000 * (i + 2) - 0x10;
- info.offset = 0x5000 + i * 0x20;
- this->eh_frame_->TestPushFdeInfo(info);
- }
-
- this->eh_frame_->TestSetFdeCount(0);
- uint64_t fde_offset;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x1000, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
-
- this->eh_frame_->TestSetFdeCount(9);
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(0x100, &fde_offset));
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
- // Odd number of elements.
- for (size_t i = 0; i < 9; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
- }
-
- // Even number of elements.
- this->eh_frame_->TestSetFdeCount(10);
- info.start = 0xa000;
- info.end = 0xaff0;
- info.offset = 0x5120;
- this->eh_frame_->TestPushFdeInfo(info);
-
- for (size_t i = 0; i < 10; i++) {
- TypeParam pc = 0x1000 * (i + 1);
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 1, &fde_offset)) << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_TRUE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xeff, &fde_offset))
- << "Failed at index " << i;
- EXPECT_EQ(0x5000 + i * 0x20, fde_offset) << "Failed at index " << i;
- ASSERT_FALSE(this->eh_frame_->GetFdeOffsetFromPc(pc + 0xfff, &fde_offset))
- << "Failed at index " << i;
- ASSERT_EQ(DWARF_ERROR_NONE, this->eh_frame_->LastErrorCode());
- }
-}
-
-TYPED_TEST_P(DwarfEhFrameTest, GetCieFde32) {
- this->eh_frame_->TestSetOffset(0x4000);
-
- // CIE 32 information.
- this->memory_.SetData32(0xf000, 0x100);
- this->memory_.SetData32(0xf004, 0);
- this->memory_.SetData8(0xf008, 0x1);
- this->memory_.SetData8(0xf009, '\0');
- this->memory_.SetData8(0xf00a, 4);
- this->memory_.SetData8(0xf00b, 8);
- this->memory_.SetData8(0xf00c, 0x20);
-
- // FDE 32 information.
- this->memory_.SetData32(0x14000, 0x20);
- this->memory_.SetData32(0x14004, 0x5004);
- this->memory_.SetData32(0x14008, 0x9000);
- this->memory_.SetData32(0x1400c, 0x100);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x14000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x1d008U, fde->pc_start);
- EXPECT_EQ(0x1d108U, fde->pc_end);
- EXPECT_EQ(0xf000U, fde->cie_offset);
+ EXPECT_EQ(0x5000U, fde->cie_offset);
+ EXPECT_EQ(0x5124U, fde->cfa_instructions_offset);
+ EXPECT_EQ(0x5208U, fde->cfa_instructions_end);
+ EXPECT_EQ(0x6618U, fde->pc_start);
+ EXPECT_EQ(0x6818U, fde->pc_end);
EXPECT_EQ(0U, fde->lsda_address);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0xf00dU, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0xf104U, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
+ const DwarfCie* cie = fde->cie;
+ ASSERT_TRUE(cie != nullptr);
+ EXPECT_EQ(1U, cie->version);
+ EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
+ EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
+ EXPECT_EQ(0U, cie->segment_size);
+ EXPECT_EQ('\0', cie->augmentation_string[0]);
+ EXPECT_EQ(0U, cie->personality_handler);
+ EXPECT_EQ(0x5019U, cie->cfa_instructions_offset);
+ EXPECT_EQ(0x5108U, cie->cfa_instructions_end);
+ EXPECT_EQ(16U, cie->code_alignment_factor);
+ EXPECT_EQ(32U, cie->data_alignment_factor);
+ EXPECT_EQ(1U, cie->return_address_register);
}
-TYPED_TEST_P(DwarfEhFrameTest, GetCieFde64) {
- this->eh_frame_->TestSetOffset(0x2000);
-
- // CIE 64 information.
- this->memory_.SetData32(0x6000, 0xffffffff);
- this->memory_.SetData64(0x6004, 0x100);
- this->memory_.SetData64(0x600c, 0);
- this->memory_.SetData8(0x6014, 0x1);
- this->memory_.SetData8(0x6015, '\0');
- this->memory_.SetData8(0x6016, 4);
- this->memory_.SetData8(0x6017, 8);
- this->memory_.SetData8(0x6018, 0x20);
-
- // FDE 64 information.
- this->memory_.SetData32(0x8000, 0xffffffff);
- this->memory_.SetData64(0x8004, 0x200);
- this->memory_.SetData64(0x800c, 0x200c);
- this->memory_.SetData64(0x8014, 0x5000);
- this->memory_.SetData64(0x801c, 0x300);
-
- const DwarfFde* fde = this->eh_frame_->GetFdeFromOffset(0x8000);
- ASSERT_TRUE(fde != nullptr);
- EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
- EXPECT_EQ(0xd018U, fde->pc_start);
- EXPECT_EQ(0xd318U, fde->pc_end);
- EXPECT_EQ(0x6000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(1U, fde->cie->version);
- EXPECT_EQ(DW_EH_PE_sdata8, fde->cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, fde->cie->lsda_encoding);
- EXPECT_EQ(0U, fde->cie->segment_size);
- EXPECT_EQ(1U, fde->cie->augmentation_string.size());
- EXPECT_EQ('\0', fde->cie->augmentation_string[0]);
- EXPECT_EQ(0U, fde->cie->personality_handler);
- EXPECT_EQ(0x6019U, fde->cie->cfa_instructions_offset);
- EXPECT_EQ(0x610cU, fde->cie->cfa_instructions_end);
- EXPECT_EQ(4U, fde->cie->code_alignment_factor);
- EXPECT_EQ(8, fde->cie->data_alignment_factor);
- EXPECT_EQ(0x20U, fde->cie->return_address_register);
-}
-
-REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, Init32, Init32_fde_not_following_cie, Init64,
- Init64_fde_not_following_cie, Init_non_zero_load_bias, Init_version1,
- Init_version4, GetFdeOffsetFromPc, GetCieFde32, GetCieFde64);
+REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameTest, GetFdeCieFromOffset32, GetFdeCieFromOffset64);
typedef ::testing::Types<uint32_t, uint64_t> DwarfEhFrameTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfEhFrameTest, DwarfEhFrameTestTypes);
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 19c7b98..910ae36 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -30,10 +30,10 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
+class TestDwarfEhFrameWithHdr : public DwarfEhFrameWithHdr<TypeParam> {
public:
- MockDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
- ~MockDwarfEhFrameWithHdr() = default;
+ TestDwarfEhFrameWithHdr(Memory* memory) : DwarfEhFrameWithHdr<TypeParam>(memory) {}
+ ~TestDwarfEhFrameWithHdr() = default;
void TestSetTableEncoding(uint8_t encoding) { this->table_encoding_ = encoding; }
void TestSetEntriesOffset(uint64_t offset) { this->entries_offset_ = offset; }
@@ -64,14 +64,14 @@
protected:
void SetUp() override {
memory_.Clear();
- eh_frame_ = new MockDwarfEhFrameWithHdr<TypeParam>(&memory_);
+ eh_frame_ = new TestDwarfEhFrameWithHdr<TypeParam>(&memory_);
ResetLogs();
}
void TearDown() override { delete eh_frame_; }
MemoryFake memory_;
- MockDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
+ TestDwarfEhFrameWithHdr<TypeParam>* eh_frame_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest);
@@ -121,23 +121,14 @@
// CIE 32 information.
this->memory_.SetData32(0x1300, 0xfc);
this->memory_.SetData32(0x1304, 0);
- this->memory_.SetData8(0x1308, 1);
- this->memory_.SetData8(0x1309, 'z');
- this->memory_.SetData8(0x130a, 'R');
- this->memory_.SetData8(0x130b, '\0');
- this->memory_.SetData8(0x130c, 0);
- this->memory_.SetData8(0x130d, 0);
- this->memory_.SetData8(0x130e, 0);
- this->memory_.SetData8(0x130f, 0);
- this->memory_.SetData8(0x1310, 0x1b);
+ this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
// FDE 32 information.
this->memory_.SetData32(0x1400, 0xfc);
this->memory_.SetData32(0x1404, 0x104);
this->memory_.SetData32(0x1408, 0x10f8);
this->memory_.SetData32(0x140c, 0x200);
- this->memory_.SetData8(0x1410, 0);
- this->memory_.SetData8(0x1411, 0);
+ this->memory_.SetData16(0x1410, 0);
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
@@ -157,6 +148,68 @@
EXPECT_EQ(0x4700U, fde->pc_end);
}
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes) {
+ this->memory_.SetMemory(
+ 0x1000, std::vector<uint8_t>{1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
+ this->memory_.SetData16(0x1004, 0x500);
+ this->memory_.SetData32(0x1006, 4);
+
+ // Header information.
+ this->memory_.SetData32(0x100a, 0x4600);
+ this->memory_.SetData32(0x100e, 0x1500);
+ this->memory_.SetData32(0x1012, 0x5500);
+ this->memory_.SetData32(0x1016, 0x1400);
+ this->memory_.SetData32(0x101a, 0x6800);
+ this->memory_.SetData32(0x101e, 0x1700);
+ this->memory_.SetData32(0x1022, 0x7700);
+ this->memory_.SetData32(0x1026, 0x1600);
+
+ // CIE 32 information.
+ this->memory_.SetData32(0x1300, 0xfc);
+ this->memory_.SetData32(0x1304, 0);
+ this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, '\0', 0, 0, 0});
+
+ // FDE 32 information.
+ // pc 0x5500 - 0x5700
+ this->memory_.SetData32(0x1400, 0xfc);
+ this->memory_.SetData32(0x1404, 0x104);
+ this->memory_.SetData32(0x1408, 0x40f8);
+ this->memory_.SetData32(0x140c, 0x200);
+
+ // pc 0x4600 - 0x4800
+ this->memory_.SetData32(0x1500, 0xfc);
+ this->memory_.SetData32(0x1504, 0x204);
+ this->memory_.SetData32(0x1508, 0x30f8);
+ this->memory_.SetData32(0x150c, 0x200);
+
+ // pc 0x7700 - 0x7900
+ this->memory_.SetData32(0x1600, 0xfc);
+ this->memory_.SetData32(0x1604, 0x304);
+ this->memory_.SetData32(0x1608, 0x60f8);
+ this->memory_.SetData32(0x160c, 0x200);
+
+ // pc 0x6800 - 0x6a00
+ this->memory_.SetData32(0x1700, 0xfc);
+ this->memory_.SetData32(0x1704, 0x404);
+ this->memory_.SetData32(0x1708, 0x50f8);
+ this->memory_.SetData32(0x170c, 0x200);
+
+ ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
+
+ std::vector<const DwarfFde*> fdes;
+ this->eh_frame_->GetFdes(&fdes);
+ ASSERT_EQ(4U, fdes.size());
+
+ EXPECT_EQ(0x4600U, fdes[0]->pc_start);
+ EXPECT_EQ(0x4800U, fdes[0]->pc_end);
+ EXPECT_EQ(0x5500U, fdes[1]->pc_start);
+ EXPECT_EQ(0x5700U, fdes[1]->pc_end);
+ EXPECT_EQ(0x6800U, fdes[2]->pc_start);
+ EXPECT_EQ(0x6a00U, fdes[2]->pc_end);
+ EXPECT_EQ(0x7700U, fdes[3]->pc_start);
+ EXPECT_EQ(0x7900U, fdes[3]->pc_end);
+}
+
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
this->eh_frame_->TestSetTableEntrySize(0x10);
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
@@ -388,11 +441,7 @@
// CIE 32 information.
this->memory_.SetData32(0xf000, 0x100);
this->memory_.SetData32(0xf004, 0);
- this->memory_.SetData8(0xf008, 0x1);
- this->memory_.SetData8(0xf009, '\0');
- this->memory_.SetData8(0xf00a, 4);
- this->memory_.SetData8(0xf00b, 8);
- this->memory_.SetData8(0xf00c, 0x20);
+ this->memory_.SetMemory(0xf008, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
// FDE 32 information.
this->memory_.SetData32(0x14000, 0x20);
@@ -429,11 +478,7 @@
this->memory_.SetData32(0x6000, 0xffffffff);
this->memory_.SetData64(0x6004, 0x100);
this->memory_.SetData64(0x600c, 0);
- this->memory_.SetData8(0x6014, 0x1);
- this->memory_.SetData8(0x6015, '\0');
- this->memory_.SetData8(0x6016, 4);
- this->memory_.SetData8(0x6017, 8);
- this->memory_.SetData8(0x6018, 0x20);
+ this->memory_.SetMemory(0x6014, std::vector<uint8_t>{1, '\0', 4, 8, 0x20});
// FDE 64 information.
this->memory_.SetData32(0x8000, 0xffffffff);
@@ -478,7 +523,7 @@
ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
}
-REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias,
+REGISTER_TYPED_TEST_CASE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias, GetFdes,
GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
GetFdeOffsetBinary_verify, GetFdeOffsetBinary_index_fail,
diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp
index 414f2f2..46f555a 100644
--- a/libunwindstack/tests/DwarfSectionImplTest.cpp
+++ b/libunwindstack/tests/DwarfSectionImplTest.cpp
@@ -16,7 +16,6 @@
#include <stdint.h>
-#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <unwindstack/DwarfError.h>
@@ -31,42 +30,27 @@
namespace unwindstack {
template <typename TypeParam>
-class MockDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
+class TestDwarfSectionImpl : public DwarfSectionImpl<TypeParam> {
public:
- MockDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
- virtual ~MockDwarfSectionImpl() = default;
+ TestDwarfSectionImpl(Memory* memory) : DwarfSectionImpl<TypeParam>(memory) {}
+ virtual ~TestDwarfSectionImpl() = default;
- MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
+ bool Init(uint64_t, uint64_t, uint64_t) override { return false; }
- MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
+ void GetFdes(std::vector<const DwarfFde*>*) override {}
- MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t));
+ const DwarfFde* GetFdeFromPc(uint64_t) override { return nullptr; }
- MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t));
+ uint64_t GetCieOffsetFromFde32(uint32_t) { return 0; }
- MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t));
+ uint64_t GetCieOffsetFromFde64(uint64_t) { return 0; }
- MOCK_METHOD1(AdjustPcFromFde, uint64_t(uint64_t));
-
- void TestSetCie32Value(uint32_t value32) { this->cie32_value_ = value32; }
-
- void TestSetCie64Value(uint64_t value64) { this->cie64_value_ = value64; }
-
- void TestSetCachedCieEntry(uint64_t offset, const DwarfCie& cie) {
- this->cie_entries_[offset] = cie;
- }
- void TestClearCachedCieEntry() { this->cie_entries_.clear(); }
-
- void TestSetCachedFdeEntry(uint64_t offset, const DwarfFde& fde) {
- this->fde_entries_[offset] = fde;
- }
- void TestClearCachedFdeEntry() { this->fde_entries_.clear(); }
+ uint64_t AdjustPcFromFde(uint64_t) override { return 0; }
void TestSetCachedCieLocRegs(uint64_t offset, const dwarf_loc_regs_t& loc_regs) {
this->cie_loc_regs_[offset] = loc_regs;
}
void TestClearCachedCieLocRegs() { this->cie_loc_regs_.clear(); }
-
void TestClearError() { this->last_error_.code = DWARF_ERROR_NONE; }
};
@@ -75,21 +59,41 @@
protected:
void SetUp() override {
memory_.Clear();
- section_ = new MockDwarfSectionImpl<TypeParam>(&memory_);
+ section_ = new TestDwarfSectionImpl<TypeParam>(&memory_);
ResetLogs();
- section_->TestSetCie32Value(static_cast<uint32_t>(-1));
- section_->TestSetCie64Value(static_cast<uint64_t>(-1));
}
void TearDown() override { delete section_; }
MemoryFake memory_;
- MockDwarfSectionImpl<TypeParam>* section_ = nullptr;
+ TestDwarfSectionImpl<TypeParam>* section_ = nullptr;
};
TYPED_TEST_CASE_P(DwarfSectionImplTest);
// NOTE: All test class variables need to be referenced as this->.
+TYPED_TEST_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache) {
+ ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+
+ this->section_->TestClearError();
+ ASSERT_TRUE(this->section_->GetCieFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+}
+
+TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
+ ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+
+ this->section_->TestClearError();
+ ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
+ EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
+ EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
+}
+
TYPED_TEST_P(DwarfSectionImplTest, Eval_cfa_expr_eval_fail) {
DwarfCie cie{.version = 3, .return_address_register = 5};
RegsImplFake<TypeParam> regs(10);
@@ -487,334 +491,6 @@
EXPECT_EQ(0x80000000U, regs.pc());
}
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_fail_should_not_cache) {
- ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_32_version_check) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x1);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetData8(0x500b, 8);
- this->memory_.SetData8(0x500c, 0x20);
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x500dU, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x20U, cie->return_address_register);
- EXPECT_EQ(DWARF_ERROR_NONE, this->section_->LastErrorCode());
-
- this->section_->TestClearCachedCieEntry();
- // Set version to 0, 2, 5 and verify we fail.
- this->memory_.SetData8(0x5008, 0x0);
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-
- this->memory_.SetData8(0x5008, 0x2);
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-
- this->memory_.SetData8(0x5008, 0x5);
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetCie(0x5000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_UNSUPPORTED_VERSION, this->section_->LastErrorCode());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_negative_data_alignment_factor) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x1);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetMemory(0x500b, std::vector<uint8_t>{0xfc, 0xff, 0xff, 0xff, 0x7f});
- this->memory_.SetData8(0x5010, 0x20);
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x5011U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(-4, cie->data_alignment_factor);
- EXPECT_EQ(0x20U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_64_no_augment) {
- this->memory_.SetData32(0x8000, 0xffffffff);
- this->memory_.SetData64(0x8004, 0x200);
- this->memory_.SetData64(0x800c, 0xffffffffffffffffULL);
- this->memory_.SetData8(0x8014, 0x1);
- this->memory_.SetData8(0x8015, '\0');
- this->memory_.SetData8(0x8016, 4);
- this->memory_.SetData8(0x8017, 8);
- this->memory_.SetData8(0x8018, 0x20);
-
- const DwarfCie* cie = this->section_->GetCie(0x8000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata8, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x8019U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x820cU, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x20U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_augment) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x1);
- this->memory_.SetMemory(0x5009, std::vector<uint8_t>{'z', 'L', 'P', 'R', '\0'});
- this->memory_.SetData8(0x500e, 4);
- this->memory_.SetData8(0x500f, 8);
- this->memory_.SetData8(0x5010, 0x10);
- // Augment length.
- this->memory_.SetData8(0x5011, 0xf);
- // L data.
- this->memory_.SetData8(0x5012, DW_EH_PE_textrel | DW_EH_PE_udata2);
- // P data.
- this->memory_.SetData8(0x5013, DW_EH_PE_udata4);
- this->memory_.SetData32(0x5014, 0x12345678);
- // R data.
- this->memory_.SetData8(0x5018, DW_EH_PE_udata2);
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(1U, cie->version);
- EXPECT_EQ(DW_EH_PE_udata2, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_textrel | DW_EH_PE_udata2, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(5U, cie->augmentation_string.size());
- EXPECT_EQ('z', cie->augmentation_string[0]);
- EXPECT_EQ('L', cie->augmentation_string[1]);
- EXPECT_EQ('P', cie->augmentation_string[2]);
- EXPECT_EQ('R', cie->augmentation_string[3]);
- EXPECT_EQ('\0', cie->augmentation_string[4]);
- EXPECT_EQ(0x12345678U, cie->personality_handler);
- EXPECT_EQ(0x5021U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x10U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_3) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x3);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetData8(0x500b, 8);
- this->memory_.SetMemory(0x500c, std::vector<uint8_t>{0x81, 0x03});
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(3U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x500eU, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x181U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetCie_version_4) {
- this->memory_.SetData32(0x5000, 0x100);
- this->memory_.SetData32(0x5004, 0xffffffff);
- this->memory_.SetData8(0x5008, 0x4);
- this->memory_.SetData8(0x5009, '\0');
- this->memory_.SetData8(0x500a, 4);
- this->memory_.SetData8(0x500b, 0x13);
- this->memory_.SetData8(0x500c, 4);
- this->memory_.SetData8(0x500d, 8);
- this->memory_.SetMemory(0x500e, std::vector<uint8_t>{0x81, 0x03});
-
- const DwarfCie* cie = this->section_->GetCie(0x5000);
- ASSERT_TRUE(cie != nullptr);
- EXPECT_EQ(4U, cie->version);
- EXPECT_EQ(DW_EH_PE_sdata4, cie->fde_address_encoding);
- EXPECT_EQ(DW_EH_PE_omit, cie->lsda_encoding);
- EXPECT_EQ(0x13U, cie->segment_size);
- EXPECT_EQ(1U, cie->augmentation_string.size());
- EXPECT_EQ('\0', cie->augmentation_string[0]);
- EXPECT_EQ(0U, cie->personality_handler);
- EXPECT_EQ(0x5010U, cie->cfa_instructions_offset);
- EXPECT_EQ(0x5104U, cie->cfa_instructions_end);
- EXPECT_EQ(4U, cie->code_alignment_factor);
- EXPECT_EQ(8, cie->data_alignment_factor);
- EXPECT_EQ(0x181U, cie->return_address_register);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_fail_should_not_cache) {
- ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
- this->section_->TestClearError();
- ASSERT_TRUE(this->section_->GetFdeFromOffset(0x4000) == nullptr);
- EXPECT_EQ(DWARF_ERROR_MEMORY_INVALID, this->section_->LastErrorCode());
- EXPECT_EQ(0x4000U, this->section_->LastErrorAddress());
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment) {
- this->memory_.SetData32(0x4000, 0x20);
- this->memory_.SetData32(0x4004, 0x8000);
- this->memory_.SetData32(0x4008, 0x5000);
- this->memory_.SetData32(0x400c, 0x100);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- this->section_->TestSetCachedCieEntry(0x8000, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x4010U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x4024U, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x8000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_no_augment_non_zero_segment_size) {
- this->memory_.SetData32(0x4000, 0x30);
- this->memory_.SetData32(0x4004, 0x8000);
- this->memory_.SetData32(0x4018, 0x5000);
- this->memory_.SetData32(0x401c, 0x100);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- cie.segment_size = 0x10;
- this->section_->TestSetCachedCieEntry(0x8000, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x4020U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x4034U, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x8000U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_32_augment) {
- this->memory_.SetData32(0x4000, 0x100);
- this->memory_.SetData32(0x4004, 0x8000);
- this->memory_.SetData32(0x4008, 0x5000);
- this->memory_.SetData32(0x400c, 0x100);
- this->memory_.SetMemory(0x4010, std::vector<uint8_t>{0x82, 0x01});
- this->memory_.SetData16(0x4012, 0x1234);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde32(0x8000)).WillOnce(::testing::Return(0x8000));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- cie.augmentation_string.push_back('z');
- cie.lsda_encoding = DW_EH_PE_udata2;
- this->section_->TestSetCachedCieEntry(0x8000, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x4094U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x4104U, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x8000U, fde->cie_offset);
- EXPECT_EQ(0x1234U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_64_no_augment) {
- this->memory_.SetData32(0x4000, 0xffffffff);
- this->memory_.SetData64(0x4004, 0x100);
- this->memory_.SetData64(0x400c, 0x12345678);
- this->memory_.SetData32(0x4014, 0x5000);
- this->memory_.SetData32(0x4018, 0x100);
-
- EXPECT_CALL(*this->section_, GetCieOffsetFromFde64(0x12345678))
- .WillOnce(::testing::Return(0x12345678));
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- this->section_->TestSetCachedCieEntry(0x12345678, cie);
- EXPECT_CALL(*this->section_, AdjustPcFromFde(0x5000)).WillOnce(::testing::Return(0x5000));
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x4000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_TRUE(fde->cie != nullptr);
- EXPECT_EQ(0x401cU, fde->cfa_instructions_offset);
- EXPECT_EQ(0x410cU, fde->cfa_instructions_end);
- EXPECT_EQ(0x5000U, fde->pc_start);
- EXPECT_EQ(0x5100U, fde->pc_end);
- EXPECT_EQ(0x12345678U, fde->cie_offset);
- EXPECT_EQ(0U, fde->lsda_address);
-}
-
-TYPED_TEST_P(DwarfSectionImplTest, GetFdeFromOffset_cached) {
- DwarfCie cie{};
- cie.fde_address_encoding = DW_EH_PE_udata4;
- cie.augmentation_string.push_back('z');
- cie.lsda_encoding = DW_EH_PE_udata2;
-
- DwarfFde fde_cached{};
- fde_cached.cfa_instructions_offset = 0x1000;
- fde_cached.cfa_instructions_end = 0x1100;
- fde_cached.pc_start = 0x9000;
- fde_cached.pc_end = 0x9400;
- fde_cached.cie_offset = 0x30000;
- fde_cached.cie = &cie;
- this->section_->TestSetCachedFdeEntry(0x6000, fde_cached);
-
- const DwarfFde* fde = this->section_->GetFdeFromOffset(0x6000);
- ASSERT_TRUE(fde != nullptr);
- ASSERT_EQ(&cie, fde->cie);
- EXPECT_EQ(0x1000U, fde->cfa_instructions_offset);
- EXPECT_EQ(0x1100U, fde->cfa_instructions_end);
- EXPECT_EQ(0x9000U, fde->pc_start);
- EXPECT_EQ(0x9400U, fde->pc_end);
- EXPECT_EQ(0x30000U, fde->cie_offset);
-}
-
TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) {
DwarfCie cie{};
cie.cfa_instructions_offset = 0x3000;
@@ -895,18 +571,16 @@
ASSERT_EQ("", GetFakeLogBuf());
}
-REGISTER_TYPED_TEST_CASE_P(
- DwarfSectionImplTest, Eval_cfa_expr_eval_fail, Eval_cfa_expr_no_stack,
- Eval_cfa_expr_is_register, Eval_cfa_expr, Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa,
- Eval_cfa_bad, Eval_cfa_register_prev, Eval_cfa_register_from_value, Eval_double_indirection,
- Eval_register_reference_chain, Eval_dex_pc, Eval_invalid_register, Eval_different_reg_locations,
- Eval_return_address_undefined, Eval_pc_zero, Eval_return_address, Eval_ignore_large_reg_loc,
- Eval_reg_expr, Eval_reg_val_expr, GetCie_fail_should_not_cache, GetCie_32_version_check,
- GetCie_negative_data_alignment_factor, GetCie_64_no_augment, GetCie_augment, GetCie_version_3,
- GetCie_version_4, GetFdeFromOffset_fail_should_not_cache, GetFdeFromOffset_32_no_augment,
- GetFdeFromOffset_32_no_augment_non_zero_segment_size, GetFdeFromOffset_32_augment,
- GetFdeFromOffset_64_no_augment, GetFdeFromOffset_cached, GetCfaLocationInfo_cie_not_cached,
- GetCfaLocationInfo_cie_cached, Log);
+REGISTER_TYPED_TEST_CASE_P(DwarfSectionImplTest, GetCieFromOffset_fail_should_not_cache,
+ GetFdeFromOffset_fail_should_not_cache, Eval_cfa_expr_eval_fail,
+ Eval_cfa_expr_no_stack, Eval_cfa_expr_is_register, Eval_cfa_expr,
+ Eval_cfa_val_expr, Eval_bad_regs, Eval_no_cfa, Eval_cfa_bad,
+ Eval_cfa_register_prev, Eval_cfa_register_from_value,
+ Eval_double_indirection, Eval_register_reference_chain, Eval_dex_pc,
+ Eval_invalid_register, Eval_different_reg_locations,
+ Eval_return_address_undefined, Eval_pc_zero, Eval_return_address,
+ Eval_ignore_large_reg_loc, Eval_reg_expr, Eval_reg_val_expr,
+ GetCfaLocationInfo_cie_not_cached, GetCfaLocationInfo_cie_cached, Log);
typedef ::testing::Types<uint32_t, uint64_t> DwarfSectionImplTestTypes;
INSTANTIATE_TYPED_TEST_CASE_P(, DwarfSectionImplTest, DwarfSectionImplTestTypes);
diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp
index 2c6c879..d754fcc 100644
--- a/libunwindstack/tests/DwarfSectionTest.cpp
+++ b/libunwindstack/tests/DwarfSectionTest.cpp
@@ -30,24 +30,18 @@
MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
virtual ~MockDwarfSection() = default;
- MOCK_METHOD3(Log, bool(uint8_t, uint64_t, const DwarfFde*));
+ MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*));
+ MOCK_METHOD3(Log, bool(uint8_t, uint64_t, const DwarfFde*));
+
+ MOCK_METHOD1(GetFdes, void(std::vector<const DwarfFde*>*));
+
+ MOCK_METHOD1(GetFdeFromPc, const DwarfFde*(uint64_t));
+
MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*));
- MOCK_METHOD3(Init, bool(uint64_t, uint64_t, uint64_t));
-
- MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*));
-
- MOCK_METHOD1(GetFdeFromOffset, const DwarfFde*(uint64_t));
-
- MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t));
-
- MOCK_METHOD1(IsCie32, bool(uint32_t));
-
- MOCK_METHOD1(IsCie64, bool(uint64_t));
-
MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t));
MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t));
@@ -57,112 +51,60 @@
class DwarfSectionTest : public ::testing::Test {
protected:
+ void SetUp() override { section_.reset(new MockDwarfSection(&memory_)); }
+
MemoryFake memory_;
+ std::unique_ptr<MockDwarfSection> section_;
};
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_from_pc) {
- MockDwarfSection mock_section(&memory_);
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(false));
-
- // Verify nullptr when GetFdeOffsetFromPc fails.
- ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
-}
-
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_fde_pc_end) {
- MockDwarfSection mock_section(&memory_);
-
- DwarfFde fde{};
- fde.pc_end = 0x500;
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- // Verify nullptr when GetFdeOffsetFromPc fails.
- ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr);
-}
-
-TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_pass) {
- MockDwarfSection mock_section(&memory_);
-
- DwarfFde fde{};
- fde.pc_end = 0x2000;
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- // Verify nullptr when GetFdeOffsetFromPc fails.
- ASSERT_EQ(&fde, mock_section.GetFdeFromPc(0x1000));
-}
-
TEST_F(DwarfSectionTest, Step_fail_fde) {
- MockDwarfSection mock_section(&memory_);
-
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(false));
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr));
bool finished;
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+ ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_fail_cie_null) {
- MockDwarfSection mock_section(&memory_);
-
DwarfFde fde{};
fde.pc_end = 0x2000;
fde.cie = nullptr;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
bool finished;
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+ ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde{};
fde.pc_end = 0x2000;
fde.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
.WillOnce(::testing::Return(false));
bool finished;
- ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished));
+ ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished));
}
TEST_F(DwarfSectionTest, Step_pass) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde{};
fde.pc_end = 0x2000;
fde.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
.WillOnce(::testing::Return(true));
MemoryFake process;
- EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+ EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
.WillOnce(::testing::Return(true));
bool finished;
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
}
static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde,
@@ -173,64 +115,53 @@
}
TEST_F(DwarfSectionTest, Step_cache) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde{};
fde.pc_start = 0x500;
fde.pc_end = 0x2000;
fde.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde));
-
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_))
.WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
MemoryFake process;
- EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+ EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
.WillRepeatedly(::testing::Return(true));
bool finished;
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
- ASSERT_TRUE(mock_section.Step(0x1500, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1500, nullptr, &process, &finished));
}
TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
- MockDwarfSection mock_section(&memory_);
-
DwarfCie cie{};
DwarfFde fde0{};
fde0.pc_start = 0x1000;
fde0.pc_end = 0x2000;
fde0.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde0));
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde0));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_))
.WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
MemoryFake process;
- EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
+ EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_))
.WillRepeatedly(::testing::Return(true));
bool finished;
- ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished));
DwarfFde fde1{};
fde1.pc_start = 0x500;
fde1.pc_end = 0x800;
fde1.cie = &cie;
- EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x600, ::testing::_))
- .WillOnce(::testing::Return(true));
- EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde1));
- EXPECT_CALL(mock_section, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
+ EXPECT_CALL(*section_, GetFdeFromPc(0x600)).WillOnce(::testing::Return(&fde1));
+ EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_))
.WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
- ASSERT_TRUE(mock_section.Step(0x600, nullptr, &process, &finished));
- ASSERT_TRUE(mock_section.Step(0x700, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x600, nullptr, &process, &finished));
+ ASSERT_TRUE(section_->Step(0x700, nullptr, &process, &finished));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index 487d39c..aa6df84 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -656,8 +656,7 @@
memory_.SetData32(0x5000, 0xfc);
memory_.SetData32(0x5004, 0xffffffff);
- memory_.SetData8(0x5008, 1);
- memory_.SetData8(0x5009, '\0');
+ memory_.SetMemory(0x5008, std::vector<uint8_t>{1, '\0', 4, 8, 2});
memory_.SetData32(0x5100, 0xfc);
memory_.SetData32(0x5104, 0);
@@ -678,56 +677,6 @@
InitHeadersDebugFrame<ElfInterface64Fake>();
}
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersEhFrameFail() {
- ElfType elf(&memory_);
-
- elf.FakeSetEhFrameOffset(0x1000);
- elf.FakeSetEhFrameSize(0x100);
- elf.FakeSetDebugFrameOffset(0);
- elf.FakeSetDebugFrameSize(0);
-
- elf.InitHeaders(0);
-
- EXPECT_TRUE(elf.eh_frame() == nullptr);
- EXPECT_EQ(0U, elf.eh_frame_offset());
- EXPECT_EQ(static_cast<uint64_t>(-1), elf.eh_frame_size());
- EXPECT_TRUE(elf.debug_frame() == nullptr);
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame32_fail) {
- InitHeadersEhFrameFail<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_eh_frame64_fail) {
- InitHeadersEhFrameFail<ElfInterface64Fake>();
-}
-
-template <typename ElfType>
-void ElfInterfaceTest::InitHeadersDebugFrameFail() {
- ElfType elf(&memory_);
-
- elf.FakeSetEhFrameOffset(0);
- elf.FakeSetEhFrameSize(0);
- elf.FakeSetDebugFrameOffset(0x1000);
- elf.FakeSetDebugFrameSize(0x100);
-
- elf.InitHeaders(0);
-
- EXPECT_TRUE(elf.eh_frame() == nullptr);
- EXPECT_TRUE(elf.debug_frame() == nullptr);
- EXPECT_EQ(0U, elf.debug_frame_offset());
- EXPECT_EQ(static_cast<uint64_t>(-1), elf.debug_frame_size());
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame32_fail) {
- InitHeadersDebugFrameFail<ElfInterface32Fake>();
-}
-
-TEST_F(ElfInterfaceTest, init_headers_debug_frame64_fail) {
- InitHeadersDebugFrameFail<ElfInterface64Fake>();
-}
-
template <typename Ehdr, typename Shdr, typename ElfInterfaceType>
void ElfInterfaceTest::InitSectionHeadersMalformed() {
std::unique_ptr<ElfInterfaceType> elf(new ElfInterfaceType(&memory_));
@@ -1024,11 +973,7 @@
// CIE 32.
memory_.SetData32(0x600, 0xfc);
memory_.SetData32(0x604, 0xffffffff);
- memory_.SetData8(0x608, 1);
- memory_.SetData8(0x609, '\0');
- memory_.SetData8(0x60a, 0x4);
- memory_.SetData8(0x60b, 0x4);
- memory_.SetData8(0x60c, 0x1);
+ memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
// FDE 32.
memory_.SetData32(0x700, 0xfc);
@@ -1085,11 +1030,7 @@
// CIE 32.
memory_.SetData32(0x600, 0xfc);
memory_.SetData32(0x604, 0);
- memory_.SetData8(0x608, 1);
- memory_.SetData8(0x609, '\0');
- memory_.SetData8(0x60a, 0x4);
- memory_.SetData8(0x60b, 0x4);
- memory_.SetData8(0x60c, 0x1);
+ memory_.SetMemory(0x608, std::vector<uint8_t>{1, '\0', 4, 4, 1});
// FDE 32.
memory_.SetData32(0x700, 0xfc);
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 197047d..625ffba 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -227,6 +227,8 @@
# pstore/ramoops previous console log
mount pstore pstore /sys/fs/pstore nodev noexec nosuid
+ chown system log /sys/fs/pstore
+ chmod 0550 /sys/fs/pstore
chown system log /sys/fs/pstore/console-ramoops
chmod 0440 /sys/fs/pstore/console-ramoops
chown system log /sys/fs/pstore/console-ramoops-0