1//===-- GsymContext.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===/
8
9#include "llvm/DebugInfo/GSYM/GsymContext.h"
10
11#include "llvm/DebugInfo/GSYM/GsymReader.h"
12#include "llvm/Support/Path.h"
13
14using namespace llvm;
15using namespace llvm::gsym;
16
17GsymContext::~GsymContext() = default;
18GsymContext::GsymContext(std::unique_ptr<GsymReader> Reader)
19 : DIContext(CK_GSYM), Reader(std::move(Reader)) {}
20
21void GsymContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {}
22
23static bool fillLineInfoFromLocation(const SourceLocation &Location,
24 DILineInfoSpecifier Specifier,
25 DILineInfo &LineInfo) {
26 // FIXME Demangle in case of DINameKind::ShortName
27 if (Specifier.FNKind != DINameKind::None) {
28 LineInfo.FunctionName = Location.Name.str();
29 }
30
31 switch (Specifier.FLIKind) {
32 case DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath:
33 // We have no information to determine the relative path, so we fall back to
34 // returning the absolute path.
35 case DILineInfoSpecifier::FileLineInfoKind::RawValue:
36 case DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath:
37 if (Location.Dir.empty()) {
38 if (Location.Base.empty())
39 LineInfo.FileName = DILineInfo::BadString;
40 else
41 LineInfo.FileName = Location.Base.str();
42 } else {
43 SmallString<128> Path(Location.Dir);
44 sys::path::append(path&: Path, a: Location.Base);
45 LineInfo.FileName = static_cast<std::string>(Path);
46 }
47 break;
48
49 case DILineInfoSpecifier::FileLineInfoKind::BaseNameOnly:
50 LineInfo.FileName = Location.Base.str();
51 break;
52
53 default:
54 return false;
55 }
56 LineInfo.Line = Location.Line;
57
58 // We don't have information in GSYM to fill any of the Source, Column,
59 // StartFileName or StartLine attributes.
60
61 return true;
62}
63
64std::optional<DILineInfo>
65GsymContext::getLineInfoForAddress(object::SectionedAddress Address,
66 DILineInfoSpecifier Specifier) {
67 if (Address.SectionIndex != object::SectionedAddress::UndefSection)
68 return {};
69
70 auto ResultOrErr = Reader->lookup(Addr: Address.Address);
71
72 if (!ResultOrErr) {
73 consumeError(Err: ResultOrErr.takeError());
74 return {};
75 }
76
77 const auto &Result = *ResultOrErr;
78
79 DILineInfo LineInfo;
80
81 if (Result.Locations.empty()) {
82 // No debug info for this, we just had a symbol from the symbol table.
83
84 // FIXME Demangle in case of DINameKind::ShortName
85 if (Specifier.FNKind != DINameKind::None)
86 LineInfo.FunctionName = Result.FuncName.str();
87 } else if (!fillLineInfoFromLocation(Location: Result.Locations.front(), Specifier,
88 LineInfo))
89 return {};
90
91 LineInfo.StartAddress = Result.FuncRange.start();
92
93 return LineInfo;
94}
95
96std::optional<DILineInfo>
97GsymContext::getLineInfoForDataAddress(object::SectionedAddress Address) {
98 // We can't implement this, there's no such information in the GSYM file.
99
100 return {};
101}
102
103DILineInfoTable
104GsymContext::getLineInfoForAddressRange(object::SectionedAddress Address,
105 uint64_t Size,
106 DILineInfoSpecifier Specifier) {
107 if (Size == 0)
108 return DILineInfoTable();
109
110 if (Address.SectionIndex != llvm::object::SectionedAddress::UndefSection)
111 return DILineInfoTable();
112
113 if (auto FuncInfoOrErr = Reader->getFunctionInfo(Addr: Address.Address)) {
114 DILineInfoTable Table;
115 if (FuncInfoOrErr->OptLineTable) {
116 const gsym::LineTable &LT = *FuncInfoOrErr->OptLineTable;
117 const uint64_t StartAddr = Address.Address;
118 const uint64_t EndAddr = Address.Address + Size;
119 for (const auto &LineEntry : LT) {
120 if (StartAddr <= LineEntry.Addr && LineEntry.Addr < EndAddr) {
121 // Use LineEntry.Addr, LineEntry.File (which is a file index into the
122 // files tables from the GsymReader), and LineEntry.Line (source line
123 // number) to add stuff to the DILineInfoTable
124 }
125 }
126 }
127 return Table;
128 } else {
129 consumeError(Err: FuncInfoOrErr.takeError());
130 return DILineInfoTable();
131 }
132}
133
134DIInliningInfo
135GsymContext::getInliningInfoForAddress(object::SectionedAddress Address,
136 DILineInfoSpecifier Specifier) {
137 auto ResultOrErr = Reader->lookup(Addr: Address.Address);
138
139 if (!ResultOrErr)
140 return {};
141
142 const auto &Result = *ResultOrErr;
143
144 DIInliningInfo InlineInfo;
145
146 for (const auto &Location : Result.Locations) {
147 DILineInfo LineInfo;
148
149 if (!fillLineInfoFromLocation(Location, Specifier, LineInfo))
150 return {};
151
152 // Hm, that's probably something that should only be filled in the first or
153 // last frame?
154 LineInfo.StartAddress = Result.FuncRange.start();
155
156 InlineInfo.addFrame(Frame: LineInfo);
157 }
158
159 return InlineInfo;
160}
161
162std::vector<DILocal>
163GsymContext::getLocalsForAddress(object::SectionedAddress Address) {
164 // We can't implement this, there's no such information in the GSYM file.
165
166 return {};
167}
168