<commit_before>/*
 * 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 <elf.h>
#include <stdint.h>
#include <sys/mman.h>

#include <memory>
#include <set>
#include <string>

#include <gtest/gtest.h>

#include <android-base/silent_death_test.h>
#include <unwindstack/Elf.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsMips.h>
#include <unwindstack/RegsMips64.h>
#include <unwindstack/RegsX86.h>
#include <unwindstack/RegsX86_64.h>
#include <unwindstack/Unwinder.h>

#include "ElfFake.h"
#include "ElfTestUtils.h"
#include "utils/MemoryFake.h"
#include "utils/RegsFake.h"

namespace unwindstack {

class UnwinderTest : public ::testing::Test {
 protected:
  static MapInfo* AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
                             const char* name, Elf* elf = nullptr) {
    std::string str_name(name);
    maps_->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
    MapInfo* map_info = maps_->Find(start);
    if (elf != nullptr) {
      map_info->set_elf(elf);
    }
    return map_info;
  }

  static void SetUpTestSuite() {
    maps_.reset(new Maps);

    memory_ = new MemoryFake;
    process_memory_.reset(memory_);

    ElfFake* elf;
    ElfInterfaceFake* interface;
    MapInfo* map_info;

    elf = new ElfFake(new MemoryFake);
    interface = new ElfInterfaceFake(nullptr);
    interface->FakeSetBuildID("FAKE");
    elf->FakeSetInterface(interface);
    AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);

    AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");

    AddMapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
               "/dev/fake_device");

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    AddMapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so", elf);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    AddMapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so", elf);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);

    elf = new ElfFake(new MemoryFake);
    interface = new ElfInterfaceFake(nullptr);
    interface->FakeSetSoname("lib_fake.so");
    elf->FakeSetInterface(interface);
    map_info = AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
    map_info->set_elf_start_offset(0x1d000);

    AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");

    map_info =
        AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
    map_info->set_load_bias(0);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    elf->FakeSetLoadBias(0x5000);
    AddMapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_load_bias.so",
               elf);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/fake/fake_offset.oat", elf);
    map_info->set_elf_offset(0x8000);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/fake/unreadable.so", elf);
    map_info->set_memory_backed_elf(true);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
    map_info->set_memory_backed_elf(true);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
    map_info->set_memory_backed_elf(true);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/memfd:/jit-cache", elf);
    map_info->set_memory_backed_elf(true);

    map_info =
        AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
    map_info->set_load_bias(0);

    elf = new ElfFake(new MemoryFake);
    interface = new ElfInterfaceFake(nullptr);
    elf->FakeSetInterface(interface);
    interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x1800);
    interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x1900);
    interface->FakeSetDataOffset(0x1000);
    interface->FakeSetDataVaddrStart(0x1000);
    interface->FakeSetDataVaddrEnd(0x8000);
    AddMapInfo(0xf0000, 0xf1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/global.so", elf);
    AddMapInfo(0xf1000, 0xf9000, 0x1000, PROT_READ | PROT_WRITE, "/fake/global.so");
    // dex debug data
    memory_->SetData32(0xf180c, 0xf3000);
    memory_->SetData32(0xf3000, 0xf4000);
    memory_->SetData32(0xf3004, 0xf4000);
    memory_->SetData32(0xf3008, 0xf5000);
    // jit debug data
    memory_->SetData32(0xf1900, 1);
    memory_->SetData32(0xf1904, 0);
    memory_->SetData32(0xf1908, 0xf6000);
    memory_->SetData32(0xf190c, 0xf6000);
    memory_->SetData32(0xf6000, 0);
    memory_->SetData32(0xf6004, 0);
    memory_->SetData32(0xf6008, 0xf7000);
    memory_->SetData32(0xf600c, 0);
    memory_->SetData64(0xf6010, 0x1000);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetValid(false);
    elf->FakeSetLoadBias(0x300);
    map_info = AddMapInfo(0x100000, 0x101000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/fake/jit.so", elf);
    map_info->set_elf_start_offset(0x100);
    map_info->set_offset(0x200);
  }

  void SetUp() override {
    ElfInterfaceFake::FakeClear();
    regs_.FakeSetArch(ARCH_ARM);
    regs_.FakeSetReturnAddressValid(false);
  }

  static std::unique_ptr<Maps> maps_;
  static RegsFake regs_;
  static MemoryFake* memory_;
  static std::shared_ptr<Memory> process_memory_;
};

std::unique_ptr<Maps> UnwinderTest::maps_;
RegsFake UnwinderTest::regs_(5);
MemoryFake* UnwinderTest::memory_;
std::shared_ptr<Memory> UnwinderTest::process_memory_(nullptr);

TEST_F(UnwinderTest, multiple_frames) {
  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));

  regs_.set_pc(0x1000);
  regs_.set_sp(0x10000);
  ElfInterfaceFake::FakePushStepData(StepData(0x1104, 0x10010, false));
  ElfInterfaceFake::FakePushStepData(StepData(0x1204, 0x10020, false));
  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));

  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
  unwinder.Unwind();
  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
  EXPECT_FALSE(unwinder.elf_from_memory_not_file());

  ASSERT_EQ(3U, unwinder.NumFrames());

  auto* frame = &unwinder.frames()[0];
  EXPECT_EQ(0U, frame->num);
  EXPECT_EQ(0U, frame->rel_pc);
  EXPECT_EQ(0x1000U, frame->pc);
  EXPECT_EQ(0x10000U, frame->sp);
  EXPECT_EQ("Frame0", frame->function_name);
  EXPECT_EQ(0U, frame->function_offset);
  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
  EXPECT_EQ(0U, frame->map_elf_start_offset);<commit_msg>Fix UnwinderTest when running locally<commit_after>/*
 * 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 <elf.h>
#include <stdint.h>
#include <sys/mman.h>

#include <memory>
#include <set>
#include <string>

#include <gtest/gtest.h>

#include <android-base/silent_death_test.h>
#include <unwindstack/Elf.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsMips.h>
#include <unwindstack/RegsMips64.h>
#include <unwindstack/RegsX86.h>
#include <unwindstack/RegsX86_64.h>
#include <unwindstack/Unwinder.h>

#include "ElfFake.h"
#include "ElfTestUtils.h"
#include "utils/MemoryFake.h"
#include "utils/RegsFake.h"

namespace unwindstack {

class UnwinderTest : public ::testing::Test {
 protected:
  // We set up `memory_` and `regs_` per test fixture, because some tests modify these, which
  // can lead to tests influencing other tests and causing them to fail. This is only
  // a problem when all tests are run in the same process, which is for example the
  // case when running these tests locally during development.
  UnwinderTest() : memory_(new MemoryFake), process_memory_(memory_), regs_(5) {
    // dex debug data
    memory_->SetData32(0xf180c, 0xf3000);
    memory_->SetData32(0xf3000, 0xf4000);
    memory_->SetData32(0xf3004, 0xf4000);
    memory_->SetData32(0xf3008, 0xf5000);
    // jit debug data
    memory_->SetData32(0xf1900, 1);
    memory_->SetData32(0xf1904, 0);
    memory_->SetData32(0xf1908, 0xf6000);
    memory_->SetData32(0xf190c, 0xf6000);
    memory_->SetData32(0xf6000, 0);
    memory_->SetData32(0xf6004, 0);
    memory_->SetData32(0xf6008, 0xf7000);
    memory_->SetData32(0xf600c, 0);
    memory_->SetData64(0xf6010, 0x1000);

    ElfInterfaceFake::FakeClear();
    regs_.FakeSetArch(ARCH_ARM);
    regs_.FakeSetReturnAddressValid(false);
  }

  static MapInfo* AddMapInfo(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
                             const char* name, Elf* elf = nullptr) {
    std::string str_name(name);
    maps_->Add(start, end, offset, flags, name, static_cast<uint64_t>(-1));
    MapInfo* map_info = maps_->Find(start);
    if (elf != nullptr) {
      map_info->set_elf(elf);
    }
    return map_info;
  }

  static void SetUpTestSuite() {
    maps_.reset(new Maps);

    ElfFake* elf;
    ElfInterfaceFake* interface;
    MapInfo* map_info;

    elf = new ElfFake(new MemoryFake);
    interface = new ElfInterfaceFake(nullptr);
    interface->FakeSetBuildID("FAKE");
    elf->FakeSetInterface(interface);
    AddMapInfo(0x1000, 0x8000, 0, PROT_READ | PROT_WRITE, "/system/fake/libc.so", elf);

    AddMapInfo(0x10000, 0x12000, 0, PROT_READ | PROT_WRITE, "[stack]");

    AddMapInfo(0x13000, 0x15000, 0, PROT_READ | PROT_WRITE | MAPS_FLAGS_DEVICE_MAP,
               "/dev/fake_device");

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    AddMapInfo(0x20000, 0x22000, 0, PROT_READ | PROT_WRITE, "/system/fake/libunwind.so", elf);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    AddMapInfo(0x23000, 0x24000, 0, PROT_READ | PROT_WRITE, "/fake/libanother.so", elf);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    AddMapInfo(0x33000, 0x34000, 0, PROT_READ | PROT_WRITE, "/fake/compressed.so", elf);

    elf = new ElfFake(new MemoryFake);
    interface = new ElfInterfaceFake(nullptr);
    interface->FakeSetSoname("lib_fake.so");
    elf->FakeSetInterface(interface);
    map_info = AddMapInfo(0x43000, 0x44000, 0x1d000, PROT_READ | PROT_WRITE, "/fake/fake.apk", elf);
    map_info->set_elf_start_offset(0x1d000);

    AddMapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat");

    map_info =
        AddMapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex");
    map_info->set_load_bias(0);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    elf->FakeSetLoadBias(0x5000);
    AddMapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake_load_bias.so",
               elf);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/fake/fake_offset.oat", elf);
    map_info->set_elf_offset(0x8000);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/fake/unreadable.so", elf);
    map_info->set_memory_backed_elf(true);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf);
    map_info->set_memory_backed_elf(true);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf);
    map_info->set_memory_backed_elf(true);

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetInterface(new ElfInterfaceFake(nullptr));
    map_info = AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/memfd:/jit-cache", elf);
    map_info->set_memory_backed_elf(true);

    map_info =
        AddMapInfo(0xd0000, 0xd1000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.apk");
    map_info->set_load_bias(0);

    elf = new ElfFake(new MemoryFake);
    interface = new ElfInterfaceFake(nullptr);
    elf->FakeSetInterface(interface);
    interface->FakeSetGlobalVariable("__dex_debug_descriptor", 0x1800);
    interface->FakeSetGlobalVariable("__jit_debug_descriptor", 0x1900);
    interface->FakeSetDataOffset(0x1000);
    interface->FakeSetDataVaddrStart(0x1000);
    interface->FakeSetDataVaddrEnd(0x8000);
    AddMapInfo(0xf0000, 0xf1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/global.so", elf);
    AddMapInfo(0xf1000, 0xf9000, 0x1000, PROT_READ | PROT_WRITE, "/fake/global.so");

    elf = new ElfFake(new MemoryFake);
    elf->FakeSetValid(false);
    elf->FakeSetLoadBias(0x300);
    map_info = AddMapInfo(0x100000, 0x101000, 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC,
                          "/fake/jit.so", elf);
    map_info->set_elf_start_offset(0x100);
    map_info->set_offset(0x200);
  }

  static std::unique_ptr<Maps> maps_;

  MemoryFake* memory_;
  std::shared_ptr<Memory> process_memory_;
  RegsFake regs_;
};

std::unique_ptr<Maps> UnwinderTest::maps_;

TEST_F(UnwinderTest, multiple_frames) {
  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));
  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame1", 1));
  ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame2", 2));

  regs_.set_pc(0x1000);
  regs_.set_sp(0x10000);
  ElfInterfaceFake::FakePushStepData(StepData(0x1104, 0x10010, false));
  ElfInterfaceFake::FakePushStepData(StepData(0x1204, 0x10020, false));
  ElfInterfaceFake::FakePushStepData(StepData(0, 0, true));

  Unwinder unwinder(64, maps_.get(), &regs_, process_memory_);
  unwinder.Unwind();
  EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode());
  EXPECT_EQ(WARNING_NONE, unwinder.warnings());
  EXPECT_FALSE(unwinder.elf_from_memory_not_file());

  ASSERT_EQ(3U, unwinder.NumFrames());

  auto* frame = &unwinder.frames()[0];
  EXPECT_EQ(0U, frame->num);
  EXPECT_EQ(0U, frame->rel_pc);
  EXPECT_EQ(0x1000U, frame->pc);
  EXPECT_EQ(0x10000U, frame->sp);
  EXPECT_EQ("Frame0", frame->function_name);
  EXPECT_EQ(0U, frame->function_offset);
  EXPECT_EQ("/system/fake/libc.so", frame->map_name);
  EXPECT_EQ(0U, frame->map_elf_start_offset);
{'fraction_non_alphanumeric': 0.12822955113704013, 'fraction_numerical': 0.0620311941897845, 'mean_word_length': 4.450681375730046, 'pattern_counts': {'":': 0, '<': 50, '<?xml version=': 0, '>': 162, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7243077', 'n_tokens_mistral': 6666, 'n_tokens_neox': 5972, 'n_words': 1140}