1 //===-- SourceManager.h -----------------------------------------*- C++ -*-===//
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 #ifndef LLDB_CORE_SOURCEMANAGER_H
10 #define LLDB_CORE_SOURCEMANAGER_H
11 
12 #include "lldb/Utility/FileSpec.h"
13 #include "lldb/lldb-defines.h"
14 #include "lldb/lldb-forward.h"
15 
16 #include "llvm/Support/Chrono.h"
17 #include "llvm/Support/RWMutex.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <map>
22 #include <memory>
23 #include <optional>
24 #include <string>
25 #include <vector>
26 
27 namespace lldb_private {
28 class RegularExpression;
29 class Stream;
30 class SymbolContextList;
31 class Target;
32 
33 class SourceManager {
34 public:
35   class File {
36     friend bool operator==(const SourceManager::File &lhs,
37                            const SourceManager::File &rhs);
38 
39   public:
40     File(const FileSpec &file_spec, lldb::TargetSP target_sp);
41     File(const FileSpec &file_spec, lldb::DebuggerSP debugger_sp);
42 
43     bool ModificationTimeIsStale() const;
44     bool PathRemappingIsStale() const;
45 
46     size_t DisplaySourceLines(uint32_t line, std::optional<size_t> column,
47                               uint32_t context_before, uint32_t context_after,
48                               Stream *s);
49     void FindLinesMatchingRegex(RegularExpression &regex, uint32_t start_line,
50                                 uint32_t end_line,
51                                 std::vector<uint32_t> &match_lines);
52 
53     bool GetLine(uint32_t line_no, std::string &buffer);
54 
55     uint32_t GetLineOffset(uint32_t line);
56 
57     bool LineIsValid(uint32_t line);
58 
59     const FileSpec &GetFileSpec() { return m_file_spec; }
60 
61     uint32_t GetSourceMapModificationID() const { return m_source_map_mod_id; }
62 
63     const char *PeekLineData(uint32_t line);
64 
65     uint32_t GetLineLength(uint32_t line, bool include_newline_chars);
66 
67     uint32_t GetNumLines();
68 
69     llvm::sys::TimePoint<> GetTimestamp() const { return m_mod_time; }
70 
71   protected:
72     /// Set file and update modification time.
73     void SetFileSpec(FileSpec file_spec);
74 
75     bool CalculateLineOffsets(uint32_t line = UINT32_MAX);
76 
77     FileSpec m_file_spec_orig; // The original file spec that was used (can be
78                                // different from m_file_spec)
79     FileSpec m_file_spec; // The actually file spec being used (if the target
80                           // has source mappings, this might be different from
81                           // m_file_spec_orig)
82 
83     // Keep the modification time that this file data is valid for
84     llvm::sys::TimePoint<> m_mod_time;
85 
86     // If the target uses path remappings, be sure to clear our notion of a
87     // source file if the path modification ID changes
88     uint32_t m_source_map_mod_id = 0;
89     lldb::DataBufferSP m_data_sp;
90     typedef std::vector<uint32_t> LineOffsets;
91     LineOffsets m_offsets;
92     lldb::DebuggerWP m_debugger_wp;
93     lldb::TargetWP m_target_wp;
94 
95   private:
96     void CommonInitializer(const FileSpec &file_spec, lldb::TargetSP target_sp);
97   };
98 
99   typedef std::shared_ptr<File> FileSP;
100 
101   /// The SourceFileCache class separates the source manager from the cache of
102   /// source files. There is one source manager per Target but both the Debugger
103   /// and the Process have their own source caches.
104   ///
105   /// The SourceFileCache just handles adding, storing, removing and looking up
106   /// source files. The caching policies are implemented in
107   /// SourceManager::GetFile.
108   class SourceFileCache {
109   public:
110     SourceFileCache() = default;
111     ~SourceFileCache() = default;
112 
113     void AddSourceFile(const FileSpec &file_spec, FileSP file_sp);
114     void RemoveSourceFile(const FileSP &file_sp);
115 
116     FileSP FindSourceFile(const FileSpec &file_spec) const;
117 
118     // Removes all elements from the cache.
119     void Clear() { m_file_cache.clear(); }
120 
121     void Dump(Stream &stream) const;
122 
123   private:
124     void AddSourceFileImpl(const FileSpec &file_spec, FileSP file_sp);
125 
126     typedef std::map<FileSpec, FileSP> FileCache;
127     FileCache m_file_cache;
128 
129     mutable llvm::sys::RWMutex m_mutex;
130   };
131 
132   /// A source manager can be made with a valid Target, in which case it can use
133   /// the path remappings to find source files that are not in their build
134   /// locations.  Without a target it won't be able to do this.
135   /// @{
136   SourceManager(const lldb::DebuggerSP &debugger_sp);
137   SourceManager(const lldb::TargetSP &target_sp);
138   /// @}
139 
140   ~SourceManager();
141 
142   FileSP GetLastFile() { return GetFile(m_last_file_spec); }
143 
144   size_t
145   DisplaySourceLinesWithLineNumbers(const FileSpec &file, uint32_t line,
146                                     uint32_t column, uint32_t context_before,
147                                     uint32_t context_after,
148                                     const char *current_line_cstr, Stream *s,
149                                     const SymbolContextList *bp_locs = nullptr);
150 
151   // This variant uses the last file we visited.
152   size_t DisplaySourceLinesWithLineNumbersUsingLastFile(
153       uint32_t start_line, uint32_t count, uint32_t curr_line, uint32_t column,
154       const char *current_line_cstr, Stream *s,
155       const SymbolContextList *bp_locs = nullptr);
156 
157   size_t DisplayMoreWithLineNumbers(Stream *s, uint32_t count, bool reverse,
158                                     const SymbolContextList *bp_locs = nullptr);
159 
160   bool SetDefaultFileAndLine(const FileSpec &file_spec, uint32_t line);
161 
162   bool GetDefaultFileAndLine(FileSpec &file_spec, uint32_t &line);
163 
164   bool DefaultFileAndLineSet() {
165     return (GetFile(m_last_file_spec).get() != nullptr);
166   }
167 
168   void FindLinesMatchingRegex(FileSpec &file_spec, RegularExpression &regex,
169                               uint32_t start_line, uint32_t end_line,
170                               std::vector<uint32_t> &match_lines);
171 
172   FileSP GetFile(const FileSpec &file_spec);
173 
174 protected:
175   FileSpec m_last_file_spec;
176   uint32_t m_last_line;
177   uint32_t m_last_count;
178   bool m_default_set;
179   lldb::TargetWP m_target_wp;
180   lldb::DebuggerWP m_debugger_wp;
181 
182 private:
183   SourceManager(const SourceManager &) = delete;
184   const SourceManager &operator=(const SourceManager &) = delete;
185 };
186 
187 bool operator==(const SourceManager::File &lhs, const SourceManager::File &rhs);
188 
189 } // namespace lldb_private
190 
191 #endif // LLDB_CORE_SOURCEMANAGER_H
192