aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/DataFormatters/FormatterSection.cpp
blob: 1de633f4998e056c0db0065b5009504c387b554b (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//===-- FormatterBytecode.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "FormatterBytecode.h"
#include "lldb/Core/Module.h"
#include "lldb/DataFormatters/DataVisualization.h"
#include "lldb/Utility/LLDBLog.h"

using namespace lldb;

namespace lldb_private {
static void ForEachFormatterInModule(
    Module &module, SectionType section_type,
    std::function<void(llvm::DataExtractor, llvm::StringRef)> fn) {
  auto *sections = module.GetSectionList();
  if (!sections)
    return;

  auto section_sp = sections->FindSectionByType(section_type, true);
  if (!section_sp)
    return;

  TypeCategoryImplSP category;
  DataVisualization::Categories::GetCategory(ConstString("default"), category);

  // The type summary record is serialized as follows.
  //
  // Each record contains, in order:
  //   * Version number of the record format
  //   * The remaining size of the record
  //   * The size of the type identifier
  //   * The type identifier, either a type name, or a regex
  //   * The size of the entry
  //   * The entry
  //
  // Integers are encoded using ULEB.
  //
  // Strings are encoded with first a length (ULEB), then the string contents,
  // and lastly a null terminator. The length includes the null.

  DataExtractor lldb_extractor;
  auto section_size = section_sp->GetSectionData(lldb_extractor);
  llvm::DataExtractor section = lldb_extractor.GetAsLLVM();
  bool le = section.isLittleEndian();
  uint8_t addr_size = section.getAddressSize();
  llvm::DataExtractor::Cursor cursor(0);
  while (cursor && cursor.tell() < section_size) {
    while (cursor && cursor.tell() < section_size) {
      // Skip over 0 padding.
      if (section.getU8(cursor) == 0)
        continue;
      cursor.seek(cursor.tell() - 1);
      break;
    }
    uint64_t version = section.getULEB128(cursor);
    uint64_t record_size = section.getULEB128(cursor);
    if (version == 1) {
      llvm::DataExtractor record(section.getData().drop_front(cursor.tell()),
                                 le, addr_size);
      llvm::DataExtractor::Cursor cursor(0);
      uint64_t type_size = record.getULEB128(cursor);
      llvm::StringRef type_name = record.getBytes(cursor, type_size);
      llvm::Error error = cursor.takeError();
      if (!error)
        fn(llvm::DataExtractor(record.getData().drop_front(cursor.tell()), le,
                               addr_size),
           type_name);
      else
        LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), std::move(error),
                       "{0}");
    } else {
      // Skip unsupported record.
      LLDB_LOG(
          GetLog(LLDBLog::DataFormatters),
          "Skipping unsupported embedded type summary of version {0} in {1}.",
          version, module.GetFileSpec());
    }
    section.skip(cursor, record_size);
  }
  if (!cursor)
    LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), cursor.takeError(), "{0}");
}

void LoadTypeSummariesForModule(ModuleSP module_sp) {
  ForEachFormatterInModule(
      *module_sp, eSectionTypeLLDBTypeSummaries,
      [&](llvm::DataExtractor extractor, llvm::StringRef type_name) {
        TypeCategoryImplSP category;
        DataVisualization::Categories::GetCategory(ConstString("default"),
                                                   category);
        // The type summary record is serialized as follows.
        //
        //   * The size of the summary string
        //   * The summary string
        //
        // Integers are encoded using ULEB.
        llvm::DataExtractor::Cursor cursor(0);
        uint64_t summary_size = extractor.getULEB128(cursor);
        llvm::StringRef summary_string =
            extractor.getBytes(cursor, summary_size);
        if (!cursor) {
          LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), cursor.takeError(),
                         "{0}");
          return;
        }
        if (type_name.empty() || summary_string.empty()) {
          LLDB_LOG(GetLog(LLDBLog::DataFormatters),
                   "Missing string(s) in embedded type summary in {0}, "
                   "type_name={1}, summary={2}",
                   module_sp->GetFileSpec(), type_name, summary_string);
          return;
        }
        TypeSummaryImpl::Flags flags;
        auto summary_sp = std::make_shared<StringSummaryFormat>(
            flags, summary_string.str().c_str());
        FormatterMatchType match_type = eFormatterMatchExact;
        if (type_name.front() == '^')
          match_type = eFormatterMatchRegex;
        category->AddTypeSummary(type_name, match_type, summary_sp);
        LLDB_LOG(GetLog(LLDBLog::DataFormatters),
                 "Loaded embedded type summary for '{0}' from {1}.", type_name,
                 module_sp->GetFileSpec());
      });
}

void LoadFormattersForModule(ModuleSP module_sp) {
  ForEachFormatterInModule(
      *module_sp, eSectionTypeLLDBFormatters,
      [&](llvm::DataExtractor extractor, llvm::StringRef type_name) {
        // * Function signature (1 byte)
        // * Length of the program (ULEB128)
        // * The program bytecode
        TypeCategoryImplSP category;
        DataVisualization::Categories::GetCategory(ConstString("default"),
                                                   category);
        llvm::DataExtractor::Cursor cursor(0);
        uint64_t flags = extractor.getULEB128(cursor);
        while (cursor && cursor.tell() < extractor.size()) {
          uint8_t signature = extractor.getU8(cursor);
          uint64_t size = extractor.getULEB128(cursor);
          llvm::StringRef bytecode = extractor.getBytes(cursor, size);
          if (!cursor) {
            LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), cursor.takeError(),
                           "{0}");
            return;
          }
          if (signature == 0) {
            auto summary_sp = std::make_shared<BytecodeSummaryFormat>(
                TypeSummaryImpl::Flags(flags),
                llvm::MemoryBuffer::getMemBufferCopy(bytecode));
            FormatterMatchType match_type = eFormatterMatchExact;
            if (type_name.front() == '^')
              match_type = eFormatterMatchRegex;
            category->AddTypeSummary(type_name, match_type, summary_sp);
            LLDB_LOG(GetLog(LLDBLog::DataFormatters),
                     "Loaded embedded type summary for '{0}' from {1}.",
                     type_name, module_sp->GetFileSpec());
          } else
            LLDB_LOG(GetLog(LLDBLog::DataFormatters),
                     "Unsupported formatter signature {0} for '{1}' in {2}",
                     signature, type_name, module_sp->GetFileSpec());
        }
      });
}
} // namespace lldb_private