/*
 * Copyright (C) 2015 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 "thread_tree.h"

#include <inttypes.h>

#include <limits>

#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>

#include "perf_event.h"
#include "record.h"
#include "record_file.h"
#include "utils.h"

namespace simpleperf {
namespace {

// Real map file path depends on where the process can create files.
// For example, app can create files only in its data directory.
// Use normalized name inherited from pid instead.
std::string GetSymbolMapDsoName(int pid) {
  return android::base::StringPrintf("perf-%d.map", pid);
}

}  // namespace

void ThreadTree::SetThreadName(int pid, int tid, const std::string& comm) {
  ThreadEntry* thread = FindThreadOrNew(pid, tid);
  if (comm != thread->comm) {
    thread_comm_storage_.push_back(std::unique_ptr<std::string>(new std::string(comm)));
    thread->comm = thread_comm_storage_.back()->c_str();
  }
}

void ThreadTree::ForkThread(int pid, int tid, int ppid, int ptid) {
  ThreadEntry* parent = FindThreadOrNew(ppid, ptid);
  ThreadEntry* child = FindThreadOrNew(pid, tid);
  child->comm = parent->comm;
  if (pid != ppid) {
    // Copy maps from parent process.
    if (child->maps->maps.empty()) {
      *child->maps = *parent->maps;
    } else {
      CHECK_NE(child->maps, parent->maps);
      for (auto& pair : parent->maps->maps) {
        InsertMap(*child->maps, *pair.second);
      }
    }
  }
}

ThreadEntry* ThreadTree::FindThread(int tid) {
  if (auto it = thread_tree_.find(tid); it != thread_tree_.end()) {
    return it->second.get();
  }
  return nullptr;
}

ThreadEntry* ThreadTree::FindThreadOrNew(int pid, int tid) {
  auto it = thread_tree_.find(tid);
  if (it != thread_tree_.end() && pid == it->second.get()->pid) {
    return it->second.get();
  }
  if (it != thread_tree_.end()) {
    ExitThread(it->second.get()->pid, tid);
  }
  return CreateThread(pid, tid);
}

ThreadEntry* ThreadTree::CreateThread(int pid, int tid) {
  const char* comm;
  std::shared_ptr<MapSet> maps;
  if (pid == tid) {
    comm = "unknown";
    maps.reset(new MapSet);
  } else {
    // Share maps among threads in the same thread group.
    ThreadEntry* process = FindThreadOrNew(pid, pid);
    comm = process->comm;
    maps = process->maps;
  }
  ThreadEntry* thread = new ThreadEntry{
      pid,
      tid,
      comm,
      maps,
  };
  auto pair = thread_tree_.insert(std::make_pair(tid, std::unique_ptr<ThreadEntry>(thread)));
  CHECK(pair.second);
  if (pid == tid) {
    // If there is a symbol map dso for the process, add maps for the symbols.
    auto name = GetSymbolMapDsoName(pid);
    auto it = user_dso_tree_.find(name);
    if (it != user_dso_tree_.end()) {
      AddThreadMapsForDsoSymbols(thread, it->second.get());
    }
  }
  return thread;
}

void ThreadTree::ExitThread(int pid, int tid) {
  auto it = thread_tree_.find(tid);
  if (it != thread_tree_.end() && pid == it->second.get()->pid) {
    thread_tree_.erase(it);
  }
}

void ThreadTree::AddKernelMap(uint64_t start_addr, uint64_t len, uint64_t pgoff,
                              const std::string& filename) {
  // kernel map len can be 0 when record command is not run in supervisor mode.
  if (len == 0) {
    return;
  }
  Dso* dso;
  if (android::base::StartsWith(filename, DEFAULT_KERNEL_MMAP_NAME)) {
    dso = FindKernelDsoOrNew();
  } else {
    dso = FindKernelModuleDsoOrNew(filename, start_addr, start_addr + len);
  }
  InsertMap(kernel_maps_, MapEntry(start_addr, len, pgoff, dso, true));
}

Dso* ThreadTree::FindKernelDsoOrNew() {
  if (!kernel_dso_) {
    kernel_dso_ = Dso::CreateDso(DSO_KERNEL, DEFAULT_KERNEL_MMAP_NAME);
  }
  return kernel_dso_.get();
}

Dso* ThreadTree::FindKernelModuleDsoOrNew(const std::string& filename, uint64_t memory_start,
                                          uint64_t memory_end) {
  auto it = module_dso_tree_.find(filename);
  if (it == module_dso_tree_.end()) {
    module_dso_tree_[filename] =
        Dso::CreateKernelModuleDso(filename, memory_start, memory_end, FindKernelDsoOrNew());
    it = module_dso_tree_.find(filename);
  }
  return it->second.get();
}

void ThreadTree::AddThreadMap(int pid, int tid, uint64_t start_addr, uint64_t len, uint64_t pgoff,
                              const std::string& filename, uint32_t flags) {
  ThreadEntry* thread = FindThreadOrNew(pid, tid);
  Dso* dso = FindUserDsoOrNew(filename, start_addr);
  InsertMap(*thread->maps, MapEntry(start_addr, len, pgoff, dso, false, flags));
}

void ThreadTree::AddThreadMapsForDsoSymbols(ThreadEntry* thread, Dso* dso) {
  const uint64_t page_size = GetPageSize();

  auto maps = thread->maps;

  uint64_t map_start = 0;
  uint64_t map_end = 0;

  // Dso symbols are sorted by address. Walk and calculate containing pages.
  for (const auto& sym : dso->GetSymbols()) {
    uint64_t sym_map_start = AlignDown(sym.addr, page_size);
    uint64_t sym_map_end = Align(sym.addr + sym.len, page_size);

    if (map_end < sym_map_start) {
      if (map_start < map_end) {
        InsertMap(*maps, MapEntry(map_start, map_end - map_start, map_start, dso, false, 0));
      }
      map_start = sym_map_start;
    }
    if (map_end < sym_map_end) {
      map_end = sym_map_end;
    }
  }

  if (map_start < map_end) {
    InsertMap(*maps, MapEntry(map_start, map_end - map_start, map_start, dso, false, 0));
  }
}

Dso* ThreadTree::FindUserDsoOrNew(const std::string& filename, uint64_t start_addr,
                                  DsoType dso_type) {
  auto it = user_dso_tree_.find(filename);
  if (it == user_dso_tree_.end()) {
    bool force_64bit = start_addr > UINT_MAX;
    std::unique_ptr<Dso> dso = Dso::CreateDso(dso_type, filename, force_64bit);
    auto pair = user_dso_tree_.insert(std::make_pair(filename, std::move(dso)));
    CHECK(pair.second);
    it = pair.first;
  }
  return it->second.get();
}

void ThreadTree::AddSymbolsForProcess(int pid, std::vector<Symbol>* symbols) {
  auto name = GetSymbolMapDsoName(pid);

  auto dso = FindUserDsoOrNew(name, 0, DSO_SYMBOL_MAP_FILE);
  dso->SetSymbols(symbols);

  auto thread = FindThreadOrNew(pid, pid);
  AddThreadMapsForDsoSymbols(thread, dso);
}

const MapEntry* ThreadTree::AllocateMap(const MapEntry& entry) {
  map_storage_.emplace_back(new MapEntry(entry));
  return map_storage_.back().get();
}

static MapEntry RemoveFirstPartOfMapEntry(const MapEntry* entry, uint64_t new_start_addr) {
  MapEntry result = *entry;
  result.start_addr = new_start_addr;
  result.len -= result.start_addr - entry->start_addr;
  result.pgoff += result.start_addr - entry->start_addr;
  return result;
}

static MapEntry RemoveSecondPartOfMapEntry(const MapEntry* entry, uint64_t new_len) {
  MapEntry result = *entry;
  result.len = new_len;
  return result;
}

// Insert a new map entry in a MapSet. If some existing map entries overlap the new map entry,
// then remove the overlapped parts.
void ThreadTree::InsertMap(MapSet& maps, const MapEntry& entry) {
  std::map<uint64_t, const MapEntry*>& map = maps.maps;
  auto it = map.lower_bound(entry.start_addr);
  // Remove overlapped entry with start_addr < entry.start_addr.
  if (it != map.begin()) {
    auto it2 = it;
    --it2;
    if (it2->second->get_end_addr() > entry.get_end_addr()) {
      map.emplace(entry.get_end_addr(),
                  AllocateMap(RemoveFirstPartOfMapEntry(it2->second, entry.get_end_addr())));
    }
    if (it2->second->get_end_addr() > entry.start_addr) {
      it2->second =
          AllocateMap(RemoveSecondPartOfMapEntry(it2->second, entry.start_addr - it2->first));
    }
  }
  // Remove overlapped entries with start_addr >= entry.start_addr.
  while (it != map.end() && it->second->get_end_addr() <= entry.get_end_addr()) {
    it = map.erase(it);
  }
  if (it != map.end() && it->second->start_addr < entry.get_end_addr()) {
    map.emplace(entry.get_end_addr(),
                AllocateMap(RemoveFirstPartOfMapEntry(it->second, entry.get_end_addr())));
    map.erase(it);
  }
  // Insert the new entry.
  map.emplace(entry.start_addr, AllocateMap(entry));
  maps.version++;
}

const MapEntry* MapSet::FindMapByAddr(uint64_t addr) const {
  auto it = maps.upper_bound(addr);
  if (it != maps.begin()) {
    --it;
    if (it->second->get_end_addr() > addr) {
      return it->second;
    }
  }
  return nullptr;
}

const MapEntry* ThreadTree::FindMap(const ThreadEntry* thread, uint64_t ip, bool in_kernel) {
  const MapEntry* result = nullptr;
  if (!in_kernel) {
    result = thread->maps->FindMapByAddr(ip);
  } else {
    result = kernel_maps_.FindMapByAddr(ip);
  }
  return result != nullptr ? result : &unknown_map_;
}

const MapEntry* ThreadTree::FindMap(const ThreadEntry* thread, uint64_t ip) {
  const MapEntry* result = thread->maps->FindMapByAddr(ip);
  if (result != nullptr) {
    return result;
  }
  result = kernel_maps_.FindMapByAddr(ip);
  return result != nullptr ? result : &unknown_map_;
}

const Symbol* ThreadTree::FindSymbol(const MapEntry* map, uint64_t ip, uint64_t* pvaddr_in_file,
                                     Dso** pdso) {
  uint64_t vaddr_in_file = 0;
  const Symbol* symbol = nullptr;
  Dso* dso = map->dso;
  if (map->flags & map_flags::PROT_JIT_SYMFILE_MAP) {
    vaddr_in_file = ip;
  } else {
    vaddr_in_file = dso->IpToVaddrInFile(ip, map->start_addr, map->pgoff);
  }
  symbol = dso->FindSymbol(vaddr_in_file);
  if (symbol == nullptr && dso->type() == DSO_KERNEL_MODULE) {
    // If the ip address hits the vmlinux, or hits a kernel module, but we can't find its symbol
    // in the kernel module file, then find its symbol in /proc/kallsyms or vmlinux.
    vaddr_in_file = ip;
    dso = FindKernelDsoOrNew();
    symbol = dso->FindSymbol(vaddr_in_file);
  }

  if (symbol == nullptr) {
    if (show_ip_for_unknown_symbol_) {
      std::string name = android::base::StringPrintf("%s%s[+%" PRIx64 "]",
                                                     (show_mark_for_unknown_symbol_ ? "*" : ""),
                                                     dso->FileName().c_str(), vaddr_in_file);
      dso->AddUnknownSymbol(vaddr_in_file, name);
      symbol = dso->FindSymbol(vaddr_in_file);
      CHECK(symbol != nullptr);
    } else {
      symbol = &unknown_symbol_;
    }
  }
  if (pvaddr_in_file != nullptr) {
    *pvaddr_in_file = vaddr_in_file;
  }
  if (pdso != nullptr) {
    *pdso = dso;
  }
  return symbol;
}

const Symbol* ThreadTree::FindKernelSymbol(uint64_t ip) {
  const MapEntry* map = FindMap(nullptr, ip, true);
  return FindSymbol(map, ip, nullptr);
}

void ThreadTree::ClearThreadAndMap() {
  thread_tree_.clear();
  thread_comm_storage_.clear();
  kernel_maps_.maps.clear();
  map_storage_.clear();
}

void ThreadTree::AddDsoInfo(FileFeature& file) {
  DsoType dso_type = file.type;
  Dso* dso = nullptr;
  if (dso_type == DSO_KERNEL) {
    dso = FindKernelDsoOrNew();
  } else if (dso_type == DSO_KERNEL_MODULE) {
    dso = FindKernelModuleDsoOrNew(file.path, 0, 0);
  } else {
    dso = FindUserDsoOrNew(file.path, 0, dso_type);
  }
  dso->SetMinExecutableVaddr(file.min_vaddr, file.file_offset_of_min_vaddr);
  dso->SetSymbols(&file.symbols);
  for (uint64_t offset : file.dex_file_offsets) {
    dso->AddDexFileOffset(offset);
  }
}

void ThreadTree::AddDexFileOffset(const std::string& file_path, uint64_t dex_file_offset) {
  Dso* dso = FindUserDsoOrNew(file_path, 0, DSO_DEX_FILE);
  dso->AddDexFileOffset(dex_file_offset);
}

void ThreadTree::Update(const Record& record) {
  if (record.type() == PERF_RECORD_MMAP) {
    const MmapRecord& r = *static_cast<const MmapRecord*>(&record);
    if (r.InKernel()) {
      AddKernelMap(r.data->addr, r.data->len, r.data->pgoff, r.filename);
    } else {
      AddThreadMap(r.data->pid, r.data->tid, r.data->addr, r.data->len, r.data->pgoff, r.filename);
    }
  } else if (record.type() == PERF_RECORD_MMAP2) {
    const Mmap2Record& r = *static_cast<const Mmap2Record*>(&record);
    if (r.InKernel()) {
      AddKernelMap(r.data->addr, r.data->len, r.data->pgoff, r.filename);
    } else {
      std::string filename =
          (r.filename == DEFAULT_EXECNAME_FOR_THREAD_MMAP) ? "[unknown]" : r.filename;
      AddThreadMap(r.data->pid, r.data->tid, r.data->addr, r.data->len, r.data->pgoff, filename,
                   r.data->prot);
    }
  } else if (record.type() == PERF_RECORD_COMM) {
    const CommRecord& r = *static_cast<const CommRecord*>(&record);
    SetThreadName(r.data->pid, r.data->tid, r.comm);
  } else if (record.type() == PERF_RECORD_FORK) {
    const ForkRecord& r = *static_cast<const ForkRecord*>(&record);
    ForkThread(r.data->pid, r.data->tid, r.data->ppid, r.data->ptid);
  } else if (record.type() == PERF_RECORD_EXIT) {
    const ExitRecord& r = *static_cast<const ExitRecord*>(&record);
    ExitThread(r.data->pid, r.data->tid);
  } else if (record.type() == SIMPLE_PERF_RECORD_KERNEL_SYMBOL) {
    const auto& r = *static_cast<const KernelSymbolRecord*>(&record);
    Dso::SetKallsyms(std::move(r.kallsyms));
  }
}

std::vector<Dso*> ThreadTree::GetAllDsos() const {
  std::vector<Dso*> result;
  if (kernel_dso_) {
    result.push_back(kernel_dso_.get());
  }
  for (auto& p : module_dso_tree_) {
    result.push_back(p.second.get());
  }
  for (auto& p : user_dso_tree_) {
    result.push_back(p.second.get());
  }
  result.push_back(unknown_dso_.get());
  return result;
}

}  // namespace simpleperf
