Merge "libmodprobe: Do not reload modules previously instantiated"
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/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;
- }
-}