aboutsummaryrefslogtreecommitdiff
path: root/lld/ELF/Strings.cpp
blob: cd19612acc65c753eda5703d1bfc750764238d80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//===- Strings.cpp -------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Strings.h"
#include "Error.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/config.h"
#include "llvm/Demangle/Demangle.h"
#include <algorithm>

using namespace llvm;
using namespace lld;
using namespace lld::elf;

bool elf::hasWildcard(StringRef S) {
  return S.find_first_of("?*[") != StringRef::npos;
}

StringRef elf::unquote(StringRef S) {
  if (!S.startswith("\""))
    return S;
  return S.substr(1, S.size() - 2);
}

// Converts a glob pattern to a regular expression.
static std::string toRegex(StringRef S) {
  std::string T;
  bool InBracket = false;
  while (!S.empty()) {
    char C = S.front();
    if (InBracket) {
      InBracket = C != ']';
      T += C;
      S = S.drop_front();
      continue;
    }

    if (C == '*')
      T += ".*";
    else if (C == '?')
      T += '.';
    else if (StringRef(".+^${}()|/\\").find_first_of(C) != StringRef::npos)
      T += std::string("\\") + C;
    else
      T += C;

    InBracket = C == '[';
    S = S.substr(1);
  }
  return T;
}

// Converts multiple glob patterns to a regular expression.
Regex elf::compileGlobPatterns(ArrayRef<StringRef> V) {
  std::string T = "^(" + toRegex(V[0]);
  for (StringRef S : V.slice(1))
    T += "|" + toRegex(S);
  return Regex(T + ")$");
}

// Converts a hex string (e.g. "deadbeef") to a vector.
std::vector<uint8_t> elf::parseHex(StringRef S) {
  std::vector<uint8_t> Hex;
  while (!S.empty()) {
    StringRef B = S.substr(0, 2);
    S = S.substr(2);
    uint8_t H;
    if (B.getAsInteger(16, H)) {
      error("not a hexadecimal value: " + B);
      return {};
    }
    Hex.push_back(H);
  }
  return Hex;
}

static bool isAlpha(char C) {
  return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_';
}

static bool isAlnum(char C) { return isAlpha(C) || ('0' <= C && C <= '9'); }

// Returns true if S is valid as a C language identifier.
bool elf::isValidCIdentifier(StringRef S) {
  return !S.empty() && isAlpha(S[0]) &&
         std::all_of(S.begin() + 1, S.end(), isAlnum);
}

// Returns the demangled C++ symbol name for Name.
std::string elf::demangle(StringRef Name) {
  // __cxa_demangle can be used to demangle strings other than symbol
  // names which do not necessarily start with "_Z". Name can be
  // either a C or C++ symbol. Don't call __cxa_demangle if the name
  // does not look like a C++ symbol name to avoid getting unexpected
  // result for a C symbol that happens to match a mangled type name.
  if (!Name.startswith("_Z"))
    return Name;

  char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
  if (!Buf)
    return Name;
  std::string S(Buf);
  free(Buf);
  return S;
}