18f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui/*
28f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * Copyright (C) 2015 The Android Open Source Project
38f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui *
48f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * Licensed under the Apache License, Version 2.0 (the "License");
58f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * you may not use this file except in compliance with the License.
68f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * You may obtain a copy of the License at
78f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui *
88f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui *      http://www.apache.org/licenses/LICENSE-2.0
98f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui *
108f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * Unless required by applicable law or agreed to in writing, software
118f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * distributed under the License is distributed on an "AS IS" BASIS,
128f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * See the License for the specific language governing permissions and
148f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui * limitations under the License.
158f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui */
168f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
178f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include "read_elf.h"
18f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh#include "read_apk.h"
198f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
208f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include <stdio.h>
218f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include <string.h>
22f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh#include <sys/stat.h>
23f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh#include <sys/types.h>
24547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui
258f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include <algorithm>
26547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui#include <limits>
27547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui
2866dd09e8e2407082ce93bf0784de641298131912Elliott Hughes#include <android-base/file.h>
2966dd09e8e2407082ce93bf0784de641298131912Elliott Hughes#include <android-base/logging.h>
308f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
318f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#pragma clang diagnostic push
328f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#pragma clang diagnostic ignored "-Wunused-parameter"
338f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
348f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include <llvm/ADT/StringRef.h>
358f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include <llvm/Object/Binary.h>
368f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include <llvm/Object/ELFObjectFile.h>
378f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include <llvm/Object/ObjectFile.h>
388f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
398f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#pragma clang diagnostic pop
408f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
418f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui#include "utils.h"
428f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
43a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui#define ELF_NOTE_GNU "GNU"
44a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui#define NT_GNU_BUILD_ID 3
45a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui
46dec43c18d06415a955b8f32355bca925be901905Yabin Cuistd::ostream& operator<<(std::ostream& os, const ElfStatus& status) {
47dec43c18d06415a955b8f32355bca925be901905Yabin Cui  switch (status) {
48dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::NO_ERROR:
49dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "No error";
50dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
51dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::FILE_NOT_FOUND:
52dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "File not found";
53dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
54dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::READ_FAILED:
55dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "Read failed";
56dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
57dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::FILE_MALFORMED:
58dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "Malformed file";
59dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
60dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::NO_SYMBOL_TABLE:
61dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "No symbol table";
62dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
63dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::NO_BUILD_ID:
64dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "No build id";
65dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
66dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::BUILD_ID_MISMATCH:
67dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "Build id mismatch";
68dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
69dec43c18d06415a955b8f32355bca925be901905Yabin Cui    case ElfStatus::SECTION_NOT_FOUND:
70dec43c18d06415a955b8f32355bca925be901905Yabin Cui      os << "Section not found";
71dec43c18d06415a955b8f32355bca925be901905Yabin Cui      break;
72dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
73dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return os;
74dec43c18d06415a955b8f32355bca925be901905Yabin Cui}
75f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh
76dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus IsValidElfFile(int fd) {
77797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui  static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
78f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh  char buf[4];
79dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (!android::base::ReadFully(fd, buf, 4)) {
80dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::READ_FAILED;
81dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
82dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (memcmp(buf, elf_magic, 4) != 0) {
83dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_MALFORMED;
84dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
85dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::NO_ERROR;
86f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh}
87f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh
88dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus IsValidElfPath(const std::string& filename) {
89797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui  if (!IsRegularFile(filename)) {
90dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_NOT_FOUND;
91797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui  }
92ffaa912ca48e87d25d516780c15cdd7c50de43dbYabin Cui  std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
93ffaa912ca48e87d25d516780c15cdd7c50de43dbYabin Cui  FILE* fp = fopen(filename.c_str(), mode.c_str());
94a5b79fd2c1a255f587859621094c50882ea8c8d1Yabin Cui  if (fp == nullptr) {
95dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::READ_FAILED;
96a5b79fd2c1a255f587859621094c50882ea8c8d1Yabin Cui  }
97dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = IsValidElfFile(fileno(fp));
98797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui  fclose(fp);
99f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh  return result;
100797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui}
101797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui
102f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cuibool GetBuildIdFromNoteSection(const char* section, size_t section_size, BuildId* build_id) {
1038f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  const char* p = section;
1048f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  const char* end = p + section_size;
1058f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  while (p < end) {
106f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    if (p + 12 >= end) {
107f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui      return false;
108f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    }
109f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    uint32_t namesz;
110f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    uint32_t descsz;
111f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    uint32_t type;
112f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    MoveFromBinaryFormat(namesz, p);
113f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    MoveFromBinaryFormat(descsz, p);
114f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    MoveFromBinaryFormat(type, p);
115a7a0e5076f0107173bc9ee067d13955d0d169f25Yabin Cui    namesz = Align(namesz, 4);
116a7a0e5076f0107173bc9ee067d13955d0d169f25Yabin Cui    descsz = Align(descsz, 4);
117f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui    if ((type == NT_GNU_BUILD_ID) && (p < end) && (strcmp(p, ELF_NOTE_GNU) == 0)) {
118f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui      const char* desc_start = p + namesz;
119f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui      const char* desc_end = desc_start + descsz;
120f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui      if (desc_start > p && desc_start < desc_end && desc_end <= end) {
121f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui        *build_id = BuildId(p + namesz, descsz);
122f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui        return true;
123f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui      } else {
124f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui        return false;
125f79a00874d415ba7e7fda01cf2eb76bf06e459a6Yabin Cui      }
1268f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui    }
1278f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui    p += namesz + descsz;
1288f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  }
1298f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  return false;
1308f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui}
1318f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
132dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus GetBuildIdFromNoteFile(const std::string& filename, BuildId* build_id) {
1338f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  std::string content;
1348f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  if (!android::base::ReadFileToString(filename, &content)) {
135dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::READ_FAILED;
1368f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  }
137dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (!GetBuildIdFromNoteSection(content.c_str(), content.size(), build_id)) {
138dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::NO_BUILD_ID;
1398f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  }
140dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::NO_ERROR;
1418f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui}
1428f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
1438f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cuitemplate <class ELFT>
144dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus GetBuildIdFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, BuildId* build_id) {
14505400539d15c50a52a388daba2e831b86824cc8eYabin Cui  for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
14605400539d15c50a52a388daba2e831b86824cc8eYabin Cui    const llvm::object::ELFSectionRef& section_ref = *it;
14705400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (section_ref.getType() == llvm::ELF::SHT_NOTE) {
14805400539d15c50a52a388daba2e831b86824cc8eYabin Cui      llvm::StringRef data;
14905400539d15c50a52a388daba2e831b86824cc8eYabin Cui      if (it->getContents(data)) {
150dec43c18d06415a955b8f32355bca925be901905Yabin Cui        return ElfStatus::READ_FAILED;
1518f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui      }
152ae56a5fe174cd2decfcac2ea8634cab88d5180faDimitry Ivanov      if (GetBuildIdFromNoteSection(data.data(), data.size(), build_id)) {
153dec43c18d06415a955b8f32355bca925be901905Yabin Cui        return ElfStatus::NO_ERROR;
1548f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui      }
1558f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui    }
1568f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  }
157dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::NO_BUILD_ID;
1588f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui}
1598f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui
160dec43c18d06415a955b8f32355bca925be901905Yabin Cuistatic ElfStatus GetBuildIdFromObjectFile(llvm::object::ObjectFile* obj, BuildId* build_id) {
161638c558339b7f1ae0ed95f64bcf7dbc5b238ed83Yabin Cui  if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
162dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return GetBuildIdFromELFFile(elf, build_id);
163638c558339b7f1ae0ed95f64bcf7dbc5b238ed83Yabin Cui  } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
164dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return GetBuildIdFromELFFile(elf, build_id);
165638c558339b7f1ae0ed95f64bcf7dbc5b238ed83Yabin Cui  }
166dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::FILE_MALFORMED;
167638c558339b7f1ae0ed95f64bcf7dbc5b238ed83Yabin Cui}
168638c558339b7f1ae0ed95f64bcf7dbc5b238ed83Yabin Cui
169dec43c18d06415a955b8f32355bca925be901905Yabin Cuistruct BinaryWrapper {
170b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  llvm::object::OwningBinary<llvm::object::Binary> binary;
171b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  llvm::object::ObjectFile* obj;
172b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui
173dec43c18d06415a955b8f32355bca925be901905Yabin Cui  BinaryWrapper() : obj(nullptr) {
174f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh  }
175b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui};
176b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui
177dec43c18d06415a955b8f32355bca925be901905Yabin Cuistatic ElfStatus OpenObjectFile(const std::string& filename, uint64_t file_offset,
178dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                uint64_t file_size, BinaryWrapper* wrapper) {
179be7ec66eaa4f995bd9068637f7c7d5718173922cYabin Cui  FileHelper fhelper = FileHelper::OpenReadOnly(filename);
180b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  if (!fhelper) {
181dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::READ_FAILED;
182f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh  }
183b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  if (file_size == 0) {
184b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui    file_size = GetFileSize(filename);
185b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui    if (file_size == 0) {
186dec43c18d06415a955b8f32355bca925be901905Yabin Cui      return ElfStatus::READ_FAILED;
187b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui    }
188f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh  }
189b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(fhelper.fd(), filename, file_size, file_offset);
190b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  if (!buffer_or_err) {
191dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::READ_FAILED;
192b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  }
193b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
194b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  if (!binary_or_err) {
195dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::READ_FAILED;
196dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
197dec43c18d06415a955b8f32355bca925be901905Yabin Cui  wrapper->binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
198dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                                                        std::move(buffer_or_err.get()));
199dec43c18d06415a955b8f32355bca925be901905Yabin Cui  wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.getBinary());
200dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (wrapper->obj == nullptr) {
201dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_MALFORMED;
202dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
203dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::NO_ERROR;
204f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh}
205f831e6d12ca2298cb34b155a9d91ef002d0482f3Than McIntosh
206dec43c18d06415a955b8f32355bca925be901905Yabin Cuistatic ElfStatus OpenObjectFileFromString(const std::string& s, BinaryWrapper* wrapper) {
20705400539d15c50a52a388daba2e831b86824cc8eYabin Cui  auto buffer = llvm::MemoryBuffer::getMemBuffer(s);
20805400539d15c50a52a388daba2e831b86824cc8eYabin Cui  auto binary_or_err = llvm::object::createBinary(buffer->getMemBufferRef());
20905400539d15c50a52a388daba2e831b86824cc8eYabin Cui  if (!binary_or_err) {
210dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_MALFORMED;
21105400539d15c50a52a388daba2e831b86824cc8eYabin Cui  }
212dec43c18d06415a955b8f32355bca925be901905Yabin Cui  wrapper->binary = llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
21305400539d15c50a52a388daba2e831b86824cc8eYabin Cui                                                                std::move(buffer));
214dec43c18d06415a955b8f32355bca925be901905Yabin Cui  wrapper->obj = llvm::dyn_cast<llvm::object::ObjectFile>(wrapper->binary.getBinary());
215dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (wrapper->obj == nullptr) {
216dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_MALFORMED;
21705400539d15c50a52a388daba2e831b86824cc8eYabin Cui  }
218dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::NO_ERROR;
21905400539d15c50a52a388daba2e831b86824cc8eYabin Cui}
22005400539d15c50a52a388daba2e831b86824cc8eYabin Cui
221dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus GetBuildIdFromElfFile(const std::string& filename, BuildId* build_id) {
222dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = IsValidElfPath(filename);
223dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
224dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
225797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui  }
226dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
227b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui}
228b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui
229dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus GetBuildIdFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
230dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                        uint32_t file_size, BuildId* build_id) {
231dec43c18d06415a955b8f32355bca925be901905Yabin Cui  BinaryWrapper wrapper;
232dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
233dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
234dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
2358f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui  }
236dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return GetBuildIdFromObjectFile(wrapper.obj, build_id);
2378f6225147c5b6cb2159a7f5cb0dab952ee0759dfYabin Cui}
238a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui
23905400539d15c50a52a388daba2e831b86824cc8eYabin Cuitemplate <class ELFT>
240dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus ReadSectionFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf, const std::string& section_name,
241dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                 std::string* content) {
24205400539d15c50a52a388daba2e831b86824cc8eYabin Cui  for (llvm::object::section_iterator it = elf->section_begin(); it != elf->section_end(); ++it) {
24305400539d15c50a52a388daba2e831b86824cc8eYabin Cui    llvm::StringRef name;
24405400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (it->getName(name) || name != section_name) {
24505400539d15c50a52a388daba2e831b86824cc8eYabin Cui      continue;
24605400539d15c50a52a388daba2e831b86824cc8eYabin Cui    }
24705400539d15c50a52a388daba2e831b86824cc8eYabin Cui    llvm::StringRef data;
24805400539d15c50a52a388daba2e831b86824cc8eYabin Cui    std::error_code err = it->getContents(data);
24905400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (err) {
250dec43c18d06415a955b8f32355bca925be901905Yabin Cui      return ElfStatus::READ_FAILED;
25105400539d15c50a52a388daba2e831b86824cc8eYabin Cui    }
25205400539d15c50a52a388daba2e831b86824cc8eYabin Cui    *content = data;
253dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::NO_ERROR;
25405400539d15c50a52a388daba2e831b86824cc8eYabin Cui  }
255dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::SECTION_NOT_FOUND;
25605400539d15c50a52a388daba2e831b86824cc8eYabin Cui}
25705400539d15c50a52a388daba2e831b86824cc8eYabin Cui
258a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cuibool IsArmMappingSymbol(const char* name) {
259a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui  // Mapping symbols in arm, which are described in "ELF for ARM Architecture" and
260a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui  // "ELF for ARM 64-bit Architecture". The regular expression to match mapping symbol
261a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui  // is ^\$(a|d|t|x)(\..*)?$
262a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui  return name[0] == '$' && strchr("adtx", name[1]) != nullptr && (name[2] == '\0' || name[2] == '.');
263a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui}
264a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui
26505400539d15c50a52a388daba2e831b86824cc8eYabin Cuivoid ReadSymbolTable(llvm::object::symbol_iterator sym_begin,
26605400539d15c50a52a388daba2e831b86824cc8eYabin Cui                     llvm::object::symbol_iterator sym_end,
2673e4c5950f3aafb0bf66544468d98ee3ec26b705cYabin Cui                     const std::function<void(const ElfFileSymbol&)>& callback,
26805400539d15c50a52a388daba2e831b86824cc8eYabin Cui                     bool is_arm) {
26905400539d15c50a52a388daba2e831b86824cc8eYabin Cui  for (; sym_begin != sym_end; ++sym_begin) {
270ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui    ElfFileSymbol symbol;
27105400539d15c50a52a388daba2e831b86824cc8eYabin Cui    auto symbol_ref = static_cast<const llvm::object::ELFSymbolRef*>(&*sym_begin);
2720ea825032cf8f343f82257c7366fe1ea65f04fa9Pirama Arumuga Nainar    llvm::Expected<llvm::object::section_iterator> section_it_or_err = symbol_ref->getSection();
27305400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (!section_it_or_err) {
274ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui      continue;
275ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui    }
27605400539d15c50a52a388daba2e831b86824cc8eYabin Cui
27707cdff03ffb5e69d73979e8c2f8585314751ee17Yabin Cui    llvm::StringRef section_name;
27805400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (section_it_or_err.get()->getName(section_name) || section_name.empty()) {
279ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui      continue;
280ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui    }
28105400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (section_name == ".text") {
282ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui      symbol.is_in_text_section = true;
283ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui    }
2840ea825032cf8f343f82257c7366fe1ea65f04fa9Pirama Arumuga Nainar    llvm::Expected<llvm::StringRef> symbol_name_or_err = symbol_ref->getName();
28505400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (!symbol_name_or_err || symbol_name_or_err.get().empty()) {
286ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui      continue;
287ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui    }
28805400539d15c50a52a388daba2e831b86824cc8eYabin Cui
28905400539d15c50a52a388daba2e831b86824cc8eYabin Cui    symbol.name = symbol_name_or_err.get();
29005400539d15c50a52a388daba2e831b86824cc8eYabin Cui    symbol.vaddr = symbol_ref->getValue();
291547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui    if ((symbol.vaddr & 1) != 0 && is_arm) {
292b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui      // Arm sets bit 0 to mark it as thumb code, remove the flag.
293547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui      symbol.vaddr &= ~1;
294b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui    }
29505400539d15c50a52a388daba2e831b86824cc8eYabin Cui    symbol.len = symbol_ref->getSize();
2960ea825032cf8f343f82257c7366fe1ea65f04fa9Pirama Arumuga Nainar    llvm::object::SymbolRef::Type symbol_type = *symbol_ref->getType();
29705400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (symbol_type == llvm::object::SymbolRef::ST_Function) {
298b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui      symbol.is_func = true;
29905400539d15c50a52a388daba2e831b86824cc8eYabin Cui    } else if (symbol_type == llvm::object::SymbolRef::ST_Unknown) {
300b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui      if (symbol.is_in_text_section) {
301b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui        symbol.is_label = true;
3022c17e0db003baeb044bf3e13175f5d00c414c3fcYabin Cui        if (is_arm) {
303a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui          // Remove mapping symbols in arm.
304a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui          const char* p = (symbol.name.compare(0, linker_prefix.size(), linker_prefix) == 0)
305a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui                              ? symbol.name.c_str() + linker_prefix.size()
306a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui                              : symbol.name.c_str();
307a5bdf0a31dc6e225c10b82840903de49535bf8fbYabin Cui          if (IsArmMappingSymbol(p)) {
3082c17e0db003baeb044bf3e13175f5d00c414c3fcYabin Cui            symbol.is_label = false;
3092c17e0db003baeb044bf3e13175f5d00c414c3fcYabin Cui          }
310b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui        }
311b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui      }
312b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui    }
313b378355f34b2b585eaf2be262bcd9baae9f3d36aYabin Cui
314ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui    callback(symbol);
315ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui  }
316ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui}
317ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui
31805400539d15c50a52a388daba2e831b86824cc8eYabin Cuitemplate <class ELFT>
3195783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cuivoid AddSymbolForPltSection(const llvm::object::ELFObjectFile<ELFT>* elf,
3203e4c5950f3aafb0bf66544468d98ee3ec26b705cYabin Cui                            const std::function<void(const ElfFileSymbol&)>& callback) {
3215783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  // We may sample instructions in .plt section if the program
3225783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  // calls functions from shared libraries. Different architectures use
3235783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  // different formats to store .plt section, so it needs a lot of work to match
3245783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  // instructions in .plt section to symbols. As samples in .plt section rarely
3255783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  // happen, and .plt section can hardly be a performance bottleneck, we can
3265783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  // just use a symbol @plt to represent instructions in .plt section.
3275783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
3285783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    const llvm::object::ELFSectionRef& section_ref = *it;
3295783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    llvm::StringRef section_name;
3305783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    std::error_code err = section_ref.getName(section_name);
3315783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    if (err || section_name != ".plt") {
3325783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui      continue;
3335783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    }
3345783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    const auto* shdr = elf->getSection(section_ref.getRawDataRefImpl());
3355783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    if (shdr == nullptr) {
3365783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui      return;
3375783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    }
3385783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    ElfFileSymbol symbol;
3395783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    symbol.vaddr = shdr->sh_addr;
3405783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    symbol.len = shdr->sh_size;
3415783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    symbol.is_func = true;
3425783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    symbol.is_label = true;
3435783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    symbol.is_in_text_section = true;
3445783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    symbol.name = "@plt";
3455783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    callback(symbol);
3465783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui    return;
3475783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui  }
3485783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui}
3495783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cui
3505783fa0c4ac6a3faaa9191c8f8e3f2b9dc2ae2f0Yabin Cuitemplate <class ELFT>
351dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus ParseSymbolsFromELFFile(const llvm::object::ELFObjectFile<ELFT>* elf,
352dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                  const std::function<void(const ElfFileSymbol&)>& callback) {
35305400539d15c50a52a388daba2e831b86824cc8eYabin Cui  auto machine = elf->getELFFile()->getHeader()->e_machine;
35405400539d15c50a52a388daba2e831b86824cc8eYabin Cui  bool is_arm = (machine == llvm::ELF::EM_ARM || machine == llvm::ELF::EM_AARCH64);
355dec43c18d06415a955b8f32355bca925be901905Yabin Cui  AddSymbolForPltSection(elf, callback);
35605400539d15c50a52a388daba2e831b86824cc8eYabin Cui  if (elf->symbol_begin() != elf->symbol_end()) {
35705400539d15c50a52a388daba2e831b86824cc8eYabin Cui    ReadSymbolTable(elf->symbol_begin(), elf->symbol_end(), callback, is_arm);
358dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::NO_ERROR;
35905400539d15c50a52a388daba2e831b86824cc8eYabin Cui  } else if (elf->dynamic_symbol_begin()->getRawDataRefImpl() != llvm::object::DataRefImpl()) {
36005400539d15c50a52a388daba2e831b86824cc8eYabin Cui    ReadSymbolTable(elf->dynamic_symbol_begin(), elf->dynamic_symbol_end(), callback, is_arm);
36105400539d15c50a52a388daba2e831b86824cc8eYabin Cui  }
36205400539d15c50a52a388daba2e831b86824cc8eYabin Cui  std::string debugdata;
363dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = ReadSectionFromELFFile(elf, ".gnu_debugdata", &debugdata);
364dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result == ElfStatus::SECTION_NOT_FOUND) {
365dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::NO_SYMBOL_TABLE;
366dec43c18d06415a955b8f32355bca925be901905Yabin Cui  } else if (result == ElfStatus::NO_ERROR) {
36705400539d15c50a52a388daba2e831b86824cc8eYabin Cui    std::string decompressed_data;
36805400539d15c50a52a388daba2e831b86824cc8eYabin Cui    if (XzDecompress(debugdata, &decompressed_data)) {
369dec43c18d06415a955b8f32355bca925be901905Yabin Cui      BinaryWrapper wrapper;
370dec43c18d06415a955b8f32355bca925be901905Yabin Cui      result = OpenObjectFileFromString(decompressed_data, &wrapper);
371dec43c18d06415a955b8f32355bca925be901905Yabin Cui      if (result == ElfStatus::NO_ERROR) {
372dec43c18d06415a955b8f32355bca925be901905Yabin Cui        if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
373dec43c18d06415a955b8f32355bca925be901905Yabin Cui          return ParseSymbolsFromELFFile(elf, callback);
374dec43c18d06415a955b8f32355bca925be901905Yabin Cui        } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
375dec43c18d06415a955b8f32355bca925be901905Yabin Cui          return ParseSymbolsFromELFFile(elf, callback);
376dec43c18d06415a955b8f32355bca925be901905Yabin Cui        } else {
377dec43c18d06415a955b8f32355bca925be901905Yabin Cui          return ElfStatus::FILE_MALFORMED;
37805400539d15c50a52a388daba2e831b86824cc8eYabin Cui        }
37905400539d15c50a52a388daba2e831b86824cc8eYabin Cui      }
38005400539d15c50a52a388daba2e831b86824cc8eYabin Cui    }
38105400539d15c50a52a388daba2e831b86824cc8eYabin Cui  }
382dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return result;
38305400539d15c50a52a388daba2e831b86824cc8eYabin Cui}
38405400539d15c50a52a388daba2e831b86824cc8eYabin Cui
385dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus MatchBuildId(llvm::object::ObjectFile* obj, const BuildId& expected_build_id) {
386b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  if (expected_build_id.IsEmpty()) {
387dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::NO_ERROR;
388ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui  }
389b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  BuildId real_build_id;
390dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = GetBuildIdFromObjectFile(obj, &real_build_id);
391dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
392dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
393ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui  }
394b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  if (expected_build_id != real_build_id) {
395dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::BUILD_ID_MISMATCH;
396dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
397dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::NO_ERROR;
398547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui}
399547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui
400dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus ParseSymbolsFromElfFile(const std::string& filename,
401dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                  const BuildId& expected_build_id,
402dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                  const std::function<void(const ElfFileSymbol&)>& callback) {
403dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = IsValidElfPath(filename);
404dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
405dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
406797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui  }
407b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui  return ParseSymbolsFromEmbeddedElfFile(filename, 0, 0, expected_build_id, callback);
408b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui}
409b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui
410dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus ParseSymbolsFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
411b1a885b014540a2f7798b5a35ea0f0ec150d93eeYabin Cui                                     uint32_t file_size, const BuildId& expected_build_id,
4123e4c5950f3aafb0bf66544468d98ee3ec26b705cYabin Cui                                     const std::function<void(const ElfFileSymbol&)>& callback) {
413dec43c18d06415a955b8f32355bca925be901905Yabin Cui  BinaryWrapper wrapper;
414dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = OpenObjectFile(filename, file_offset, file_size, &wrapper);
415dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
416dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
417dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
418dec43c18d06415a955b8f32355bca925be901905Yabin Cui  result = MatchBuildId(wrapper.obj, expected_build_id);
419dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
420dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
421dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
422dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
423dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ParseSymbolsFromELFFile(elf, callback);
424dec43c18d06415a955b8f32355bca925be901905Yabin Cui  } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
425dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ParseSymbolsFromELFFile(elf, callback);
426638c558339b7f1ae0ed95f64bcf7dbc5b238ed83Yabin Cui  }
427dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::FILE_MALFORMED;
428ec12ed9010128483993a87d68edc02d3a89d56cfYabin Cui}
429547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui
430547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cuitemplate <class ELFT>
431dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus ReadMinExecutableVirtualAddress(const llvm::object::ELFFile<ELFT>* elf, uint64_t* p_vaddr) {
432547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui  bool has_vaddr = false;
433547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui  uint64_t min_addr = std::numeric_limits<uint64_t>::max();
43407cdff03ffb5e69d73979e8c2f8585314751ee17Yabin Cui  for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
435547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui    if ((it->p_type == llvm::ELF::PT_LOAD) && (it->p_flags & llvm::ELF::PF_X)) {
436547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui      if (it->p_vaddr < min_addr) {
437547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui        min_addr = it->p_vaddr;
438547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui        has_vaddr = true;
439547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui      }
440547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui    }
441547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui  }
442dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (!has_vaddr) {
443dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_MALFORMED;
444547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui  }
445dec43c18d06415a955b8f32355bca925be901905Yabin Cui  *p_vaddr = min_addr;
446dec43c18d06415a955b8f32355bca925be901905Yabin Cui  return ElfStatus::NO_ERROR;
447547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui}
448547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui
449dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus ReadMinExecutableVirtualAddressFromElfFile(const std::string& filename,
450dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                                     const BuildId& expected_build_id,
451dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                                     uint64_t* min_vaddr) {
452dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = IsValidElfPath(filename);
453dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
454dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
455797116bfb9ad10d858086680c7465d65c399ef6eYabin Cui  }
456dec43c18d06415a955b8f32355bca925be901905Yabin Cui  BinaryWrapper wrapper;
457dec43c18d06415a955b8f32355bca925be901905Yabin Cui  result = OpenObjectFile(filename, 0, 0, &wrapper);
458dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
459dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
460547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui  }
461dec43c18d06415a955b8f32355bca925be901905Yabin Cui  result = MatchBuildId(wrapper.obj, expected_build_id);
462dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
463dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
464547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui  }
465547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui
466dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
467dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
468dec43c18d06415a955b8f32355bca925be901905Yabin Cui  } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
469dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ReadMinExecutableVirtualAddress(elf->getELFFile(), min_vaddr);
470dec43c18d06415a955b8f32355bca925be901905Yabin Cui  } else {
471dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_MALFORMED;
472547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui  }
473547c60e4dd29c5788d5948ad348acf33a55d6ed6Yabin Cui}
474be7ec66eaa4f995bd9068637f7c7d5718173922cYabin Cui
475dec43c18d06415a955b8f32355bca925be901905Yabin CuiElfStatus ReadSectionFromElfFile(const std::string& filename, const std::string& section_name,
476dec43c18d06415a955b8f32355bca925be901905Yabin Cui                                 std::string* content) {
477dec43c18d06415a955b8f32355bca925be901905Yabin Cui  ElfStatus result = IsValidElfPath(filename);
478dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
479dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
480dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
481dec43c18d06415a955b8f32355bca925be901905Yabin Cui  BinaryWrapper wrapper;
482dec43c18d06415a955b8f32355bca925be901905Yabin Cui  result = OpenObjectFile(filename, 0, 0, &wrapper);
483dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (result != ElfStatus::NO_ERROR) {
484dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return result;
485dec43c18d06415a955b8f32355bca925be901905Yabin Cui  }
486dec43c18d06415a955b8f32355bca925be901905Yabin Cui  if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(wrapper.obj)) {
487dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ReadSectionFromELFFile(elf, section_name, content);
488dec43c18d06415a955b8f32355bca925be901905Yabin Cui  } else if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(wrapper.obj)) {
489dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ReadSectionFromELFFile(elf, section_name, content);
490be7ec66eaa4f995bd9068637f7c7d5718173922cYabin Cui  } else {
491dec43c18d06415a955b8f32355bca925be901905Yabin Cui    return ElfStatus::FILE_MALFORMED;
492be7ec66eaa4f995bd9068637f7c7d5718173922cYabin Cui  }
493be7ec66eaa4f995bd9068637f7c7d5718173922cYabin Cui}
494