Merge "fs_mgr: Add stable_inodes flag to encrypted ext4"
diff --git a/fastboot/Android.bp b/fastboot/Android.bp
index f452a64..02a887e 100644
--- a/fastboot/Android.bp
+++ b/fastboot/Android.bp
@@ -122,6 +122,7 @@
shared_libs: [
"android.hardware.boot@1.0",
+ "android.hardware.boot@1.1",
"android.hardware.fastboot@1.0",
"android.hardware.health@2.0",
"libadbd",
diff --git a/fastboot/constants.h b/fastboot/constants.h
index 8a72627..7fba67c 100644
--- a/fastboot/constants.h
+++ b/fastboot/constants.h
@@ -34,6 +34,7 @@
#define FB_CMD_UPDATE_SUPER "update-super"
#define FB_CMD_OEM "oem"
#define FB_CMD_GSI "gsi"
+#define FB_CMD_SNAPSHOT_UPDATE "snapshot-update"
#define RESPONSE_OKAY "OKAY"
#define RESPONSE_FAIL "FAIL"
@@ -66,3 +67,4 @@
#define FB_VAR_BATTERY_VOLTAGE "battery-voltage"
#define FB_VAR_BATTERY_SOC_OK "battery-soc-ok"
#define FB_VAR_SUPER_PARTITION_NAME "super-partition-name"
+#define FB_VAR_SNAPSHOT_UPDATE_STATUS "snapshot-update-status"
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 4c77c75..dfd5690 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -25,6 +25,7 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
#include <cutils/android_reboot.h>
#include <ext4_utils/wipe.h>
#include <fs_mgr.h>
@@ -44,8 +45,10 @@
using ::android::hardware::boot::V1_0::BoolResult;
using ::android::hardware::boot::V1_0::CommandResult;
using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::boot::V1_1::MergeStatus;
using ::android::hardware::fastboot::V1_0::Result;
using ::android::hardware::fastboot::V1_0::Status;
+using IBootControl1_1 = ::android::hardware::boot::V1_1::IBootControl;
struct VariableHandlers {
// Callback to retrieve the value of a single variable.
@@ -101,7 +104,8 @@
{FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}},
{FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}},
{FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}},
- {FB_VAR_SUPER_PARTITION_NAME, {GetSuperPartitionName, nullptr}}};
+ {FB_VAR_SUPER_PARTITION_NAME, {GetSuperPartitionName, nullptr}},
+ {FB_VAR_SNAPSHOT_UPDATE_STATUS, {GetSnapshotUpdateStatus, nullptr}}};
if (args.size() < 2) {
return device->WriteFail("Missing argument");
@@ -547,3 +551,40 @@
}
return device->WriteStatus(FastbootResult::OKAY, "Success");
}
+
+bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string>& args) {
+ // Note that we use the HAL rather than mounting /metadata, since we want
+ // our results to match the bootloader.
+ auto hal = device->boot_control_hal();
+ if (!hal) return device->WriteFail("Not supported");
+
+ android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
+ if (!hal11) return device->WriteFail("Not supported");
+
+ // If no arguments, return the same thing as a getvar. Note that we get the
+ // HAL first so we can return "not supported" before we return the less
+ // specific error message below.
+ if (args.size() < 2 || args[1].empty()) {
+ std::string message;
+ if (!GetSnapshotUpdateStatus(device, {}, &message)) {
+ return device->WriteFail("Could not determine update status");
+ }
+ device->WriteInfo(message);
+ return device->WriteOkay("");
+ }
+
+ if (args.size() != 2 || args[1] != "cancel") {
+ return device->WriteFail("Invalid arguments");
+ }
+
+ MergeStatus status = hal11->getSnapshotMergeStatus();
+ switch (status) {
+ case MergeStatus::SNAPSHOTTED:
+ case MergeStatus::MERGING:
+ hal11->setSnapshotMergeStatus(MergeStatus::CANCELLED);
+ break;
+ default:
+ break;
+ }
+ return device->WriteStatus(FastbootResult::OKAY, "Success");
+}
diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h
index 9b6e7b6..c1324bc 100644
--- a/fastboot/device/commands.h
+++ b/fastboot/device/commands.h
@@ -49,3 +49,4 @@
bool UpdateSuperHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool OemCmdHandler(FastbootDevice* device, const std::vector<std::string>& args);
bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args);
+bool SnapshotUpdateHandler(FastbootDevice* device, const std::vector<std::string>& args);
diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp
index 56fafab..d3c2bda 100644
--- a/fastboot/device/fastboot_device.cpp
+++ b/fastboot/device/fastboot_device.cpp
@@ -54,6 +54,7 @@
{FB_CMD_UPDATE_SUPER, UpdateSuperHandler},
{FB_CMD_OEM, OemCmdHandler},
{FB_CMD_GSI, GsiHandler},
+ {FB_CMD_SNAPSHOT_UPDATE, SnapshotUpdateHandler},
}),
transport_(std::make_unique<ClientUsbTransport>()),
boot_control_hal_(IBootControl::getService()),
diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp
index 130a3cf..6e613d6 100644
--- a/fastboot/device/variables.cpp
+++ b/fastboot/device/variables.cpp
@@ -23,6 +23,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <android/hardware/boot/1.1/IBootControl.h>
#include <ext4_utils/ext4_utils.h>
#include <fs_mgr.h>
#include <healthhalutils/HealthHalUtils.h>
@@ -34,9 +35,11 @@
using ::android::hardware::boot::V1_0::BoolResult;
using ::android::hardware::boot::V1_0::Slot;
+using ::android::hardware::boot::V1_1::MergeStatus;
using ::android::hardware::fastboot::V1_0::FileSystemType;
using ::android::hardware::fastboot::V1_0::Result;
using ::android::hardware::fastboot::V1_0::Status;
+using IBootControl1_1 = ::android::hardware::boot::V1_1::IBootControl;
using namespace android::fs_mgr;
constexpr char kFastbootProtocolVersion[] = "0.4";
@@ -424,3 +427,34 @@
*message = fs_mgr_get_super_partition_name(slot_number);
return true;
}
+
+bool GetSnapshotUpdateStatus(FastbootDevice* device, const std::vector<std::string>& /* args */,
+ std::string* message) {
+ // Note that we use the HAL rather than mounting /metadata, since we want
+ // our results to match the bootloader.
+ auto hal = device->boot_control_hal();
+ if (!hal) {
+ *message = "not supported";
+ return false;
+ }
+
+ android::sp<IBootControl1_1> hal11 = IBootControl1_1::castFrom(hal);
+ if (!hal11) {
+ *message = "not supported";
+ return false;
+ }
+
+ MergeStatus status = hal11->getSnapshotMergeStatus();
+ switch (status) {
+ case MergeStatus::SNAPSHOTTED:
+ *message = "snapshotted";
+ break;
+ case MergeStatus::MERGING:
+ *message = "merging";
+ break;
+ default:
+ *message = "none";
+ break;
+ }
+ return true;
+}
diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h
index 015a4c5..4dec10f 100644
--- a/fastboot/device/variables.h
+++ b/fastboot/device/variables.h
@@ -61,6 +61,8 @@
std::string* message);
bool GetSuperPartitionName(FastbootDevice* device, const std::vector<std::string>& args,
std::string* message);
+bool GetSnapshotUpdateStatus(FastbootDevice* device, const std::vector<std::string>& args,
+ std::string* message);
// Helpers for getvar all.
std::vector<std::vector<std::string>> GetAllPartitionArgsWithSlot(FastbootDevice* device);
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 2fe3b1a..7ce7c7c 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -396,6 +396,9 @@
" gsi wipe|disable Wipe or disable a GSI installation (fastbootd only).\n"
" wipe-super [SUPER_EMPTY] Wipe the super partition. This will reset it to\n"
" contain an empty set of default dynamic partitions.\n"
+ " snapshot-update cancel On devices that support snapshot-based updates, cancel\n"
+ " an in-progress update. This may make the device\n"
+ " unbootable until it is reflashed.\n"
"\n"
"boot image:\n"
" boot KERNEL [RAMDISK [SECOND]]\n"
@@ -1216,6 +1219,14 @@
target_sparse_limit = -1;
}
+static void CancelSnapshotIfNeeded() {
+ std::string merge_status = "none";
+ if (fb->GetVar(FB_VAR_SNAPSHOT_UPDATE_STATUS, &merge_status) == fastboot::SUCCESS &&
+ merge_status != "none") {
+ fb->SnapshotUpdateCommand("Cancel");
+ }
+}
+
class ImageSource {
public:
virtual bool ReadFile(const std::string& name, std::vector<char>* out) const = 0;
@@ -1268,6 +1279,8 @@
DetermineSecondarySlot();
CollectImages();
+ CancelSnapshotIfNeeded();
+
// First flash boot partitions. We allow this to happen either in userspace
// or in bootloader fastboot.
FlashImages(boot_images_);
@@ -2071,12 +2084,24 @@
image = next_arg(&args);
}
do_wipe_super(image, slot_override);
+ } else if (command == "snapshot-update") {
+ std::string arg;
+ if (!args.empty()) {
+ arg = next_arg(&args);
+ }
+ if (!arg.empty() && arg != "cancel") {
+ syntax_error("expected: snapshot-update [cancel]");
+ }
+ fb->SnapshotUpdateCommand(arg);
} else {
syntax_error("unknown command %s", command.c_str());
}
}
if (wants_wipe) {
+ if (force_flash) {
+ CancelSnapshotIfNeeded();
+ }
std::vector<std::string> partitions = { "userdata", "cache", "metadata" };
for (const auto& partition : partitions) {
std::string partition_type;
diff --git a/fastboot/fastboot_driver.cpp b/fastboot/fastboot_driver.cpp
index b897182..6a5ad20 100644
--- a/fastboot/fastboot_driver.cpp
+++ b/fastboot/fastboot_driver.cpp
@@ -122,6 +122,12 @@
response, info);
}
+RetCode FastBootDriver::SnapshotUpdateCommand(const std::string& command, std::string* response,
+ std::vector<std::string>* info) {
+ std::string raw = FB_CMD_SNAPSHOT_UPDATE ":" + command;
+ return RawCommand(raw, response, info);
+}
+
RetCode FastBootDriver::FlashPartition(const std::string& partition,
const std::vector<char>& data) {
RetCode ret;
diff --git a/fastboot/fastboot_driver.h b/fastboot/fastboot_driver.h
index af02637..7265632 100644
--- a/fastboot/fastboot_driver.h
+++ b/fastboot/fastboot_driver.h
@@ -104,6 +104,8 @@
std::vector<std::string>* info = nullptr);
RetCode Upload(const std::string& outfile, std::string* response = nullptr,
std::vector<std::string>* info = nullptr);
+ RetCode SnapshotUpdateCommand(const std::string& command, std::string* response = nullptr,
+ std::vector<std::string>* info = nullptr);
/* HIGHER LEVEL COMMANDS -- Composed of the commands above */
RetCode FlashPartition(const std::string& partition, const std::vector<char>& data);
diff --git a/fs_mgr/README.overlayfs.md b/fs_mgr/README.overlayfs.md
index bb63df8..f579078 100644
--- a/fs_mgr/README.overlayfs.md
+++ b/fs_mgr/README.overlayfs.md
@@ -32,9 +32,9 @@
Then enter one of the following sequences:
- $ adb stop
+ $ adb shell stop
$ adb sync
- $ adb start
+ $ adb shell start
$ adb reboot
*or*
diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h
index dcb4ffb..421d826 100644
--- a/libmodprobe/include/modprobe/modprobe.h
+++ b/libmodprobe/include/modprobe/modprobe.h
@@ -19,6 +19,7 @@
#include <set>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
class Modprobe {
@@ -59,5 +60,6 @@
std::vector<std::string> module_load_;
std::unordered_map<std::string, std::string> module_options_;
std::set<std::string> module_blacklist_;
+ std::unordered_set<std::string> module_loaded_;
bool blacklist_enabled = false;
};
diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp
index 73ae15b..3c78ec9 100644
--- a/libmodprobe/libmodprobe.cpp
+++ b/libmodprobe/libmodprobe.cpp
@@ -330,7 +330,12 @@
bool Modprobe::LoadWithAliases(const std::string& module_name, bool strict,
const std::string& parameters) {
- std::set<std::string> modules_to_load = {MakeCanonical(module_name)};
+ auto canonical_name = MakeCanonical(module_name);
+ if (module_loaded_.count(canonical_name)) {
+ return true;
+ }
+
+ std::set<std::string> modules_to_load = {canonical_name};
bool module_loaded = false;
// use aliases to expand list of modules to load (multiple modules
@@ -338,6 +343,7 @@
for (const auto& [alias, aliased_module] : module_aliases_) {
if (fnmatch(alias.c_str(), module_name.c_str(), 0) != 0) continue;
LOG(VERBOSE) << "Found alias for '" << module_name << "': '" << aliased_module;
+ if (module_loaded_.count(MakeCanonical(aliased_module))) continue;
modules_to_load.emplace(aliased_module);
}
diff --git a/libmodprobe/libmodprobe_ext.cpp b/libmodprobe/libmodprobe_ext.cpp
index 2efcac2..8bebe4c 100644
--- a/libmodprobe/libmodprobe_ext.cpp
+++ b/libmodprobe/libmodprobe_ext.cpp
@@ -30,8 +30,9 @@
return false;
}
+ auto canonical_name = MakeCanonical(path_name);
std::string options = "";
- auto options_iter = module_options_.find(MakeCanonical(path_name));
+ auto options_iter = module_options_.find(canonical_name);
if (options_iter != module_options_.end()) {
options = options_iter->second;
}
@@ -44,6 +45,7 @@
if (ret != 0) {
if (errno == EEXIST) {
// Module already loaded
+ module_loaded_.emplace(canonical_name);
return true;
}
LOG(ERROR) << "Failed to insmod '" << path_name << "' with args '" << options << "'";
@@ -51,15 +53,18 @@
}
LOG(INFO) << "Loaded kernel module " << path_name;
+ module_loaded_.emplace(canonical_name);
return true;
}
bool Modprobe::Rmmod(const std::string& module_name) {
- int ret = syscall(__NR_delete_module, MakeCanonical(module_name).c_str(), O_NONBLOCK);
+ auto canonical_name = MakeCanonical(module_name);
+ int ret = syscall(__NR_delete_module, canonical_name.c_str(), O_NONBLOCK);
if (ret != 0) {
PLOG(ERROR) << "Failed to remove module '" << module_name << "'";
return false;
}
+ module_loaded_.erase(canonical_name);
return true;
}
diff --git a/libunwindstack/DwarfDebugFrame.h b/libunwindstack/DwarfDebugFrame.h
index 388ab0a..635cefd 100644
--- a/libunwindstack/DwarfDebugFrame.h
+++ b/libunwindstack/DwarfDebugFrame.h
@@ -26,9 +26,9 @@
namespace unwindstack {
template <typename AddressType>
-class DwarfDebugFrame : public DwarfSectionImplNoHdr<AddressType> {
+class DwarfDebugFrame : public DwarfSectionImpl<AddressType> {
public:
- DwarfDebugFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {
+ DwarfDebugFrame(Memory* memory) : DwarfSectionImpl<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 df441fb..7a41e45 100644
--- a/libunwindstack/DwarfEhFrame.h
+++ b/libunwindstack/DwarfEhFrame.h
@@ -25,9 +25,9 @@
namespace unwindstack {
template <typename AddressType>
-class DwarfEhFrame : public DwarfSectionImplNoHdr<AddressType> {
+class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
public:
- DwarfEhFrame(Memory* memory) : DwarfSectionImplNoHdr<AddressType>(memory) {}
+ DwarfEhFrame(Memory* memory) : DwarfSectionImpl<AddressType>(memory) {}
virtual ~DwarfEhFrame() = default;
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
diff --git a/libunwindstack/DwarfEhFrameWithHdr.cpp b/libunwindstack/DwarfEhFrameWithHdr.cpp
index 24b94f0..1358e51 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.cpp
+++ b/libunwindstack/DwarfEhFrameWithHdr.cpp
@@ -32,14 +32,19 @@
}
template <typename AddressType>
-bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
- section_bias_ = section_bias;
+bool DwarfEhFrameWithHdr<AddressType>::EhFrameInit(uint64_t offset, uint64_t size,
+ int64_t section_bias) {
+ return DwarfSectionImpl<AddressType>::Init(offset, size, section_bias);
+}
+template <typename AddressType>
+bool DwarfEhFrameWithHdr<AddressType>::Init(uint64_t offset, uint64_t, int64_t section_bias) {
memory_.clear_func_offset();
memory_.clear_text_offset();
memory_.set_data_offset(offset);
memory_.set_cur_offset(offset);
- pc_offset_ = offset;
+
+ hdr_section_bias_ = section_bias;
// Read the first four bytes all at once.
uint8_t data[4];
@@ -56,7 +61,7 @@
return false;
}
- ptr_encoding_ = data[1];
+ uint8_t ptr_encoding = data[1];
uint8_t fde_count_encoding = data[2];
table_encoding_ = data[3];
table_entry_size_ = memory_.template GetEncodedSize<AddressType>(table_encoding_);
@@ -70,7 +75,8 @@
}
memory_.set_pc_offset(memory_.cur_offset());
- if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding_, &ptr_offset_)) {
+ uint64_t ptr_offset;
+ if (!memory_.template ReadEncodedValue<AddressType>(ptr_encoding, &ptr_offset)) {
last_error_.code = DWARF_ERROR_MEMORY_INVALID;
last_error_.address = memory_.cur_offset();
return false;
@@ -88,10 +94,8 @@
return false;
}
- entries_offset_ = memory_.cur_offset();
- entries_end_ = offset + size;
- entries_data_offset_ = offset;
- cur_entries_offset_ = entries_offset_;
+ hdr_entries_offset_ = memory_.cur_offset();
+ hdr_entries_data_offset_ = offset;
return true;
}
@@ -107,6 +111,16 @@
return nullptr;
}
+ // There is a possibility that this entry points to a zero length FDE
+ // due to a bug. If this happens, try and find the non-zero length FDE
+ // from eh_frame directly. See b/142483624.
+ if (fde->pc_start == fde->pc_end) {
+ fde = DwarfSectionImpl<AddressType>::GetFdeFromPc(pc);
+ if (fde == nullptr) {
+ return nullptr;
+ }
+ }
+
// Guaranteed pc >= pc_start, need to check pc in the fde range.
if (pc < fde->pc_end) {
return fde;
@@ -124,8 +138,8 @@
}
FdeInfo* info = &fde_info_[index];
- memory_.set_data_offset(entries_data_offset_);
- memory_.set_cur_offset(entries_offset_ + 2 * index * table_entry_size_);
+ memory_.set_data_offset(hdr_entries_data_offset_);
+ memory_.set_cur_offset(hdr_entries_offset_ + 2 * index * table_entry_size_);
memory_.set_pc_offset(0);
uint64_t value;
if (!memory_.template ReadEncodedValue<AddressType>(table_encoding_, &value) ||
@@ -138,7 +152,7 @@
// Relative encodings require adding in the load bias.
if (IsEncodingRelative(table_encoding_)) {
- value += section_bias_;
+ value += hdr_section_bias_;
}
info->pc = value;
return info;
@@ -190,6 +204,16 @@
if (fde == nullptr) {
break;
}
+
+ // There is a possibility that this entry points to a zero length FDE
+ // due to a bug. If this happens, try and find the non-zero length FDE
+ // from eh_frame directly. See b/142483624.
+ if (fde->pc_start == fde->pc_end) {
+ const DwarfFde* fde_real = DwarfSectionImpl<AddressType>::GetFdeFromPc(fde->pc_start);
+ if (fde_real != nullptr) {
+ fde = fde_real;
+ }
+ }
fdes->push_back(fde);
}
}
diff --git a/libunwindstack/DwarfEhFrameWithHdr.h b/libunwindstack/DwarfEhFrameWithHdr.h
index b8dd3dd..f7c010c 100644
--- a/libunwindstack/DwarfEhFrameWithHdr.h
+++ b/libunwindstack/DwarfEhFrameWithHdr.h
@@ -34,11 +34,7 @@
// 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>::section_bias_;
struct FdeInfo {
AddressType pc;
@@ -49,18 +45,19 @@
virtual ~DwarfEhFrameWithHdr() = default;
uint64_t GetCieOffsetFromFde32(uint32_t pointer) override {
- return this->memory_.cur_offset() - pointer - 4;
+ return memory_.cur_offset() - pointer - 4;
}
uint64_t GetCieOffsetFromFde64(uint64_t pointer) override {
- return this->memory_.cur_offset() - pointer - 8;
+ return 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;
+ return pc + memory_.cur_offset() - 4;
}
+ bool EhFrameInit(uint64_t offset, uint64_t size, int64_t section_bias);
bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
const DwarfFde* GetFdeFromPc(uint64_t pc) override;
@@ -72,17 +69,15 @@
void GetFdes(std::vector<const DwarfFde*>* fdes) override;
protected:
- uint8_t version_;
- uint8_t ptr_encoding_;
- uint8_t table_encoding_;
- size_t table_entry_size_;
+ uint8_t version_ = 0;
+ uint8_t table_encoding_ = 0;
+ size_t table_entry_size_ = 0;
- uint64_t ptr_offset_;
+ uint64_t hdr_entries_offset_ = 0;
+ uint64_t hdr_entries_data_offset_ = 0;
+ uint64_t hdr_section_bias_ = 0;
- uint64_t entries_data_offset_;
- uint64_t cur_entries_offset_ = 0;
-
- uint64_t fde_count_;
+ uint64_t fde_count_ = 0;
std::unordered_map<uint64_t, FdeInfo> fde_info_;
};
diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp
index cdb6141..e6263f8 100644
--- a/libunwindstack/DwarfSection.cpp
+++ b/libunwindstack/DwarfSection.cpp
@@ -69,6 +69,7 @@
return &cie_entry->second;
}
DwarfCie* cie = &cie_entries_[offset];
+ memory_.set_data_offset(entries_offset_);
memory_.set_cur_offset(offset);
if (!FillInCieHeader(cie) || !FillInCie(cie)) {
// Erase the cached entry.
@@ -251,6 +252,7 @@
return &fde_entry->second;
}
DwarfFde* fde = &fde_entries_[offset];
+ memory_.set_data_offset(entries_offset_);
memory_.set_cur_offset(offset);
if (!FillInFdeHeader(fde) || !FillInFde(fde)) {
fde_entries_.erase(offset);
@@ -591,8 +593,7 @@
}
template <typename AddressType>
-bool DwarfSectionImplNoHdr<AddressType>::Init(uint64_t offset, uint64_t size,
- int64_t section_bias) {
+bool DwarfSectionImpl<AddressType>::Init(uint64_t offset, uint64_t size, int64_t section_bias) {
section_bias_ = section_bias;
entries_offset_ = offset;
next_entries_offset_ = offset;
@@ -601,7 +602,6 @@
memory_.clear_func_offset();
memory_.clear_text_offset();
memory_.set_cur_offset(offset);
- memory_.set_data_offset(offset);
pc_offset_ = offset;
return true;
@@ -617,7 +617,7 @@
// and an fde has a start pc of 0x100 and end pc of 0x500, two new entries
// will be added: 0x200, 0x100 and 0x500, 0x400.
template <typename AddressType>
-void DwarfSectionImplNoHdr<AddressType>::InsertFde(const DwarfFde* fde) {
+void DwarfSectionImpl<AddressType>::InsertFde(const DwarfFde* fde) {
uint64_t start = fde->pc_start;
uint64_t end = fde->pc_end;
auto it = fdes_.upper_bound(start);
@@ -654,9 +654,10 @@
}
template <typename AddressType>
-bool DwarfSectionImplNoHdr<AddressType>::GetNextCieOrFde(DwarfFde** fde_entry) {
+bool DwarfSectionImpl<AddressType>::GetNextCieOrFde(const DwarfFde** fde_entry) {
uint64_t start_offset = next_entries_offset_;
+ memory_.set_data_offset(entries_offset_);
memory_.set_cur_offset(next_entries_offset_);
uint32_t value32;
if (!memory_.ReadBytes(&value32, sizeof(value32))) {
@@ -689,7 +690,7 @@
entry_is_cie = true;
cie_fde_encoding = DW_EH_PE_sdata8;
} else {
- cie_offset = this->GetCieOffsetFromFde64(value64);
+ cie_offset = GetCieOffsetFromFde64(value64);
}
} else {
next_entries_offset_ = memory_.cur_offset() + value32;
@@ -705,37 +706,45 @@
entry_is_cie = true;
cie_fde_encoding = DW_EH_PE_sdata4;
} else {
- cie_offset = this->GetCieOffsetFromFde32(value32);
+ cie_offset = GetCieOffsetFromFde32(value32);
}
}
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;
+ auto entry = cie_entries_.find(start_offset);
+ if (entry == cie_entries_.end()) {
+ DwarfCie* cie = &cie_entries_[start_offset];
+ cie->lsda_encoding = DW_EH_PE_omit;
+ cie->cfa_instructions_end = next_entries_offset_;
+ cie->fde_address_encoding = cie_fde_encoding;
- if (!this->FillInCie(cie)) {
- cie_entries_.erase(start_offset);
- return false;
+ if (!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;
+ auto entry = fde_entries_.find(start_offset);
+ if (entry != fde_entries_.end()) {
+ *fde_entry = &entry->second;
+ } else {
+ DwarfFde* fde = &fde_entries_[start_offset];
+ fde->cfa_instructions_end = next_entries_offset_;
+ fde->cie_offset = cie_offset;
- if (!this->FillInFde(fde)) {
- fde_entries_.erase(start_offset);
- return false;
+ if (!FillInFde(fde)) {
+ fde_entries_.erase(start_offset);
+ return false;
+ }
+ *fde_entry = fde;
}
- *fde_entry = fde;
}
return true;
}
template <typename AddressType>
-void DwarfSectionImplNoHdr<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
+void DwarfSectionImpl<AddressType>::GetFdes(std::vector<const DwarfFde*>* fdes) {
// Loop through the already cached entries.
uint64_t entry_offset = entries_offset_;
while (entry_offset < next_entries_offset_) {
@@ -754,7 +763,7 @@
}
while (next_entries_offset_ < entries_end_) {
- DwarfFde* fde;
+ const DwarfFde* fde;
if (!GetNextCieOrFde(&fde)) {
break;
}
@@ -771,7 +780,7 @@
}
template <typename AddressType>
-const DwarfFde* DwarfSectionImplNoHdr<AddressType>::GetFdeFromPc(uint64_t pc) {
+const DwarfFde* DwarfSectionImpl<AddressType>::GetFdeFromPc(uint64_t pc) {
// Search in the list of fdes we already have.
auto it = fdes_.upper_bound(pc);
if (it != fdes_.end()) {
@@ -784,7 +793,7 @@
// 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;
+ const DwarfFde* fde;
if (!GetNextCieOrFde(&fde)) {
return nullptr;
}
@@ -807,10 +816,6 @@
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/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index e863f22..5f95fa8 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -126,8 +126,10 @@
template <typename AddressType>
void ElfInterface::InitHeadersWithTemplate() {
if (eh_frame_hdr_offset_ != 0) {
- eh_frame_.reset(new DwarfEhFrameWithHdr<AddressType>(memory_));
- if (!eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, eh_frame_hdr_section_bias_)) {
+ DwarfEhFrameWithHdr<AddressType>* eh_frame_hdr = new DwarfEhFrameWithHdr<AddressType>(memory_);
+ eh_frame_.reset(eh_frame_hdr);
+ if (!eh_frame_hdr->EhFrameInit(eh_frame_offset_, eh_frame_size_, eh_frame_section_bias_) ||
+ !eh_frame_->Init(eh_frame_hdr_offset_, eh_frame_hdr_size_, eh_frame_hdr_section_bias_)) {
eh_frame_.reset(nullptr);
}
}
diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h
index 0b3f6d4..c244749 100644
--- a/libunwindstack/include/unwindstack/DwarfSection.h
+++ b/libunwindstack/include/unwindstack/DwarfSection.h
@@ -125,10 +125,16 @@
DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {}
virtual ~DwarfSectionImpl() = default;
+ bool Init(uint64_t offset, uint64_t size, int64_t section_bias) override;
+
const DwarfCie* GetCieFromOffset(uint64_t offset);
const DwarfFde* GetFdeFromOffset(uint64_t offset);
+ const DwarfFde* GetFdeFromPc(uint64_t pc) override;
+
+ void GetFdes(std::vector<const DwarfFde*>* fdes) override;
+
bool EvalRegister(const DwarfLocation* loc, uint32_t reg, AddressType* reg_ptr, void* info);
bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs,
@@ -139,6 +145,8 @@
bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override;
protected:
+ bool GetNextCieOrFde(const DwarfFde** fde_entry);
+
bool FillInCieHeader(DwarfCie* cie);
bool FillInCie(DwarfCie* cie);
@@ -150,43 +158,13 @@
bool EvalExpression(const DwarfLocation& loc, Memory* regular_memory, AddressType* value,
RegsInfo<AddressType>* regs_info, bool* is_dex_pc);
+ void InsertFde(const DwarfFde* fde);
+
int64_t section_bias_ = 0;
uint64_t entries_offset_ = 0;
uint64_t entries_end_ = 0;
- uint64_t pc_offset_ = 0;
-};
-
-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>::section_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, int64_t section_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;
+ uint64_t pc_offset_ = 0;
std::map<uint64_t, std::pair<uint64_t, const DwarfFde*>> fdes_;
};
diff --git a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
index 78608e3..768a808 100644
--- a/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
+++ b/libunwindstack/tests/DwarfEhFrameWithHdrTest.cpp
@@ -36,10 +36,8 @@
~TestDwarfEhFrameWithHdr() = default;
void TestSetTableEncoding(uint8_t encoding) { this->table_encoding_ = encoding; }
- void TestSetEntriesOffset(uint64_t offset) { this->entries_offset_ = offset; }
- void TestSetEntriesEnd(uint64_t end) { this->entries_end_ = end; }
- void TestSetEntriesDataOffset(uint64_t offset) { this->entries_data_offset_ = offset; }
- void TestSetCurEntriesOffset(uint64_t offset) { this->cur_entries_offset_ = offset; }
+ void TestSetHdrEntriesOffset(uint64_t offset) { this->hdr_entries_offset_ = offset; }
+ void TestSetHdrEntriesDataOffset(uint64_t offset) { this->hdr_entries_data_offset_ = offset; }
void TestSetTableEntrySize(size_t size) { this->table_entry_size_ = size; }
void TestSetFdeCount(uint64_t count) { this->fde_count_ = count; }
@@ -48,15 +46,11 @@
}
uint8_t TestGetVersion() { return this->version_; }
- uint8_t TestGetPtrEncoding() { return this->ptr_encoding_; }
- uint64_t TestGetPtrOffset() { return this->ptr_offset_; }
uint8_t TestGetTableEncoding() { return this->table_encoding_; }
uint64_t TestGetTableEntrySize() { return this->table_entry_size_; }
uint64_t TestGetFdeCount() { return this->fde_count_; }
- uint64_t TestGetEntriesOffset() { return this->entries_offset_; }
- uint64_t TestGetEntriesEnd() { return this->entries_end_; }
- uint64_t TestGetEntriesDataOffset() { return this->entries_data_offset_; }
- uint64_t TestGetCurEntriesOffset() { return this->cur_entries_offset_; }
+ uint64_t TestGetHdrEntriesOffset() { return this->hdr_entries_offset_; }
+ uint64_t TestGetHdrEntriesDataOffset() { return this->hdr_entries_data_offset_; }
};
template <typename TypeParam>
@@ -85,15 +79,11 @@
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
- EXPECT_EQ(DW_EH_PE_udata2, this->eh_frame_->TestGetPtrEncoding());
EXPECT_EQ(DW_EH_PE_sdata4, this->eh_frame_->TestGetTableEncoding());
EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
EXPECT_EQ(126U, this->eh_frame_->TestGetFdeCount());
- EXPECT_EQ(0x500U, this->eh_frame_->TestGetPtrOffset());
- EXPECT_EQ(0x100aU, this->eh_frame_->TestGetEntriesOffset());
- EXPECT_EQ(0x1100U, this->eh_frame_->TestGetEntriesEnd());
- EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
- EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
+ EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
+ EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
// Verify a zero table entry size fails to init.
this->memory_.SetData8(0x1003, 0x1);
@@ -137,17 +127,14 @@
this->memory_.SetData32(0x140c, 0x200);
this->memory_.SetData16(0x1410, 0);
+ ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x200, 0x2000));
ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
- EXPECT_EQ(DW_EH_PE_udata2, this->eh_frame_->TestGetPtrEncoding());
EXPECT_EQ(0x1b, this->eh_frame_->TestGetTableEncoding());
EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
EXPECT_EQ(1U, this->eh_frame_->TestGetFdeCount());
- EXPECT_EQ(0x500U, this->eh_frame_->TestGetPtrOffset());
- EXPECT_EQ(0x100aU, this->eh_frame_->TestGetEntriesOffset());
- EXPECT_EQ(0x1100U, this->eh_frame_->TestGetEntriesEnd());
- EXPECT_EQ(0x1000U, this->eh_frame_->TestGetEntriesDataOffset());
- EXPECT_EQ(0x100aU, this->eh_frame_->TestGetCurEntriesOffset());
+ EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
+ EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
ASSERT_TRUE(fde != nullptr);
@@ -155,6 +142,115 @@
EXPECT_EQ(0x4700U, fde->pc_end);
}
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, Init_non_zero_load_bias_different_from_eh_frame_bias) {
+ this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4});
+ this->memory_.SetData16(0x1004, 0x500);
+ this->memory_.SetData32(0x1006, 1);
+ this->memory_.SetData32(0x100a, 0x2500);
+ this->memory_.SetData32(0x100e, 0x1400);
+
+ // CIE 32 information.
+ this->memory_.SetData32(0x1300, 0xfc);
+ this->memory_.SetData32(0x1304, 0);
+ this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
+
+ // FDE 32 information.
+ this->memory_.SetData32(0x1400, 0xfc);
+ this->memory_.SetData32(0x1404, 0x104);
+ this->memory_.SetData32(0x1408, 0x20f8);
+ this->memory_.SetData32(0x140c, 0x200);
+ this->memory_.SetData16(0x1410, 0);
+
+ ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x200, 0x1000));
+ ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0x2000));
+ EXPECT_EQ(1U, this->eh_frame_->TestGetVersion());
+ EXPECT_EQ(0x1b, this->eh_frame_->TestGetTableEncoding());
+ EXPECT_EQ(4U, this->eh_frame_->TestGetTableEntrySize());
+ EXPECT_EQ(1U, this->eh_frame_->TestGetFdeCount());
+ EXPECT_EQ(0x100aU, this->eh_frame_->TestGetHdrEntriesOffset());
+ EXPECT_EQ(0x1000U, this->eh_frame_->TestGetHdrEntriesDataOffset());
+
+ const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+ EXPECT_EQ(0x4700U, fde->pc_end);
+}
+
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeFromPc_wtih_empty_fde) {
+ this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4});
+ this->memory_.SetData16(0x1004, 0x500);
+ this->memory_.SetData32(0x1006, 1);
+ this->memory_.SetData32(0x100a, 0x2500);
+ this->memory_.SetData32(0x100e, 0x1400);
+
+ // CIE 32 information.
+ this->memory_.SetData32(0x1300, 0xfc);
+ this->memory_.SetData32(0x1304, 0);
+ this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
+
+ // FDE 32 information.
+ this->memory_.SetData32(0x1400, 0xfc);
+ this->memory_.SetData32(0x1404, 0x104);
+ this->memory_.SetData32(0x1408, 0x30f8);
+ this->memory_.SetData32(0x140c, 0);
+ this->memory_.SetData16(0x1410, 0);
+
+ // FDE 32 information.
+ this->memory_.SetData32(0x1500, 0xfc);
+ this->memory_.SetData32(0x1504, 0x204);
+ this->memory_.SetData32(0x1508, 0x2ff8);
+ this->memory_.SetData32(0x150c, 0x200);
+ this->memory_.SetData16(0x1510, 0);
+
+ ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x300, 0));
+ ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
+
+ const DwarfFde* fde = this->eh_frame_->GetFdeFromPc(0x4600);
+ ASSERT_TRUE(fde != nullptr);
+ EXPECT_EQ(0x4500U, fde->pc_start);
+ EXPECT_EQ(0x4700U, fde->pc_end);
+}
+
+TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes_with_empty_fde) {
+ this->memory_.SetMemory(0x1000, std::vector<uint8_t>{0x1, DW_EH_PE_udata2, DW_EH_PE_udata4,
+ DW_EH_PE_pcrel | DW_EH_PE_sdata4});
+ this->memory_.SetData16(0x1004, 0x500);
+ this->memory_.SetData32(0x1006, 1);
+ this->memory_.SetData32(0x100a, 0x2500);
+ this->memory_.SetData32(0x100e, 0x1400);
+
+ // CIE 32 information.
+ this->memory_.SetData32(0x1300, 0xfc);
+ this->memory_.SetData32(0x1304, 0);
+ this->memory_.SetMemory(0x1308, std::vector<uint8_t>{1, 'z', 'R', '\0', 0, 0, 0, 0, 0x1b});
+
+ // FDE 32 information.
+ this->memory_.SetData32(0x1400, 0xfc);
+ this->memory_.SetData32(0x1404, 0x104);
+ this->memory_.SetData32(0x1408, 0x30f8);
+ this->memory_.SetData32(0x140c, 0);
+ this->memory_.SetData16(0x1410, 0);
+
+ // FDE 32 information.
+ this->memory_.SetData32(0x1500, 0xfc);
+ this->memory_.SetData32(0x1504, 0x204);
+ this->memory_.SetData32(0x1508, 0x2ff8);
+ this->memory_.SetData32(0x150c, 0x200);
+ this->memory_.SetData16(0x1510, 0);
+
+ ASSERT_TRUE(this->eh_frame_->EhFrameInit(0x1300, 0x300, 0));
+ ASSERT_TRUE(this->eh_frame_->Init(0x1000, 0x100, 0));
+
+ std::vector<const DwarfFde*> fdes;
+ this->eh_frame_->GetFdes(&fdes);
+ ASSERT_FALSE(fdes.empty());
+ ASSERT_EQ(1U, fdes.size());
+ EXPECT_EQ(0x4500U, fdes[0]->pc_start);
+ EXPECT_EQ(0x4700U, fdes[0]->pc_end);
+}
+
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdes) {
this->memory_.SetMemory(
0x1000, std::vector<uint8_t>{1, DW_EH_PE_udata2, DW_EH_PE_udata4, DW_EH_PE_sdata4});
@@ -220,7 +316,7 @@
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_expect_cache_fail) {
this->eh_frame_->TestSetTableEntrySize(0x10);
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
- this->eh_frame_->TestSetEntriesOffset(0x1000);
+ this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
ASSERT_TRUE(this->eh_frame_->GetFdeInfoFromIndex(0) == nullptr);
ASSERT_EQ(DWARF_ERROR_MEMORY_INVALID, this->eh_frame_->LastErrorCode());
@@ -233,8 +329,8 @@
// We are assuming that pc rel, is really relative to the load_bias.
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_pcrel) {
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_pcrel | DW_EH_PE_udata4);
- this->eh_frame_->TestSetEntriesOffset(0x1000);
- this->eh_frame_->TestSetEntriesDataOffset(0x3000);
+ this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
+ this->eh_frame_->TestSetHdrEntriesDataOffset(0x3000);
this->eh_frame_->TestSetTableEntrySize(0x10);
this->memory_.SetData32(0x1040, 0x340);
@@ -248,8 +344,8 @@
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_read_datarel) {
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_datarel | DW_EH_PE_udata4);
- this->eh_frame_->TestSetEntriesOffset(0x1000);
- this->eh_frame_->TestSetEntriesDataOffset(0x3000);
+ this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
+ this->eh_frame_->TestSetHdrEntriesDataOffset(0x3000);
this->eh_frame_->TestSetTableEntrySize(0x10);
this->memory_.SetData32(0x1040, 0x340);
@@ -263,7 +359,7 @@
TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetFdeInfoFromIndex_cached) {
this->eh_frame_->TestSetTableEncoding(DW_EH_PE_udata4);
- this->eh_frame_->TestSetEntriesOffset(0x1000);
+ this->eh_frame_->TestSetHdrEntriesOffset(0x1000);
this->eh_frame_->TestSetTableEntrySize(0x10);
this->memory_.SetData32(0x1040, 0x340);
@@ -446,7 +542,9 @@
ASSERT_EQ(nullptr, this->eh_frame_->GetFdeFromPc(0x800));
}
-REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias, GetFdes,
+REGISTER_TYPED_TEST_SUITE_P(DwarfEhFrameWithHdrTest, Init, Init_non_zero_load_bias,
+ Init_non_zero_load_bias_different_from_eh_frame_bias,
+ GetFdeFromPc_wtih_empty_fde, GetFdes_with_empty_fde, GetFdes,
GetFdeInfoFromIndex_expect_cache_fail, GetFdeInfoFromIndex_read_pcrel,
GetFdeInfoFromIndex_read_datarel, GetFdeInfoFromIndex_cached,
GetFdeOffsetFromPc_verify, GetFdeOffsetFromPc_index_fail,
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index f0f5a1d..047af90 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -40,8 +40,8 @@
* Represents information about a zip entry in a zip file.
*/
struct ZipEntry {
- // Compression method: One of kCompressStored or
- // kCompressDeflated.
+ // Compression method. One of kCompressStored or kCompressDeflated.
+ // See also `gpbf` for deflate subtypes.
uint16_t method;
// Modification time. The zipfile format specifies
@@ -55,7 +55,7 @@
struct tm GetModificationTime() const;
// Suggested Unix mode for this entry, from the zip archive if created on
- // Unix, or a default otherwise.
+ // Unix, or a default otherwise. See also `external_file_attributes`.
mode_t unix_mode;
// 1 if this entry contains a data descriptor segment, 0
@@ -80,10 +80,16 @@
// The offset to the start of data for this ZipEntry.
off64_t offset;
- // The version of zip and the host file system this came from.
+ // The version of zip and the host file system this came from (for zipinfo).
uint16_t version_made_by;
- // Whether this entry is believed to be text or binary.
+ // The raw attributes, whose interpretation depends on the host
+ // file system in `version_made_by` (for zipinfo). See also `unix_mode`.
+ uint32_t external_file_attributes;
+
+ // Specifics about the deflation (for zipinfo).
+ uint16_t gpbf;
+ // Whether this entry is believed to be text or binary (for zipinfo).
bool is_text;
};
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index e936614..af70f1d 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -34,13 +34,21 @@
#include <android-base/strings.h>
#include <ziparchive/zip_archive.h>
+using android::base::EndsWith;
+using android::base::StartsWith;
+
enum OverwriteMode {
kAlways,
kNever,
kPrompt,
};
-static bool is_unzip;
+enum Role {
+ kUnzip,
+ kZipinfo,
+};
+
+static Role role;
static OverwriteMode overwrite_mode = kPrompt;
static bool flag_1 = false;
static const char* flag_d = nullptr;
@@ -92,7 +100,7 @@
}
static void MaybeShowHeader(ZipArchiveHandle zah) {
- if (is_unzip) {
+ if (role == kUnzip) {
// unzip has three formats.
if (!flag_q) printf("Archive: %s\n", archive_name);
if (flag_v) {
@@ -116,7 +124,7 @@
}
static void MaybeShowFooter() {
- if (is_unzip) {
+ if (role == kUnzip) {
if (flag_v) {
printf(
"-------- ------- --- -------\n"
@@ -185,8 +193,7 @@
static void ExtractOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
// Bad filename?
- if (android::base::StartsWith(name, "/") || android::base::StartsWith(name, "../") ||
- name.find("/../") != std::string::npos) {
+ if (StartsWith(name, "/") || StartsWith(name, "../") || name.find("/../") != std::string::npos) {
error(1, 0, "bad filename %s", name.c_str());
}
@@ -194,7 +201,7 @@
std::string dst;
if (flag_d) {
dst = flag_d;
- if (!android::base::EndsWith(dst, "/")) dst += '/';
+ if (!EndsWith(dst, "/")) dst += '/';
}
dst += name;
@@ -204,7 +211,7 @@
}
// An entry in a zip file can just be a directory itself.
- if (android::base::EndsWith(name, "/")) {
+ if (EndsWith(name, "/")) {
if (mkdir(name.c_str(), entry.unix_mode) == -1) {
// If the directory already exists, that's fine.
if (errno == EEXIST) {
@@ -258,9 +265,26 @@
int version = entry.version_made_by & 0xff;
int os = (entry.version_made_by >> 8) & 0xff;
- // TODO: Support suid/sgid? Non-Unix host file system attributes?
- char mode[] = "??????????";
- if (os == 3) {
+ // TODO: Support suid/sgid? Non-Unix/non-FAT host file system attributes?
+ const char* src_fs = "???";
+ char mode[] = "??? ";
+ if (os == 0) {
+ src_fs = "fat";
+ // https://docs.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
+ int attrs = entry.external_file_attributes & 0xff;
+ mode[0] = (attrs & 0x10) ? 'd' : '-';
+ mode[1] = 'r';
+ mode[2] = (attrs & 0x01) ? '-' : 'w';
+ // The man page also mentions ".btm", but that seems to be obsolete?
+ mode[3] = EndsWith(name, ".exe") || EndsWith(name, ".com") || EndsWith(name, ".bat") ||
+ EndsWith(name, ".cmd")
+ ? 'x'
+ : '-';
+ mode[4] = (attrs & 0x20) ? 'a' : '-';
+ mode[5] = (attrs & 0x02) ? 'h' : '-';
+ mode[6] = (attrs & 0x04) ? 's' : '-';
+ } else if (os == 3) {
+ src_fs = "unx";
mode[0] = S_ISDIR(entry.unix_mode) ? 'd' : (S_ISREG(entry.unix_mode) ? '-' : '?');
mode[1] = entry.unix_mode & S_IRUSR ? 'r' : '-';
mode[2] = entry.unix_mode & S_IWUSR ? 'w' : '-';
@@ -273,6 +297,11 @@
mode[9] = entry.unix_mode & S_IXOTH ? 'x' : '-';
}
+ char method[5] = "stor";
+ if (entry.method == kCompressDeflated) {
+ snprintf(method, sizeof(method), "def%c", "NXFS"[(entry.gpbf >> 1) & 0x3]);
+ }
+
// TODO: zipinfo (unlike unzip) sometimes uses time zone?
// TODO: this uses 4-digit years because we're not barbarians unless interoperability forces it.
tm t = entry.GetModificationTime();
@@ -281,14 +310,13 @@
t.tm_mday, t.tm_hour, t.tm_min);
// "-rw-r--r-- 3.0 unx 577 t- defX 19-Feb-12 16:09 android-ndk-r19b/sources/android/NOTICE"
- printf("%s %2d.%d %s %8d %c%c %s %s %s\n", mode, version / 10, version % 10,
- os == 3 ? "unx" : "???", entry.uncompressed_length, entry.is_text ? 't' : 'b',
- entry.has_data_descriptor ? 'X' : 'x', entry.method == kCompressStored ? "stor" : "defX",
- time, name.c_str());
+ printf("%s %2d.%d %s %8d %c%c %s %s %s\n", mode, version / 10, version % 10, src_fs,
+ entry.uncompressed_length, entry.is_text ? 't' : 'b',
+ entry.has_data_descriptor ? 'X' : 'x', method, time, name.c_str());
}
static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
- if (is_unzip) {
+ if (role == kUnzip) {
if (flag_l || flag_v) {
// -l or -lv or -lq or -v.
ListOne(entry, name);
@@ -333,7 +361,7 @@
}
static void ShowHelp(bool full) {
- if (is_unzip) {
+ if (role == kUnzip) {
fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n");
if (!full) exit(EXIT_FAILURE);
@@ -391,12 +419,28 @@
}
int main(int argc, char* argv[]) {
- static struct option opts[] = {
+ // Who am I, and what am I doing?
+ const char* base = basename(argv[0]);
+ if (!strcmp(base, "ziptool") && argc > 1) return main(argc - 1, argv + 1);
+ if (!strcmp(base, "unzip")) {
+ role = kUnzip;
+ } else if (!strcmp(base, "zipinfo")) {
+ role = kZipinfo;
+ } else {
+ error(1, 0, "run as ziptool with unzip or zipinfo as the first argument, or symlink");
+ }
+
+ static const struct option opts[] = {
{"help", no_argument, 0, 'h'},
};
- is_unzip = !strcmp(basename(argv[0]), "unzip");
- if (is_unzip) {
+ if (role == kUnzip) {
+ // `unzip -Z` is "zipinfo mode", so in that case just restart...
+ if (argc > 1 && !strcmp(argv[1], "-Z")) {
+ argv[1] = const_cast<char*>("zipinfo");
+ return main(argc - 1, argv + 1);
+ }
+
int opt;
while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) {
switch (opt) {
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index caf8fae..ef29188 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -622,12 +622,16 @@
// 4.4.2.1: the upper byte of `version_made_by` gives the source OS. Unix is 3.
data->version_made_by = cdr->version_made_by;
+ data->external_file_attributes = cdr->external_file_attributes;
if ((data->version_made_by >> 8) == 3) {
data->unix_mode = (cdr->external_file_attributes >> 16) & 0xffff;
} else {
data->unix_mode = 0777;
}
+ // 4.4.4: general purpose bit flags.
+ data->gpbf = lfh->gpb_flags;
+
// 4.4.14: the lowest bit of the internal file attributes field indicates text.
// Currently only needed to implement zipinfo.
data->is_text = (cdr->internal_file_attributes & 1);
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 1517c33..dc84fd2 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -43,11 +43,14 @@
#include <android-base/file.h>
#include <android-base/macros.h>
+#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <android/log.h>
#include <log/event_tag_map.h>
+#include <log/log_id.h>
#include <log/logprint.h>
#include <private/android_logger.h>
#include <processgroup/sched_policy.h>
@@ -55,62 +58,51 @@
#define DEFAULT_MAX_ROTATED_LOGS 4
+using android::base::Join;
+using android::base::ParseByteCount;
+using android::base::ParseUint;
+using android::base::Split;
using android::base::StringPrintf;
-struct log_device_t {
- const char* device;
- bool binary;
- struct logger* logger;
- struct logger_list* logger_list;
- bool printed;
-
- log_device_t* next;
-
- log_device_t(const char* d, bool b) {
- device = d;
- binary = b;
- next = nullptr;
- printed = false;
- logger = nullptr;
- logger_list = nullptr;
- }
-};
-
class Logcat {
public:
- ~Logcat();
-
int Run(int argc, char** argv);
private:
void RotateLogs();
- void ProcessBuffer(log_device_t* dev, struct log_msg* buf);
- void MaybePrintStart(log_device_t* dev, bool print_dividers);
+ void ProcessBuffer(struct log_msg* buf);
+ void PrintDividers(log_id_t log_id, bool print_dividers);
void SetupOutputAndSchedulingPolicy(bool blocking);
int SetLogFormat(const char* format_string);
+ // Used for all options
android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
android_log_format_new(), &android_log_format_free};
+
+ // For logging to a file and log rotation
const char* output_file_name_ = nullptr;
- // 0 means "no log rotation"
- size_t log_rotate_size_kb_ = 0;
- // 0 means "unbounded"
- size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS;
+ size_t log_rotate_size_kb_ = 0; // 0 means "no log rotation"
+ size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS; // 0 means "unbounded"
size_t out_byte_count_ = 0;
+
+ // For binary log buffers
int print_binary_ = 0;
- int dev_count_ = 0; // >1 means multiple
- std::unique_ptr<std::regex> regex_;
- log_device_t* devices_ = nullptr;
std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
nullptr, &android_closeEventTagMap};
- // 0 means "infinite"
- size_t max_count_ = 0;
- size_t print_count_ = 0;
-
- bool print_it_anyways_ = false;
- bool debug_ = false;
bool has_opened_event_tag_map_ = false;
+
+ // For the related --regex, --max-count, --print
+ std::unique_ptr<std::regex> regex_;
+ size_t max_count_ = 0; // 0 means "infinite"
+ size_t print_count_ = 0;
+ bool print_it_anyways_ = false;
+
+ // For PrintDividers()
+ log_id_t last_printed_id_ = LOG_ID_MAX;
+ bool printed_start_[LOG_ID_MAX] = {};
+
+ bool debug_ = false;
};
// logd prefixes records with a length field
@@ -186,13 +178,16 @@
out_byte_count_ = 0;
}
-void Logcat::ProcessBuffer(log_device_t* dev, struct log_msg* buf) {
+void Logcat::ProcessBuffer(struct log_msg* buf) {
int bytesWritten = 0;
int err;
AndroidLogEntry entry;
char binaryMsgBuf[1024];
- if (dev->binary) {
+ bool is_binary =
+ buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;
+
+ if (is_binary) {
if (!event_tag_map_ && !has_opened_event_tag_map_) {
event_tag_map_.reset(android_openEventTagMap(nullptr));
has_opened_event_tag_map_ = true;
@@ -228,16 +223,19 @@
}
}
-void Logcat::MaybePrintStart(log_device_t* dev, bool print_dividers) {
- if (!dev->printed || print_dividers) {
- if (dev_count_ > 1 && !print_binary_) {
- if (dprintf(output_fd_.get(), "--------- %s %s\n",
- dev->printed ? "switch to" : "beginning of", dev->device) < 0) {
- LogcatPanic(HELP_FALSE, "output error");
- }
- }
- dev->printed = true;
+void Logcat::PrintDividers(log_id_t log_id, bool print_dividers) {
+ if (log_id == last_printed_id_ || print_binary_) {
+ return;
}
+ if (!printed_start_[log_id] || print_dividers) {
+ if (dprintf(output_fd_.get(), "--------- %s %s\n",
+ printed_start_[log_id] ? "switch to" : "beginning of",
+ android_log_id_to_name(log_id)) < 0) {
+ LogcatPanic(HELP_FALSE, "output error");
+ }
+ }
+ last_printed_id_ = log_id;
+ printed_start_[log_id] = true;
}
void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
@@ -425,23 +423,6 @@
return std::make_pair(value, multipliers[i]);
}
-// String to unsigned int, returns -1 if it fails
-static bool getSizeTArg(const char* ptr, size_t* val, size_t min = 0,
- size_t max = SIZE_MAX) {
- if (!ptr) return false;
-
- char* endp;
- errno = 0;
- size_t ret = (size_t)strtoll(ptr, &endp, 0);
-
- if (endp[0] || errno) return false;
-
- if ((ret > max) || (ret < min)) return false;
-
- *val = ret;
- return true;
-}
-
static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
@@ -540,19 +521,18 @@
return retval;
}
-void reportErrorName(const char** current, const char* name,
- bool blockSecurity) {
- if (*current) return;
- if (!blockSecurity || (android_name_to_log_id(name) != LOG_ID_SECURITY)) {
- *current = name;
+void ReportErrorName(const std::string& name, bool allow_security,
+ std::vector<std::string>* errors) {
+ if (allow_security || name != "security") {
+ errors->emplace_back(name);
}
}
int Logcat::Run(int argc, char** argv) {
- int err;
bool hasSetLogFormat = false;
bool clearLog = false;
- bool allSelected = false;
+ bool security_buffer_selected =
+ false; // Do not report errors on the security buffer unless it is explicitly named.
bool getLogSize = false;
bool getPruneList = false;
bool printStatistics = false;
@@ -562,19 +542,11 @@
const char* setId = nullptr;
int mode = ANDROID_LOG_RDONLY;
std::string forceFilters;
- log_device_t* dev;
- struct logger_list* logger_list;
size_t tail_lines = 0;
log_time tail_time(log_time::EPOCH);
size_t pid = 0;
bool got_t = false;
-
- // object instantiations before goto's can happen
- log_device_t unexpected("unexpected", false);
- const char* openDeviceFail = nullptr;
- const char* clearFail = nullptr;
- const char* setSizeFail = nullptr;
- const char* getSizeFail = nullptr;
+ unsigned id_mask = 0;
if (argc == 2 && !strcmp(argv[1], "--help")) {
show_help();
@@ -640,7 +612,7 @@
}
// ToDo: determine runtime PID_MAX?
- if (!getSizeTArg(optarg, &pid, 1)) {
+ if (!ParseUint(optarg, &pid) || pid < 1) {
LogcatPanic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
@@ -651,7 +623,7 @@
ANDROID_LOG_NONBLOCK;
// ToDo: implement API that supports setting a wrap timeout
size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
- if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
+ if (optarg && (!ParseUint(optarg, &dummy) || dummy < 1)) {
LogcatPanic(HELP_TRUE, "%s %s out of range\n",
long_options[option_index].name, optarg);
}
@@ -712,7 +684,7 @@
*cp = ch;
}
} else {
- if (!getSizeTArg(optarg, &tail_lines, 1)) {
+ if (!ParseUint(optarg, &tail_lines) || tail_lines < 1) {
fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
tail_lines = 1;
}
@@ -728,7 +700,7 @@
break;
case 'm': {
- if (!getSizeTArg(optarg, &max_count_)) {
+ if (!ParseUint(optarg, &max_count_) || max_count_ < 1) {
LogcatPanic(HELP_FALSE, "-%c \"%s\" isn't an integer greater than zero\n", c,
optarg);
}
@@ -742,34 +714,7 @@
FALLTHROUGH_INTENDED;
case 'G': {
- char* cp;
- if (strtoll(optarg, &cp, 0) > 0) {
- setLogSize = strtoll(optarg, &cp, 0);
- } else {
- setLogSize = 0;
- }
-
- switch (*cp) {
- case 'g':
- case 'G':
- setLogSize *= 1024;
- FALLTHROUGH_INTENDED;
- case 'm':
- case 'M':
- setLogSize *= 1024;
- FALLTHROUGH_INTENDED;
- case 'k':
- case 'K':
- setLogSize *= 1024;
- FALLTHROUGH_INTENDED;
- case '\0':
- break;
-
- default:
- setLogSize = 0;
- }
-
- if (!setLogSize) {
+ if (!ParseByteCount(optarg, &setLogSize) || setLogSize < 1) {
LogcatPanic(HELP_FALSE, "ERROR: -G <num><multiplier>\n");
}
} break;
@@ -785,62 +730,24 @@
setPruneList = optarg;
break;
- case 'b': {
- std::unique_ptr<char, void (*)(void*)> buffers(strdup(optarg), free);
- char* arg = buffers.get();
- unsigned idMask = 0;
- char* sv = nullptr; // protect against -ENOMEM above
- while (!!(arg = strtok_r(arg, delimiters, &sv))) {
- if (!strcmp(arg, "default")) {
- idMask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) |
- (1 << LOG_ID_CRASH);
- } else if (!strcmp(arg, "all")) {
- allSelected = true;
- idMask = (unsigned)-1;
+ case 'b':
+ for (const auto& buffer : Split(optarg, delimiters)) {
+ if (buffer == "default") {
+ id_mask |= (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH);
+ } else if (buffer == "all") {
+ id_mask = -1;
} else {
- log_id_t log_id = android_name_to_log_id(arg);
- const char* name = android_log_id_to_name(log_id);
-
- if (!!strcmp(name, arg)) {
- LogcatPanic(HELP_TRUE, "unknown buffer %s\n", arg);
+ log_id_t log_id = android_name_to_log_id(buffer.c_str());
+ if (log_id >= LOG_ID_MAX) {
+ LogcatPanic(HELP_TRUE, "unknown buffer %s\n", buffer.c_str());
}
- if (log_id == LOG_ID_SECURITY) allSelected = false;
- idMask |= (1 << log_id);
- }
- arg = nullptr;
- }
-
- for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
- const char* name = android_log_id_to_name((log_id_t)i);
- log_id_t log_id = android_name_to_log_id(name);
-
- if (log_id != (log_id_t)i) continue;
- if (!(idMask & (1 << i))) continue;
-
- bool found = false;
- for (dev = devices_; dev; dev = dev->next) {
- if (!strcmp(name, dev->device)) {
- found = true;
- break;
+ if (log_id == LOG_ID_SECURITY) {
+ security_buffer_selected = true;
}
- if (!dev->next) break;
+ id_mask |= (1 << log_id);
}
- if (found) continue;
-
- bool binary = !strcmp(name, "events") ||
- !strcmp(name, "security") ||
- !strcmp(name, "stats");
- log_device_t* d = new log_device_t(name, binary);
-
- if (dev) {
- dev->next = d;
- dev = d;
- } else {
- devices_ = dev = d;
- }
- dev_count_++;
}
- } break;
+ break;
case 'B':
print_binary_ = 1;
@@ -855,34 +762,30 @@
break;
case 'r':
- if (!getSizeTArg(optarg, &log_rotate_size_kb_, 1)) {
+ if (!ParseUint(optarg, &log_rotate_size_kb_) || log_rotate_size_kb_ < 1) {
LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -r\n", optarg);
}
break;
case 'n':
- if (!getSizeTArg(optarg, &max_rotated_logs_, 1)) {
+ if (!ParseUint(optarg, &max_rotated_logs_) || max_rotated_logs_ < 1) {
LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -n\n", optarg);
}
break;
- case 'v': {
+ case 'v':
if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
show_format_help();
return EXIT_SUCCESS;
}
- std::unique_ptr<char, void (*)(void*)> formats(strdup(optarg), free);
- char* arg = formats.get();
- char* sv = nullptr; // protect against -ENOMEM above
- while (!!(arg = strtok_r(arg, delimiters, &sv))) {
- err = SetLogFormat(arg);
+ for (const auto& arg : Split(optarg, delimiters)) {
+ int err = SetLogFormat(arg.c_str());
if (err < 0) {
- LogcatPanic(HELP_FORMAT, "Invalid parameter \"%s\" to -v\n", arg);
+ LogcatPanic(HELP_FORMAT, "Invalid parameter \"%s\" to -v\n", arg.c_str());
}
- arg = nullptr;
if (err) hasSetLogFormat = true;
}
- } break;
+ break;
case 'Q':
#define LOGCAT_FILTER "androidboot.logcat="
@@ -1001,21 +904,10 @@
print_it_anyways_ = false;
}
- if (!devices_) {
- dev = devices_ = new log_device_t("main", false);
- dev_count_ = 1;
- if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
- dev = dev->next = new log_device_t("system", false);
- dev_count_++;
- }
- if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
- dev = dev->next = new log_device_t("crash", false);
- dev_count_++;
- }
- if (android_name_to_log_id("kernel") == LOG_ID_KERNEL) {
- dev = dev->next = new log_device_t("kernel", false);
- dev_count_++;
- }
+ // If no buffers are specified, default to using these buffers.
+ if (id_mask == 0) {
+ id_mask = (1 << LOG_ID_MAIN) | (1 << LOG_ID_SYSTEM) | (1 << LOG_ID_CRASH) |
+ (1 << LOG_ID_KERNEL);
}
if (log_rotate_size_kb_ != 0 && !output_file_name_) {
@@ -1039,17 +931,12 @@
const char* logFormat = getenv("ANDROID_PRINTF_LOG");
if (!!logFormat) {
- std::unique_ptr<char, void (*)(void*)> formats(strdup(logFormat),
- free);
- char* sv = nullptr; // protect against -ENOMEM above
- char* arg = formats.get();
- while (!!(arg = strtok_r(arg, delimiters, &sv))) {
- err = SetLogFormat(arg);
+ for (const auto& arg : Split(logFormat, delimiters)) {
+ int err = SetLogFormat(arg.c_str());
// environment should not cause crash of logcat
if (err < 0) {
- fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg);
+ fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg.c_str());
}
- arg = nullptr;
if (err > 0) hasSetLogFormat = true;
}
}
@@ -1059,7 +946,7 @@
}
if (forceFilters.size()) {
- err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
+ int err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
if (err < 0) {
LogcatPanic(HELP_FALSE, "Invalid filter expression in logcat args\n");
}
@@ -1068,7 +955,7 @@
const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
if (!!env_tags_orig) {
- err = android_log_addFilterString(logformat_.get(), env_tags_orig);
+ int err = android_log_addFilterString(logformat_.get(), env_tags_orig);
if (err < 0) {
LogcatPanic(HELP_TRUE, "Invalid filter expression in ANDROID_LOG_TAGS\n");
@@ -1077,33 +964,34 @@
} else {
// Add from commandline
for (int i = optind ; i < argc ; i++) {
- // skip stderr redirections of _all_ kinds
- if ((argv[i][0] == '2') && (argv[i][1] == '>')) continue;
- // skip stdout redirections of _all_ kinds
- if (argv[i][0] == '>') continue;
-
- err = android_log_addFilterString(logformat_.get(), argv[i]);
+ int err = android_log_addFilterString(logformat_.get(), argv[i]);
if (err < 0) {
LogcatPanic(HELP_TRUE, "Invalid filter expression '%s'\n", argv[i]);
}
}
}
- dev = devices_;
+ std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
+ nullptr, &android_logger_list_free};
if (tail_time != log_time::EPOCH) {
- logger_list = android_logger_list_alloc_time(mode, tail_time, pid);
+ logger_list.reset(android_logger_list_alloc_time(mode, tail_time, pid));
} else {
- logger_list = android_logger_list_alloc(mode, tail_lines, pid);
+ logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));
}
// We have three orthogonal actions below to clear, set log size and
// get log size. All sharing the same iteration loop.
- while (dev) {
- dev->logger_list = logger_list;
- dev->logger = android_logger_open(logger_list,
- android_name_to_log_id(dev->device));
- if (!dev->logger) {
- reportErrorName(&openDeviceFail, dev->device, allSelected);
- dev = dev->next;
+ std::vector<std::string> open_device_failures;
+ std::vector<std::string> clear_failures;
+ std::vector<std::string> set_size_failures;
+ std::vector<std::string> get_size_failures;
+
+ for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+ if (!(id_mask & (1 << i))) continue;
+ const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));
+
+ auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
+ if (logger == nullptr) {
+ ReportErrorName(buffer_name, security_buffer_selected, &open_device_failures);
continue;
}
@@ -1124,64 +1012,65 @@
if (!file.length()) {
perror("while clearing log files");
- reportErrorName(&clearFail, dev->device, allSelected);
+ ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
break;
}
- err = unlink(file.c_str());
+ int err = unlink(file.c_str());
- if (err < 0 && errno != ENOENT && !clearFail) {
+ if (err < 0 && errno != ENOENT) {
perror("while clearing log files");
- reportErrorName(&clearFail, dev->device, allSelected);
+ ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
}
}
- } else if (android_logger_clear(dev->logger)) {
- reportErrorName(&clearFail, dev->device, allSelected);
+ } else if (android_logger_clear(logger)) {
+ ReportErrorName(buffer_name, security_buffer_selected, &clear_failures);
}
}
if (setLogSize) {
- if (android_logger_set_log_size(dev->logger, setLogSize)) {
- reportErrorName(&setSizeFail, dev->device, allSelected);
+ if (android_logger_set_log_size(logger, setLogSize)) {
+ ReportErrorName(buffer_name, security_buffer_selected, &set_size_failures);
}
}
if (getLogSize) {
- long size = android_logger_get_log_size(dev->logger);
- long readable = android_logger_get_log_readable_size(dev->logger);
+ long size = android_logger_get_log_size(logger);
+ long readable = android_logger_get_log_readable_size(logger);
- if ((size < 0) || (readable < 0)) {
- reportErrorName(&getSizeFail, dev->device, allSelected);
+ if (size < 0 || readable < 0) {
+ ReportErrorName(buffer_name, security_buffer_selected, &get_size_failures);
} else {
auto size_format = format_of_size(size);
auto readable_format = format_of_size(readable);
std::string str = android::base::StringPrintf(
- "%s: ring buffer is %lu %sB (%lu %sB consumed),"
- " max entry is %d B, max payload is %d B\n",
- dev->device,
- size_format.first, size_format.second,
- readable_format.first, readable_format.second,
- (int)LOGGER_ENTRY_MAX_LEN,
- (int)LOGGER_ENTRY_MAX_PAYLOAD);
+ "%s: ring buffer is %lu %sB (%lu %sB consumed),"
+ " max entry is %d B, max payload is %d B\n",
+ buffer_name, size_format.first, size_format.second, readable_format.first,
+ readable_format.second, (int)LOGGER_ENTRY_MAX_LEN,
+ (int)LOGGER_ENTRY_MAX_PAYLOAD);
TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
}
}
-
- dev = dev->next;
}
// report any errors in the above loop and exit
- if (openDeviceFail) {
- LogcatPanic(HELP_FALSE, "Unable to open log device '%s'\n", openDeviceFail);
+ if (!open_device_failures.empty()) {
+ LogcatPanic(HELP_FALSE, "Unable to open log device%s '%s'\n",
+ open_device_failures.size() > 1 ? "s" : "",
+ Join(open_device_failures, ",").c_str());
}
- if (clearFail) {
- LogcatPanic(HELP_FALSE, "failed to clear the '%s' log\n", clearFail);
+ if (!clear_failures.empty()) {
+ LogcatPanic(HELP_FALSE, "failed to clear the '%s' log%s\n",
+ Join(clear_failures, ",").c_str(), clear_failures.size() > 1 ? "s" : "");
}
- if (setSizeFail) {
- LogcatPanic(HELP_FALSE, "failed to set the '%s' log size\n", setSizeFail);
+ if (!set_size_failures.empty()) {
+ LogcatPanic(HELP_FALSE, "failed to set the '%s' log size%s\n",
+ Join(set_size_failures, ",").c_str(), set_size_failures.size() > 1 ? "s" : "");
}
- if (getSizeFail) {
- LogcatPanic(HELP_FALSE, "failed to get the readable '%s' log size", getSizeFail);
+ if (!get_size_failures.empty()) {
+ LogcatPanic(HELP_FALSE, "failed to get the readable '%s' log size%s\n",
+ Join(get_size_failures, ",").c_str(), get_size_failures.size() > 1 ? "s" : "");
}
if (setPruneList) {
@@ -1191,7 +1080,7 @@
char* buf = nullptr;
if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
buf[len] = '\0';
- if (android_logger_set_prune_list(logger_list, buf, bLen)) {
+ if (android_logger_set_prune_list(logger_list.get(), buf, bLen)) {
LogcatPanic(HELP_FALSE, "failed to set the prune list");
}
free(buf);
@@ -1208,9 +1097,9 @@
for (int retry = 32; (retry >= 0) && ((buf = new char[len]));
delete[] buf, buf = nullptr, --retry) {
if (getPruneList) {
- android_logger_get_prune_list(logger_list, buf, len);
+ android_logger_get_prune_list(logger_list.get(), buf, len);
} else {
- android_logger_get_statistics(logger_list, buf, len);
+ android_logger_get_statistics(logger_list.get(), buf, len);
}
buf[len - 1] = '\0';
if (atol(buf) < 3) {
@@ -1253,11 +1142,9 @@
SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
- dev = nullptr;
-
while (!max_count_ || print_count_ < max_count_) {
struct log_msg log_msg;
- int ret = android_logger_list_read(logger_list, &log_msg);
+ int ret = android_logger_list_read(logger_list.get(), &log_msg);
if (!ret) {
LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
}
@@ -1274,24 +1161,17 @@
LogcatPanic(HELP_FALSE, "logcat read failure\n");
}
- log_device_t* d;
- for (d = devices_; d; d = d->next) {
- if (android_name_to_log_id(d->device) == log_msg.id()) break;
- }
- if (!d) {
- dev_count_ = 2; // set to Multiple
- d = &unexpected;
- d->binary = log_msg.id() == LOG_ID_EVENTS;
+ if (log_msg.id() > LOG_ID_MAX) {
+ LogcatPanic(HELP_FALSE, "read: unexpected log id (%d) over LOG_ID_MAX (%d)",
+ log_msg.id(), LOG_ID_MAX);
}
- if (dev != d) {
- dev = d;
- MaybePrintStart(dev, printDividers);
- }
+ PrintDividers(log_msg.id(), printDividers);
+
if (print_binary_) {
TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
} else {
- ProcessBuffer(dev, &log_msg);
+ ProcessBuffer(&log_msg);
}
}
return EXIT_SUCCESS;
@@ -1301,19 +1181,3 @@
Logcat logcat;
return logcat.Run(argc, argv);
}
-
-Logcat::~Logcat() {
- // generic cleanup of devices list to handle all possible dirty cases
- log_device_t* dev;
- while (!!(dev = devices_)) {
- struct logger_list* logger_list = dev->logger_list;
- if (logger_list) {
- for (log_device_t* d = dev; d; d = d->next) {
- if (d->logger_list == logger_list) d->logger_list = nullptr;
- }
- android_logger_list_free(logger_list);
- }
- devices_ = dev->next;
- delete dev;
- }
-}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index e1bb02f..5241730 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -326,7 +326,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.vendor)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.com.android.vndk.current)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
@@ -342,7 +342,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.vendor)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.com.android.vndk.current)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
@@ -358,7 +358,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.vendor)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.com.android.vndk.current)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)