diff options
author | Christopher Ferris <cferris@google.com> | 2017-07-14 10:37:19 -0700 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2017-07-14 12:20:23 -0700 |
commit | d226a5140989f509a0ed3e2723f05d5fc93ce8df (patch) | |
tree | ffe7078dc51b6292506856c0a0982d2e8596612f /libunwindstack/include/unwindstack | |
parent | b76158d56af33f512cad32c5e948656e47a73216 (diff) | |
download | system_core-d226a5140989f509a0ed3e2723f05d5fc93ce8df.tar.gz system_core-d226a5140989f509a0ed3e2723f05d5fc93ce8df.tar.bz2 system_core-d226a5140989f509a0ed3e2723f05d5fc93ce8df.zip |
Make the library usable as a library.
- Add namespace unwindstack everywhere so that it's easier for other
code to use the library.
- Move some of the header files into include/unwindstack so that they
can be exposed.
- Modify the headers so that only a limited number need to be exposed.
- Update the tools to use the new headers.
- Add a GetLoadBias() call on the Elf object. This prevents the need
to get the interface object out of the Elf object.
- Move the GetRelPc() call out of the Reg class, to the Elf class. It's
not always the case that a Reg object will be around when you want to
get a relative pc. The tests for this moved to ElfTest.cpp.
Bug: 23762183
Test: Unit tests pass.
Change-Id: Iac609dac1dd90ed83d1a1e24ff2579c96c023bc3
Diffstat (limited to 'libunwindstack/include/unwindstack')
-rw-r--r-- | libunwindstack/include/unwindstack/DwarfLocation.h | 45 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/DwarfMemory.h | 76 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/DwarfSection.h | 141 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/DwarfStructs.h | 54 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Elf.h | 86 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/ElfInterface.h | 173 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Log.h | 29 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/MapInfo.h | 49 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Maps.h | 110 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Memory.h | 141 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/Regs.h | 141 | ||||
-rw-r--r-- | libunwindstack/include/unwindstack/RegsGetLocal.h | 104 |
12 files changed, 1149 insertions, 0 deletions
diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h new file mode 100644 index 000000000..3467e6a8f --- /dev/null +++ b/libunwindstack/include/unwindstack/DwarfLocation.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_DWARF_LOCATION_H +#define _LIBUNWINDSTACK_DWARF_LOCATION_H + +#include <stdint.h> + +#include <unordered_map> + +namespace unwindstack { + +enum DwarfLocationEnum : uint8_t { + DWARF_LOCATION_INVALID = 0, + DWARF_LOCATION_UNDEFINED, + DWARF_LOCATION_OFFSET, + DWARF_LOCATION_VAL_OFFSET, + DWARF_LOCATION_REGISTER, + DWARF_LOCATION_EXPRESSION, + DWARF_LOCATION_VAL_EXPRESSION, +}; + +struct DwarfLocation { + DwarfLocationEnum type; + uint64_t values[2]; +}; + +typedef std::unordered_map<uint16_t, DwarfLocation> dwarf_loc_regs_t; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_DWARF_LOCATION_H diff --git a/libunwindstack/include/unwindstack/DwarfMemory.h b/libunwindstack/include/unwindstack/DwarfMemory.h new file mode 100644 index 000000000..8dd8d2bb1 --- /dev/null +++ b/libunwindstack/include/unwindstack/DwarfMemory.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_DWARF_MEMORY_H +#define _LIBUNWINDSTACK_DWARF_MEMORY_H + +#include <stdint.h> + +namespace unwindstack { + +// Forward declarations. +class Memory; + +class DwarfMemory { + public: + DwarfMemory(Memory* memory) : memory_(memory) {} + virtual ~DwarfMemory() = default; + + bool ReadBytes(void* dst, size_t num_bytes); + + template <typename SignedType> + bool ReadSigned(uint64_t* value); + + bool ReadULEB128(uint64_t* value); + + bool ReadSLEB128(int64_t* value); + + template <typename AddressType> + size_t GetEncodedSize(uint8_t encoding); + + bool AdjustEncodedValue(uint8_t encoding, uint64_t* value); + + template <typename AddressType> + bool ReadEncodedValue(uint8_t encoding, uint64_t* value); + + uint64_t cur_offset() { return cur_offset_; } + void set_cur_offset(uint64_t cur_offset) { cur_offset_ = cur_offset; } + + void set_pc_offset(uint64_t offset) { pc_offset_ = offset; } + void clear_pc_offset() { pc_offset_ = static_cast<uint64_t>(-1); } + + void set_data_offset(uint64_t offset) { data_offset_ = offset; } + void clear_data_offset() { data_offset_ = static_cast<uint64_t>(-1); } + + void set_func_offset(uint64_t offset) { func_offset_ = offset; } + void clear_func_offset() { func_offset_ = static_cast<uint64_t>(-1); } + + void set_text_offset(uint64_t offset) { text_offset_ = offset; } + void clear_text_offset() { text_offset_ = static_cast<uint64_t>(-1); } + + private: + Memory* memory_; + uint64_t cur_offset_ = 0; + + uint64_t pc_offset_ = static_cast<uint64_t>(-1); + uint64_t data_offset_ = static_cast<uint64_t>(-1); + uint64_t func_offset_ = static_cast<uint64_t>(-1); + uint64_t text_offset_ = static_cast<uint64_t>(-1); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_DWARF_MEMORY_H diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h new file mode 100644 index 000000000..a97ca2b1d --- /dev/null +++ b/libunwindstack/include/unwindstack/DwarfSection.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_DWARF_SECTION_H +#define _LIBUNWINDSTACK_DWARF_SECTION_H + +#include <stdint.h> + +#include <iterator> +#include <unordered_map> + +#include <unwindstack/DwarfLocation.h> +#include <unwindstack/DwarfMemory.h> +#include <unwindstack/DwarfStructs.h> + +namespace unwindstack { + +// Forward declarations. +enum DwarfError : uint8_t; +class Memory; +class Regs; + +class DwarfSection { + public: + DwarfSection(Memory* memory); + virtual ~DwarfSection() = default; + + class iterator : public std::iterator<std::bidirectional_iterator_tag, DwarfFde*> { + public: + iterator(DwarfSection* section, size_t index) : section_(section), index_(index) {} + + iterator& operator++() { + index_++; + return *this; + } + iterator& operator++(int increment) { + index_ += increment; + return *this; + } + iterator& operator--() { + index_--; + return *this; + } + iterator& operator--(int decrement) { + index_ -= decrement; + return *this; + } + + bool operator==(const iterator& rhs) { return this->index_ == rhs.index_; } + bool operator!=(const iterator& rhs) { return this->index_ != rhs.index_; } + + const DwarfFde* operator*() { return section_->GetFdeFromIndex(index_); } + + private: + DwarfSection* section_ = nullptr; + size_t index_ = 0; + }; + + iterator begin() { return iterator(this, 0); } + iterator end() { return iterator(this, fde_count_); } + + DwarfError last_error() { return last_error_; } + + virtual bool Init(uint64_t offset, uint64_t size) = 0; + + virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*) = 0; + + virtual bool GetFdeOffsetFromPc(uint64_t pc, uint64_t* fde_offset) = 0; + + virtual bool Log(uint8_t indent, uint64_t pc, uint64_t load_bias, const DwarfFde* fde) = 0; + + virtual const DwarfFde* GetFdeFromIndex(size_t index) = 0; + + const DwarfFde* GetFdeFromPc(uint64_t pc); + + virtual const DwarfFde* GetFdeFromOffset(uint64_t fde_offset) = 0; + + virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) = 0; + + virtual bool IsCie32(uint32_t value32) = 0; + + virtual bool IsCie64(uint64_t value64) = 0; + + virtual uint64_t GetCieOffsetFromFde32(uint32_t pointer) = 0; + + virtual uint64_t GetCieOffsetFromFde64(uint64_t pointer) = 0; + + virtual uint64_t AdjustPcFromFde(uint64_t pc) = 0; + + bool Step(uint64_t pc, Regs* regs, Memory* process_memory); + + protected: + DwarfMemory memory_; + DwarfError last_error_; + + uint64_t fde_count_; + std::unordered_map<uint64_t, DwarfFde> fde_entries_; + std::unordered_map<uint64_t, DwarfCie> cie_entries_; + std::unordered_map<uint64_t, dwarf_loc_regs_t> cie_loc_regs_; +}; + +template <typename AddressType> +class DwarfSectionImpl : public DwarfSection { + public: + DwarfSectionImpl(Memory* memory) : DwarfSection(memory) {} + virtual ~DwarfSectionImpl() = default; + + bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs, + Regs* regs) override; + + const DwarfCie* GetCie(uint64_t offset); + bool FillInCie(DwarfCie* cie); + + const DwarfFde* GetFdeFromOffset(uint64_t offset) override; + bool FillInFde(DwarfFde* fde); + + bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) override; + + bool Log(uint8_t indent, uint64_t pc, uint64_t load_bias, const DwarfFde* fde) override; + + protected: + bool EvalExpression(const DwarfLocation& loc, uint8_t version, Memory* regular_memory, + AddressType* value); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_DWARF_SECTION_H diff --git a/libunwindstack/include/unwindstack/DwarfStructs.h b/libunwindstack/include/unwindstack/DwarfStructs.h new file mode 100644 index 000000000..4b481f082 --- /dev/null +++ b/libunwindstack/include/unwindstack/DwarfStructs.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_DWARF_STRUCTS_H +#define _LIBUNWINDSTACK_DWARF_STRUCTS_H + +#include <stdint.h> + +#include <vector> + +namespace unwindstack { + +struct DwarfCie { + uint8_t version = 0; + uint8_t fde_address_encoding = 0; + uint8_t lsda_encoding = 0; + uint8_t segment_size = 0; + std::vector<char> augmentation_string; + uint64_t personality_handler = 0; + uint64_t cfa_instructions_offset = 0; + uint64_t cfa_instructions_end = 0; + uint64_t code_alignment_factor = 0; + int64_t data_alignment_factor = 0; + uint64_t return_address_register = 0; +}; + +struct DwarfFde { + uint64_t cie_offset = 0; + uint64_t cfa_instructions_offset = 0; + uint64_t cfa_instructions_end = 0; + uint64_t pc_start = 0; + uint64_t pc_end = 0; + uint64_t lsda_address = 0; + const DwarfCie* cie = nullptr; +}; + +constexpr uint16_t CFA_REG = static_cast<uint16_t>(-1); + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_DWARF_STRUCTS_H diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h new file mode 100644 index 000000000..d89a7464a --- /dev/null +++ b/libunwindstack/include/unwindstack/Elf.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_ELF_H +#define _LIBUNWINDSTACK_ELF_H + +#include <stddef.h> + +#include <memory> +#include <string> + +#include <unwindstack/ElfInterface.h> +#include <unwindstack/Memory.h> + +#if !defined(EM_AARCH64) +#define EM_AARCH64 183 +#endif + +namespace unwindstack { + +// Forward declaration. +struct MapInfo; +class Regs; + +class Elf { + public: + Elf(Memory* memory) : memory_(memory) {} + virtual ~Elf() = default; + + bool Init(); + + void InitGnuDebugdata(); + + bool GetSoname(std::string* name); + + bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset); + + uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info); + + bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory); + + ElfInterface* CreateInterfaceFromMemory(Memory* memory); + + uint64_t GetLoadBias(); + + bool valid() { return valid_; } + + uint32_t machine_type() { return machine_type_; } + + uint8_t class_type() { return class_type_; } + + Memory* memory() { return memory_.get(); } + + ElfInterface* interface() { return interface_.get(); } + + ElfInterface* gnu_debugdata_interface() { return gnu_debugdata_interface_.get(); } + + static bool IsValidElf(Memory* memory); + + protected: + bool valid_ = false; + std::unique_ptr<ElfInterface> interface_; + std::unique_ptr<Memory> memory_; + uint32_t machine_type_; + uint8_t class_type_; + + std::unique_ptr<Memory> gnu_debugdata_memory_; + std::unique_ptr<ElfInterface> gnu_debugdata_interface_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_ELF_H diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h new file mode 100644 index 000000000..5cac0d358 --- /dev/null +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_ELF_INTERFACE_H +#define _LIBUNWINDSTACK_ELF_INTERFACE_H + +#include <elf.h> +#include <stdint.h> + +#include <memory> +#include <string> +#include <unordered_map> +#include <vector> + +#include <unwindstack/DwarfSection.h> + +namespace unwindstack { + +// Forward declarations. +class Memory; +class Regs; +class Symbols; + +struct LoadInfo { + uint64_t offset; + uint64_t table_offset; + size_t table_size; +}; + +enum : uint8_t { + SONAME_UNKNOWN = 0, + SONAME_VALID, + SONAME_INVALID, +}; + +class ElfInterface { + public: + ElfInterface(Memory* memory) : memory_(memory) {} + virtual ~ElfInterface(); + + virtual bool Init() = 0; + + virtual void InitHeaders() = 0; + + virtual bool GetSoname(std::string* name) = 0; + + virtual bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* offset) = 0; + + virtual bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory); + + Memory* CreateGnuDebugdataMemory(); + + Memory* memory() { return memory_; } + + const std::unordered_map<uint64_t, LoadInfo>& pt_loads() { return pt_loads_; } + uint64_t load_bias() { return load_bias_; } + void set_load_bias(uint64_t load_bias) { load_bias_ = load_bias; } + + uint64_t dynamic_offset() { return dynamic_offset_; } + uint64_t dynamic_size() { return dynamic_size_; } + uint64_t eh_frame_offset() { return eh_frame_offset_; } + uint64_t eh_frame_size() { return eh_frame_size_; } + uint64_t debug_frame_offset() { return debug_frame_offset_; } + uint64_t debug_frame_size() { return debug_frame_size_; } + uint64_t gnu_debugdata_offset() { return gnu_debugdata_offset_; } + uint64_t gnu_debugdata_size() { return gnu_debugdata_size_; } + + DwarfSection* eh_frame() { return eh_frame_.get(); } + DwarfSection* debug_frame() { return debug_frame_.get(); } + + protected: + template <typename AddressType> + void InitHeadersWithTemplate(); + + template <typename EhdrType, typename PhdrType, typename ShdrType> + bool ReadAllHeaders(); + + template <typename EhdrType, typename PhdrType> + bool ReadProgramHeaders(const EhdrType& ehdr); + + template <typename EhdrType, typename ShdrType> + bool ReadSectionHeaders(const EhdrType& ehdr); + + template <typename DynType> + bool GetSonameWithTemplate(std::string* soname); + + template <typename SymType> + bool GetFunctionNameWithTemplate(uint64_t addr, std::string* name, uint64_t* func_offset); + + virtual bool HandleType(uint64_t, uint32_t) { return false; } + + Memory* memory_; + std::unordered_map<uint64_t, LoadInfo> pt_loads_; + uint64_t load_bias_ = 0; + + // Stored elf data. + uint64_t dynamic_offset_ = 0; + uint64_t dynamic_size_ = 0; + + uint64_t eh_frame_offset_ = 0; + uint64_t eh_frame_size_ = 0; + + uint64_t debug_frame_offset_ = 0; + uint64_t debug_frame_size_ = 0; + + uint64_t gnu_debugdata_offset_ = 0; + uint64_t gnu_debugdata_size_ = 0; + + uint8_t soname_type_ = SONAME_UNKNOWN; + std::string soname_; + + std::unique_ptr<DwarfSection> eh_frame_; + std::unique_ptr<DwarfSection> debug_frame_; + + std::vector<Symbols*> symbols_; +}; + +class ElfInterface32 : public ElfInterface { + public: + ElfInterface32(Memory* memory) : ElfInterface(memory) {} + virtual ~ElfInterface32() = default; + + bool Init() override { + return ElfInterface::ReadAllHeaders<Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr>(); + } + + void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint32_t>(); } + + bool GetSoname(std::string* soname) override { + return ElfInterface::GetSonameWithTemplate<Elf32_Dyn>(soname); + } + + bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { + return ElfInterface::GetFunctionNameWithTemplate<Elf32_Sym>(addr, name, func_offset); + } +}; + +class ElfInterface64 : public ElfInterface { + public: + ElfInterface64(Memory* memory) : ElfInterface(memory) {} + virtual ~ElfInterface64() = default; + + bool Init() override { + return ElfInterface::ReadAllHeaders<Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr>(); + } + + void InitHeaders() override { ElfInterface::InitHeadersWithTemplate<uint64_t>(); } + + bool GetSoname(std::string* soname) override { + return ElfInterface::GetSonameWithTemplate<Elf64_Dyn>(soname); + } + + bool GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offset) override { + return ElfInterface::GetFunctionNameWithTemplate<Elf64_Sym>(addr, name, func_offset); + } +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_ELF_INTERFACE_H diff --git a/libunwindstack/include/unwindstack/Log.h b/libunwindstack/include/unwindstack/Log.h new file mode 100644 index 000000000..aa1219c26 --- /dev/null +++ b/libunwindstack/include/unwindstack/Log.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_LOG_H +#define _LIBUNWINDSTACK_LOG_H + +#include <stdint.h> + +namespace unwindstack { + +void log_to_stdout(bool enable); +void log(uint8_t indent, const char* format, ...); + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_LOG_H diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h new file mode 100644 index 000000000..2a97dde09 --- /dev/null +++ b/libunwindstack/include/unwindstack/MapInfo.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_MAP_INFO_H +#define _LIBUNWINDSTACK_MAP_INFO_H + +#include <stdint.h> + +#include <string> + +namespace unwindstack { + +// Forward declarations. +class Elf; +class Memory; + +struct MapInfo { + uint64_t start; + uint64_t end; + uint64_t offset; + uint16_t flags; + std::string name; + Elf* elf = nullptr; + // This value is only non-zero if the offset is non-zero but there is + // no elf signature found at that offset. This indicates that the + // entire file is represented by the Memory object returned by CreateMemory, + // instead of a portion of the file. + uint64_t elf_offset; + + Memory* CreateMemory(pid_t pid); + Elf* GetElf(pid_t pid, bool init_gnu_debugdata = false); +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MAP_INFO_H diff --git a/libunwindstack/include/unwindstack/Maps.h b/libunwindstack/include/unwindstack/Maps.h new file mode 100644 index 000000000..0b02739dc --- /dev/null +++ b/libunwindstack/include/unwindstack/Maps.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_MAPS_H +#define _LIBUNWINDSTACK_MAPS_H + +#include <sys/types.h> +#include <unistd.h> + +#include <string> +#include <vector> + +#include <unwindstack/MapInfo.h> + +namespace unwindstack { + +// Special flag to indicate a map is in /dev/. However, a map in +// /dev/ashmem/... does not set this flag. +static constexpr int MAPS_FLAGS_DEVICE_MAP = 0x8000; + +class Maps { + public: + Maps() = default; + virtual ~Maps(); + + MapInfo* Find(uint64_t pc); + + bool ParseLine(const char* line, MapInfo* map_info); + + virtual bool Parse(); + + virtual const std::string GetMapsFile() const { return ""; } + + typedef std::vector<MapInfo>::iterator iterator; + iterator begin() { return maps_.begin(); } + iterator end() { return maps_.end(); } + + typedef std::vector<MapInfo>::const_iterator const_iterator; + const_iterator begin() const { return maps_.begin(); } + const_iterator end() const { return maps_.end(); } + + size_t Total() { return maps_.size(); } + + protected: + std::vector<MapInfo> maps_; +}; + +class RemoteMaps : public Maps { + public: + RemoteMaps(pid_t pid) : pid_(pid) {} + virtual ~RemoteMaps() = default; + + virtual const std::string GetMapsFile() const override; + + private: + pid_t pid_; +}; + +class LocalMaps : public RemoteMaps { + public: + LocalMaps() : RemoteMaps(getpid()) {} + virtual ~LocalMaps() = default; +}; + +class BufferMaps : public Maps { + public: + BufferMaps(const char* buffer) : buffer_(buffer) {} + virtual ~BufferMaps() = default; + + bool Parse() override; + + private: + const char* buffer_; +}; + +class FileMaps : public Maps { + public: + FileMaps(const std::string& file) : file_(file) {} + virtual ~FileMaps() = default; + + const std::string GetMapsFile() const override { return file_; } + + protected: + const std::string file_; +}; + +class OfflineMaps : public FileMaps { + public: + OfflineMaps(const std::string& file) : FileMaps(file) {} + virtual ~OfflineMaps() = default; + + bool Parse() override; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MAPS_H diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h new file mode 100644 index 000000000..0c0526616 --- /dev/null +++ b/libunwindstack/include/unwindstack/Memory.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_MEMORY_H +#define _LIBUNWINDSTACK_MEMORY_H + +#include <stdint.h> +#include <sys/types.h> +#include <unistd.h> + +#include <string> +#include <vector> + +namespace unwindstack { + +class Memory { + public: + Memory() = default; + virtual ~Memory() = default; + + virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX); + + virtual bool Read(uint64_t addr, void* dst, size_t size) = 0; + + inline bool ReadField(uint64_t addr, void* start, void* field, size_t size) { + if (reinterpret_cast<uintptr_t>(field) < reinterpret_cast<uintptr_t>(start)) { + return false; + } + uint64_t offset = reinterpret_cast<uintptr_t>(field) - reinterpret_cast<uintptr_t>(start); + if (__builtin_add_overflow(addr, offset, &offset)) { + return false; + } + // The read will check if offset + size overflows. + return Read(offset, field, size); + } + + inline bool Read32(uint64_t addr, uint32_t* dst) { return Read(addr, dst, sizeof(uint32_t)); } + + inline bool Read64(uint64_t addr, uint64_t* dst) { return Read(addr, dst, sizeof(uint64_t)); } +}; + +class MemoryBuffer : public Memory { + public: + MemoryBuffer() = default; + virtual ~MemoryBuffer() = default; + + bool Read(uint64_t addr, void* dst, size_t size) override; + + uint8_t* GetPtr(size_t offset); + + void Resize(size_t size) { raw_.resize(size); } + + uint64_t Size() { return raw_.size(); } + + private: + std::vector<uint8_t> raw_; +}; + +class MemoryFileAtOffset : public Memory { + public: + MemoryFileAtOffset() = default; + virtual ~MemoryFileAtOffset(); + + bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX); + + bool Read(uint64_t addr, void* dst, size_t size) override; + + void Clear(); + + protected: + size_t size_ = 0; + size_t offset_ = 0; + uint8_t* data_ = nullptr; +}; + +class MemoryOffline : public MemoryFileAtOffset { + public: + MemoryOffline() = default; + virtual ~MemoryOffline() = default; + + bool Init(const std::string& file, uint64_t offset); + + bool Read(uint64_t addr, void* dst, size_t size) override; + + private: + uint64_t start_; +}; + +class MemoryRemote : public Memory { + public: + MemoryRemote(pid_t pid) : pid_(pid) {} + virtual ~MemoryRemote() = default; + + bool Read(uint64_t addr, void* dst, size_t size) override; + + pid_t pid() { return pid_; } + + protected: + virtual bool PtraceRead(uint64_t addr, long* value); + + private: + pid_t pid_; +}; + +class MemoryLocal : public Memory { + public: + MemoryLocal() = default; + virtual ~MemoryLocal() = default; + + bool Read(uint64_t addr, void* dst, size_t size) override; +}; + +class MemoryRange : public Memory { + public: + MemoryRange(Memory* memory, uint64_t begin, uint64_t end); + virtual ~MemoryRange() { delete memory_; } + + bool Read(uint64_t addr, void* dst, size_t size) override; + + private: + Memory* memory_; + uint64_t begin_; + uint64_t length_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_H diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h new file mode 100644 index 000000000..ab98f3223 --- /dev/null +++ b/libunwindstack/include/unwindstack/Regs.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBUNWINDSTACK_REGS_H +#define _LIBUNWINDSTACK_REGS_H + +#include <stdint.h> + +#include <vector> + +namespace unwindstack { + +// Forward declarations. +class Elf; +struct MapInfo; +class Memory; + +class Regs { + public: + enum LocationEnum : uint8_t { + LOCATION_UNKNOWN = 0, + LOCATION_REGISTER, + LOCATION_SP_OFFSET, + }; + + struct Location { + Location(LocationEnum type, int16_t value) : type(type), value(value) {} + + LocationEnum type; + int16_t value; + }; + + Regs(uint16_t total_regs, uint16_t sp_reg, const Location& return_loc) + : total_regs_(total_regs), sp_reg_(sp_reg), return_loc_(return_loc) {} + virtual ~Regs() = default; + + virtual void* RawData() = 0; + virtual uint64_t pc() = 0; + virtual uint64_t sp() = 0; + + virtual bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) = 0; + + virtual uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) = 0; + + virtual void SetFromRaw() = 0; + + uint16_t sp_reg() { return sp_reg_; } + uint16_t total_regs() { return total_regs_; } + + static uint32_t GetMachineType(); + static Regs* RemoteGet(pid_t pid, uint32_t* machine_type); + static Regs* CreateFromUcontext(uint32_t machine_type, void* ucontext); + static Regs* CreateFromLocal(); + + protected: + uint16_t total_regs_; + uint16_t sp_reg_; + Location return_loc_; +}; + +template <typename AddressType> +class RegsImpl : public Regs { + public: + RegsImpl(uint16_t total_regs, uint16_t sp_reg, Location return_loc) + : Regs(total_regs, sp_reg, return_loc), regs_(total_regs) {} + virtual ~RegsImpl() = default; + + bool GetReturnAddressFromDefault(Memory* memory, uint64_t* value) override; + + uint64_t pc() override { return pc_; } + uint64_t sp() override { return sp_; } + + void set_pc(AddressType pc) { pc_ = pc; } + void set_sp(AddressType sp) { sp_ = sp; } + + inline AddressType& operator[](size_t reg) { return regs_[reg]; } + + void* RawData() override { return regs_.data(); } + + protected: + AddressType pc_; + AddressType sp_; + std::vector<AddressType> regs_; +}; + +class RegsArm : public RegsImpl<uint32_t> { + public: + RegsArm(); + virtual ~RegsArm() = default; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; +}; + +class RegsArm64 : public RegsImpl<uint64_t> { + public: + RegsArm64(); + virtual ~RegsArm64() = default; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; +}; + +class RegsX86 : public RegsImpl<uint32_t> { + public: + RegsX86(); + virtual ~RegsX86() = default; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; +}; + +class RegsX86_64 : public RegsImpl<uint64_t> { + public: + RegsX86_64(); + virtual ~RegsX86_64() = default; + + uint64_t GetAdjustedPc(uint64_t rel_pc, Elf* elf) override; + + void SetFromRaw() override; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_REGS_H diff --git a/libunwindstack/include/unwindstack/RegsGetLocal.h b/libunwindstack/include/unwindstack/RegsGetLocal.h new file mode 100644 index 000000000..ffec213e8 --- /dev/null +++ b/libunwindstack/include/unwindstack/RegsGetLocal.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _LIBUNWINDSTACK_REGS_GET_LOCAL_H +#define _LIBUNWINDSTACK_REGS_GET_LOCAL_H + +namespace unwindstack { + +#if defined(__arm__) + +inline void RegsGetLocal(Regs* regs) { + void* reg_data = regs->RawData(); + asm volatile( + ".align 2\n" + "bx pc\n" + "nop\n" + ".code 32\n" + "stmia %[base], {r0-r12}\n" + "add %[base], #52\n" + "mov r1, r13\n" + "mov r2, r14\n" + "mov r3, r15\n" + "stmia %[base], {r1-r3}\n" + "orr %[base], pc, #1\n" + "bx %[base]\n" + : [base] "+r"(reg_data) + : + : "memory"); + + regs->SetFromRaw(); +} + +#elif defined(__aarch64__) + +inline void RegsGetLocal(Regs* regs) { + void* reg_data = regs->RawData(); + asm volatile( + "1:\n" + "stp x0, x1, [%[base], #0]\n" + "stp x2, x3, [%[base], #16]\n" + "stp x4, x5, [%[base], #32]\n" + "stp x6, x7, [%[base], #48]\n" + "stp x8, x9, [%[base], #64]\n" + "stp x10, x11, [%[base], #80]\n" + "stp x12, x13, [%[base], #96]\n" + "stp x14, x15, [%[base], #112]\n" + "stp x16, x17, [%[base], #128]\n" + "stp x18, x19, [%[base], #144]\n" + "stp x20, x21, [%[base], #160]\n" + "stp x22, x23, [%[base], #176]\n" + "stp x24, x25, [%[base], #192]\n" + "stp x26, x27, [%[base], #208]\n" + "stp x28, x29, [%[base], #224]\n" + "str x30, [%[base], #240]\n" + "mov x12, sp\n" + "adr x13, 1b\n" + "stp x12, x13, [%[base], #248]\n" + : [base] "+r"(reg_data) + : + : "x12", "x13", "memory"); + + regs->SetFromRaw(); +} + +#elif defined(__i386__) || defined(__x86_64__) + +extern "C" void AsmGetRegs(void* regs); + +inline void RegsGetLocal(Regs* regs) { + AsmGetRegs(regs->RawData()); + + regs->SetFromRaw(); +} + +#endif + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_REGS_GET_LOCAL_H |