Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 052dd1ba authored by Christopher Ferris's avatar Christopher Ferris Committed by android-build-merger
Browse files

Merge "Add DwarfMemory class."

am: ce124179

Change-Id: If3928bf14f25d792f512b3a67cdc5b05c14e7f0a
parents ba54f32b ce124179
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ cc_defaults {

    srcs: [
        "ArmExidx.cpp",
        "DwarfMemory.cpp",
        "Elf.cpp",
        "ElfInterface.cpp",
        "ElfInterfaceArm.cpp",
@@ -87,6 +88,7 @@ cc_defaults {
    srcs: [
        "tests/ArmExidxDecodeTest.cpp",
        "tests/ArmExidxExtractTest.cpp",
        "tests/DwarfMemoryTest.cpp",
        "tests/ElfInterfaceArmTest.cpp",
        "tests/ElfInterfaceTest.cpp",
        "tests/ElfTest.cpp",
+47 −0
Original line number Diff line number Diff line
/*
 * 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_ENCODING_H
#define _LIBUNWINDSTACK_DWARF_ENCODING_H

#include <stdint.h>

enum DwarfEncoding : uint8_t {
  DW_EH_PE_omit = 0xff,

  DW_EH_PE_absptr = 0x00,
  DW_EH_PE_uleb128 = 0x01,
  DW_EH_PE_udata2 = 0x02,
  DW_EH_PE_udata4 = 0x03,
  DW_EH_PE_udata8 = 0x04,
  DW_EH_PE_sleb128 = 0x09,
  DW_EH_PE_sdata2 = 0x0a,
  DW_EH_PE_sdata4 = 0x0b,
  DW_EH_PE_sdata8 = 0x0c,

  DW_EH_PE_pcrel = 0x10,
  DW_EH_PE_textrel = 0x20,
  DW_EH_PE_datarel = 0x30,
  DW_EH_PE_funcrel = 0x40,
  DW_EH_PE_aligned = 0x50,

  // The following are special values used to encode CFA and OP operands.
  DW_EH_PE_udata1 = 0x0d,
  DW_EH_PE_sdata1 = 0x0e,
  DW_EH_PE_block = 0x0f,
};

#endif  // _LIBUNWINDSTACK_DWARF_ENCODING_H
+248 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <assert.h>
#include <stdint.h>

#include <string>

#include "DwarfEncoding.h"
#include "DwarfMemory.h"
#include "Memory.h"

bool DwarfMemory::ReadBytes(void* dst, size_t num_bytes) {
  if (!memory_->Read(cur_offset_, dst, num_bytes)) {
    return false;
  }
  cur_offset_ += num_bytes;
  return true;
}

template <typename SignedType>
bool DwarfMemory::ReadSigned(uint64_t* value) {
  SignedType signed_value;
  if (!ReadBytes(&signed_value, sizeof(SignedType))) {
    return false;
  }
  *value = static_cast<int64_t>(signed_value);
  return true;
}

bool DwarfMemory::ReadULEB128(uint64_t* value) {
  uint64_t cur_value = 0;
  uint64_t shift = 0;
  uint8_t byte;
  do {
    if (!ReadBytes(&byte, 1)) {
      return false;
    }
    cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
    shift += 7;
  } while (byte & 0x80);
  *value = cur_value;
  return true;
}

bool DwarfMemory::ReadSLEB128(int64_t* value) {
  uint64_t cur_value = 0;
  uint64_t shift = 0;
  uint8_t byte;
  do {
    if (!ReadBytes(&byte, 1)) {
      return false;
    }
    cur_value += static_cast<uint64_t>(byte & 0x7f) << shift;
    shift += 7;
  } while (byte & 0x80);
  if (byte & 0x40) {
    // Negative value, need to sign extend.
    cur_value |= static_cast<uint64_t>(-1) << shift;
  }
  *value = static_cast<int64_t>(cur_value);
  return true;
}

template <typename AddressType>
size_t DwarfMemory::GetEncodedSize(uint8_t encoding) {
  switch (encoding & 0x0f) {
    case DW_EH_PE_absptr:
      return sizeof(AddressType);
    case DW_EH_PE_udata1:
    case DW_EH_PE_sdata1:
      return 1;
    case DW_EH_PE_udata2:
    case DW_EH_PE_sdata2:
      return 2;
    case DW_EH_PE_udata4:
    case DW_EH_PE_sdata4:
      return 4;
    case DW_EH_PE_udata8:
    case DW_EH_PE_sdata8:
      return 8;
    case DW_EH_PE_uleb128:
    case DW_EH_PE_sleb128:
    default:
      return 0;
  }
}

bool DwarfMemory::AdjustEncodedValue(uint8_t encoding, uint64_t* value) {
  assert((encoding & 0x0f) == 0);
  assert(encoding != DW_EH_PE_aligned);

  // Handle the encoding.
  switch (encoding) {
    case DW_EH_PE_absptr:
      // Nothing to do.
      break;
    case DW_EH_PE_pcrel:
      if (pc_offset_ == static_cast<uint64_t>(-1)) {
        // Unsupported encoding.
        return false;
      }
      *value += pc_offset_;
      break;
    case DW_EH_PE_textrel:
      if (text_offset_ == static_cast<uint64_t>(-1)) {
        // Unsupported encoding.
        return false;
      }
      *value += text_offset_;
      break;
    case DW_EH_PE_datarel:
      if (data_offset_ == static_cast<uint64_t>(-1)) {
        // Unsupported encoding.
        return false;
      }
      *value += data_offset_;
      break;
    case DW_EH_PE_funcrel:
      if (func_offset_ == static_cast<uint64_t>(-1)) {
        // Unsupported encoding.
        return false;
      }
      *value += func_offset_;
      break;
    default:
      return false;
  }

  return true;
}

template <typename AddressType>
bool DwarfMemory::ReadEncodedValue(uint8_t encoding, uint64_t* value) {
  if (encoding == DW_EH_PE_omit) {
    *value = 0;
    return true;
  } else if (encoding == DW_EH_PE_aligned) {
    if (__builtin_add_overflow(cur_offset_, sizeof(AddressType) - 1, &cur_offset_)) {
      return false;
    }
    cur_offset_ &= -sizeof(AddressType);

    if (sizeof(AddressType) != sizeof(uint64_t)) {
      *value = 0;
    }
    return ReadBytes(value, sizeof(AddressType));
  }

  // Get the data.
  switch (encoding & 0x0f) {
    case DW_EH_PE_absptr:
      if (sizeof(AddressType) != sizeof(uint64_t)) {
        *value = 0;
      }
      if (!ReadBytes(value, sizeof(AddressType))) {
        return false;
      }
      break;
    case DW_EH_PE_uleb128:
      if (!ReadULEB128(value)) {
        return false;
      }
      break;
    case DW_EH_PE_sleb128:
      int64_t signed_value;
      if (!ReadSLEB128(&signed_value)) {
        return false;
      }
      *value = static_cast<uint64_t>(signed_value);
      break;
    case DW_EH_PE_udata1: {
      uint8_t value8;
      if (!ReadBytes(&value8, 1)) {
        return false;
      }
      *value = value8;
    } break;
    case DW_EH_PE_sdata1:
      if (!ReadSigned<int8_t>(value)) {
        return false;
      }
      break;
    case DW_EH_PE_udata2: {
      uint16_t value16;
      if (!ReadBytes(&value16, 2)) {
        return false;
      }
      *value = value16;
    } break;
    case DW_EH_PE_sdata2:
      if (!ReadSigned<int16_t>(value)) {
        return false;
      }
      break;
    case DW_EH_PE_udata4: {
      uint32_t value32;
      if (!ReadBytes(&value32, 4)) {
        return false;
      }
      *value = value32;
    } break;
    case DW_EH_PE_sdata4:
      if (!ReadSigned<int32_t>(value)) {
        return false;
      }
      break;
    case DW_EH_PE_udata8:
      if (!ReadBytes(value, sizeof(uint64_t))) {
        return false;
      }
      break;
    case DW_EH_PE_sdata8:
      if (!ReadSigned<int64_t>(value)) {
        return false;
      }
      break;
    default:
      return false;
  }

  return AdjustEncodedValue(encoding & 0xf0, value);
}

// Instantiate all of the needed template functions.
template bool DwarfMemory::ReadSigned<int8_t>(uint64_t*);
template bool DwarfMemory::ReadSigned<int16_t>(uint64_t*);
template bool DwarfMemory::ReadSigned<int32_t>(uint64_t*);
template bool DwarfMemory::ReadSigned<int64_t>(uint64_t*);

template size_t DwarfMemory::GetEncodedSize<uint32_t>(uint8_t);
template size_t DwarfMemory::GetEncodedSize<uint64_t>(uint8_t);

template bool DwarfMemory::ReadEncodedValue<uint32_t>(uint8_t, uint64_t*);
template bool DwarfMemory::ReadEncodedValue<uint64_t>(uint8_t, uint64_t*);
+72 −0
Original line number Diff line number Diff line
/*
 * 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>

// 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);
};

#endif  // _LIBUNWINDSTACK_DWARF_MEMORY_H
+472 −0

File added.

Preview size limit exceeded, changes collapsed.