130fdc8d8SChris Lattner //===-- SourceManager.cpp ---------------------------------------*- C++ -*-===// 230fdc8d8SChris Lattner // 330fdc8d8SChris Lattner // The LLVM Compiler Infrastructure 430fdc8d8SChris Lattner // 530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source 630fdc8d8SChris Lattner // License. See LICENSE.TXT for details. 730fdc8d8SChris Lattner // 830fdc8d8SChris Lattner //===----------------------------------------------------------------------===// 930fdc8d8SChris Lattner 1030fdc8d8SChris Lattner #include "lldb/Core/SourceManager.h" 1130fdc8d8SChris Lattner 1230fdc8d8SChris Lattner // C Includes 1330fdc8d8SChris Lattner // C++ Includes 1430fdc8d8SChris Lattner // Other libraries and framework includes 1530fdc8d8SChris Lattner // Project includes 1630fdc8d8SChris Lattner #include "lldb/Core/DataBuffer.h" 1730fdc8d8SChris Lattner #include "lldb/Core/Stream.h" 18176761e5SGreg Clayton #include "lldb/Symbol/SymbolContext.h" 197e14f91dSGreg Clayton #include "lldb/Target/Target.h" 2030fdc8d8SChris Lattner 2130fdc8d8SChris Lattner using namespace lldb_private; 2230fdc8d8SChris Lattner 2330fdc8d8SChris Lattner static inline bool is_newline_char(char ch) 2430fdc8d8SChris Lattner { 2530fdc8d8SChris Lattner return ch == '\n' || ch == '\r'; 2630fdc8d8SChris Lattner } 2730fdc8d8SChris Lattner 2830fdc8d8SChris Lattner 2930fdc8d8SChris Lattner //---------------------------------------------------------------------- 3030fdc8d8SChris Lattner // SourceManager constructor 3130fdc8d8SChris Lattner //---------------------------------------------------------------------- 32*b7f6b2faSJim Ingham SourceManager::SourceManager(Target *target) : 3330fdc8d8SChris Lattner m_file_cache (), 3430fdc8d8SChris Lattner m_last_file_sp (), 3530fdc8d8SChris Lattner m_last_file_line (0), 3630fdc8d8SChris Lattner m_last_file_context_before (0), 37*b7f6b2faSJim Ingham m_last_file_context_after (10), 38*b7f6b2faSJim Ingham m_target (target) 3930fdc8d8SChris Lattner { 4030fdc8d8SChris Lattner } 4130fdc8d8SChris Lattner 4230fdc8d8SChris Lattner //---------------------------------------------------------------------- 4330fdc8d8SChris Lattner // Destructor 4430fdc8d8SChris Lattner //---------------------------------------------------------------------- 4530fdc8d8SChris Lattner SourceManager::~SourceManager() 4630fdc8d8SChris Lattner { 4730fdc8d8SChris Lattner } 4830fdc8d8SChris Lattner 4930fdc8d8SChris Lattner size_t 5030fdc8d8SChris Lattner SourceManager::DisplaySourceLines 5130fdc8d8SChris Lattner ( 5230fdc8d8SChris Lattner const FileSpec &file_spec, 5330fdc8d8SChris Lattner uint32_t line, 5430fdc8d8SChris Lattner uint32_t context_before, 5530fdc8d8SChris Lattner uint32_t context_after, 5630fdc8d8SChris Lattner Stream *s 5730fdc8d8SChris Lattner ) 5830fdc8d8SChris Lattner { 59*b7f6b2faSJim Ingham m_last_file_sp = GetFile (file_spec); 6030fdc8d8SChris Lattner m_last_file_line = line + context_after + 1; 6130fdc8d8SChris Lattner m_last_file_context_before = context_before; 6230fdc8d8SChris Lattner m_last_file_context_after = context_after; 6330fdc8d8SChris Lattner if (m_last_file_sp.get()) 6430fdc8d8SChris Lattner return m_last_file_sp->DisplaySourceLines (line, context_before, context_after, s); 6530fdc8d8SChris Lattner 6630fdc8d8SChris Lattner return 0; 6730fdc8d8SChris Lattner } 6830fdc8d8SChris Lattner 6930fdc8d8SChris Lattner SourceManager::FileSP 70*b7f6b2faSJim Ingham SourceManager::GetFile (const FileSpec &file_spec) 7130fdc8d8SChris Lattner { 7230fdc8d8SChris Lattner FileSP file_sp; 7330fdc8d8SChris Lattner FileCache::iterator pos = m_file_cache.find(file_spec); 7430fdc8d8SChris Lattner if (pos != m_file_cache.end()) 7530fdc8d8SChris Lattner file_sp = pos->second; 7630fdc8d8SChris Lattner else 7730fdc8d8SChris Lattner { 78*b7f6b2faSJim Ingham file_sp.reset (new File (file_spec, m_target)); 7930fdc8d8SChris Lattner m_file_cache[file_spec] = file_sp; 8030fdc8d8SChris Lattner } 8130fdc8d8SChris Lattner return file_sp; 8230fdc8d8SChris Lattner } 8330fdc8d8SChris Lattner 8430fdc8d8SChris Lattner size_t 8530fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile 8630fdc8d8SChris Lattner ( 8730fdc8d8SChris Lattner uint32_t line, 8830fdc8d8SChris Lattner uint32_t context_before, 8930fdc8d8SChris Lattner uint32_t context_after, 9030fdc8d8SChris Lattner const char* current_line_cstr, 91176761e5SGreg Clayton Stream *s, 92176761e5SGreg Clayton const SymbolContextList *bp_locs 9330fdc8d8SChris Lattner ) 9430fdc8d8SChris Lattner { 9530fdc8d8SChris Lattner if (line == 0) 9630fdc8d8SChris Lattner { 9730fdc8d8SChris Lattner if (m_last_file_line != 0 9830fdc8d8SChris Lattner && m_last_file_line != UINT32_MAX) 9930fdc8d8SChris Lattner line = m_last_file_line + context_before; 10030fdc8d8SChris Lattner else 10130fdc8d8SChris Lattner line = 1; 10230fdc8d8SChris Lattner } 10330fdc8d8SChris Lattner 10430fdc8d8SChris Lattner m_last_file_line = line + context_after + 1; 10530fdc8d8SChris Lattner m_last_file_context_before = context_before; 10630fdc8d8SChris Lattner m_last_file_context_after = context_after; 10730fdc8d8SChris Lattner 10830fdc8d8SChris Lattner if (context_before == UINT32_MAX) 10930fdc8d8SChris Lattner context_before = 0; 11030fdc8d8SChris Lattner if (context_after == UINT32_MAX) 11130fdc8d8SChris Lattner context_after = 10; 11230fdc8d8SChris Lattner 11330fdc8d8SChris Lattner if (m_last_file_sp.get()) 11430fdc8d8SChris Lattner { 11530fdc8d8SChris Lattner const uint32_t start_line = line <= context_before ? 1 : line - context_before; 11630fdc8d8SChris Lattner const uint32_t end_line = line + context_after; 11730fdc8d8SChris Lattner uint32_t curr_line; 11830fdc8d8SChris Lattner for (curr_line = start_line; curr_line <= end_line; ++curr_line) 11930fdc8d8SChris Lattner { 12030fdc8d8SChris Lattner if (!m_last_file_sp->LineIsValid (curr_line)) 12130fdc8d8SChris Lattner { 12230fdc8d8SChris Lattner m_last_file_line = UINT32_MAX; 12330fdc8d8SChris Lattner break; 12430fdc8d8SChris Lattner } 12530fdc8d8SChris Lattner 126176761e5SGreg Clayton char prefix[32] = ""; 127176761e5SGreg Clayton if (bp_locs) 128176761e5SGreg Clayton { 129176761e5SGreg Clayton uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line); 130176761e5SGreg Clayton 131176761e5SGreg Clayton if (bp_count > 0) 132176761e5SGreg Clayton ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count); 133176761e5SGreg Clayton else 134176761e5SGreg Clayton ::snprintf (prefix, sizeof (prefix), " "); 135176761e5SGreg Clayton } 136176761e5SGreg Clayton 137176761e5SGreg Clayton s->Printf("%s%2.2s %-4u\t", 138176761e5SGreg Clayton prefix, 139176761e5SGreg Clayton curr_line == line ? current_line_cstr : "", 140176761e5SGreg Clayton curr_line); 14130fdc8d8SChris Lattner if (m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s) == 0) 14230fdc8d8SChris Lattner { 14330fdc8d8SChris Lattner m_last_file_line = UINT32_MAX; 14430fdc8d8SChris Lattner break; 14530fdc8d8SChris Lattner } 14630fdc8d8SChris Lattner } 14730fdc8d8SChris Lattner } 14830fdc8d8SChris Lattner return 0; 14930fdc8d8SChris Lattner } 15030fdc8d8SChris Lattner 15130fdc8d8SChris Lattner size_t 15230fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbers 15330fdc8d8SChris Lattner ( 15430fdc8d8SChris Lattner const FileSpec &file_spec, 15530fdc8d8SChris Lattner uint32_t line, 15630fdc8d8SChris Lattner uint32_t context_before, 15730fdc8d8SChris Lattner uint32_t context_after, 15830fdc8d8SChris Lattner const char* current_line_cstr, 159176761e5SGreg Clayton Stream *s, 160176761e5SGreg Clayton const SymbolContextList *bp_locs 16130fdc8d8SChris Lattner ) 16230fdc8d8SChris Lattner { 16330fdc8d8SChris Lattner bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec); 16430fdc8d8SChris Lattner 16530fdc8d8SChris Lattner if (!same_as_previous) 166*b7f6b2faSJim Ingham m_last_file_sp = GetFile (file_spec); 16730fdc8d8SChris Lattner 16830fdc8d8SChris Lattner if (line == 0) 16930fdc8d8SChris Lattner { 17030fdc8d8SChris Lattner if (!same_as_previous) 17130fdc8d8SChris Lattner m_last_file_line = 0; 17230fdc8d8SChris Lattner } 17330fdc8d8SChris Lattner 174176761e5SGreg Clayton return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs); 17530fdc8d8SChris Lattner } 17630fdc8d8SChris Lattner 17730fdc8d8SChris Lattner size_t 178176761e5SGreg Clayton SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs) 17930fdc8d8SChris Lattner { 18030fdc8d8SChris Lattner if (m_last_file_sp) 18130fdc8d8SChris Lattner { 18230fdc8d8SChris Lattner if (m_last_file_line == UINT32_MAX) 18330fdc8d8SChris Lattner return 0; 184176761e5SGreg Clayton DisplaySourceLinesWithLineNumbersUsingLastFile (0, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs); 18530fdc8d8SChris Lattner } 18630fdc8d8SChris Lattner return 0; 18730fdc8d8SChris Lattner } 18830fdc8d8SChris Lattner 189*b7f6b2faSJim Ingham bool 190*b7f6b2faSJim Ingham SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line) 191*b7f6b2faSJim Ingham { 192*b7f6b2faSJim Ingham FileSP old_file_sp = m_last_file_sp; 193*b7f6b2faSJim Ingham m_last_file_sp = GetFile (file_spec); 194*b7f6b2faSJim Ingham if (m_last_file_sp) 195*b7f6b2faSJim Ingham { 196*b7f6b2faSJim Ingham m_last_file_line = line; 197*b7f6b2faSJim Ingham return true; 198*b7f6b2faSJim Ingham } 199*b7f6b2faSJim Ingham else 200*b7f6b2faSJim Ingham { 201*b7f6b2faSJim Ingham m_last_file_sp = old_file_sp; 202*b7f6b2faSJim Ingham return false; 203*b7f6b2faSJim Ingham } 204*b7f6b2faSJim Ingham } 205*b7f6b2faSJim Ingham 206*b7f6b2faSJim Ingham bool 207*b7f6b2faSJim Ingham SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line) 208*b7f6b2faSJim Ingham { 209*b7f6b2faSJim Ingham if (m_last_file_sp) 210*b7f6b2faSJim Ingham { 211*b7f6b2faSJim Ingham file_spec = m_last_file_sp->GetFileSpec(); 212*b7f6b2faSJim Ingham line = m_last_file_line; 213*b7f6b2faSJim Ingham return true; 214*b7f6b2faSJim Ingham } 215*b7f6b2faSJim Ingham else 216*b7f6b2faSJim Ingham return false; 217*b7f6b2faSJim Ingham } 21830fdc8d8SChris Lattner 21930fdc8d8SChris Lattner 2207e14f91dSGreg Clayton SourceManager::File::File(const FileSpec &file_spec, Target *target) : 2217e14f91dSGreg Clayton m_file_spec_orig (file_spec), 22230fdc8d8SChris Lattner m_file_spec(file_spec), 2237e14f91dSGreg Clayton m_mod_time (file_spec.GetModificationTime()), 2247e14f91dSGreg Clayton m_data_sp(), 22530fdc8d8SChris Lattner m_offsets() 22630fdc8d8SChris Lattner { 2277e14f91dSGreg Clayton if (!m_mod_time.IsValid()) 2287e14f91dSGreg Clayton { 229*b7f6b2faSJim Ingham if (target && target->GetSourcePathMap().RemapPath(file_spec.GetDirectory(), m_file_spec.GetDirectory())) 2307e14f91dSGreg Clayton m_mod_time = file_spec.GetModificationTime(); 2317e14f91dSGreg Clayton } 2327e14f91dSGreg Clayton 2337e14f91dSGreg Clayton if (m_mod_time.IsValid()) 2347e14f91dSGreg Clayton m_data_sp = m_file_spec.ReadFileContents (); 23530fdc8d8SChris Lattner } 23630fdc8d8SChris Lattner 23730fdc8d8SChris Lattner SourceManager::File::~File() 23830fdc8d8SChris Lattner { 23930fdc8d8SChris Lattner } 24030fdc8d8SChris Lattner 24130fdc8d8SChris Lattner uint32_t 24230fdc8d8SChris Lattner SourceManager::File::GetLineOffset (uint32_t line) 24330fdc8d8SChris Lattner { 24430fdc8d8SChris Lattner if (line == 0) 24530fdc8d8SChris Lattner return UINT32_MAX; 24630fdc8d8SChris Lattner 24730fdc8d8SChris Lattner if (line == 1) 24830fdc8d8SChris Lattner return 0; 24930fdc8d8SChris Lattner 25030fdc8d8SChris Lattner if (CalculateLineOffsets (line)) 25130fdc8d8SChris Lattner { 25230fdc8d8SChris Lattner if (line < m_offsets.size()) 25330fdc8d8SChris Lattner return m_offsets[line - 1]; // yes we want "line - 1" in the index 25430fdc8d8SChris Lattner } 25530fdc8d8SChris Lattner return UINT32_MAX; 25630fdc8d8SChris Lattner } 25730fdc8d8SChris Lattner 25830fdc8d8SChris Lattner bool 25930fdc8d8SChris Lattner SourceManager::File::LineIsValid (uint32_t line) 26030fdc8d8SChris Lattner { 26130fdc8d8SChris Lattner if (line == 0) 26230fdc8d8SChris Lattner return false; 26330fdc8d8SChris Lattner 26430fdc8d8SChris Lattner if (CalculateLineOffsets (line)) 26530fdc8d8SChris Lattner return line < m_offsets.size(); 26630fdc8d8SChris Lattner return false; 26730fdc8d8SChris Lattner } 26830fdc8d8SChris Lattner 26930fdc8d8SChris Lattner size_t 27030fdc8d8SChris Lattner SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s) 27130fdc8d8SChris Lattner { 2729625d08cSGreg Clayton // TODO: use host API to sign up for file modifications to anything in our 2739625d08cSGreg Clayton // source cache and only update when we determine a file has been updated. 2749625d08cSGreg Clayton // For now we check each time we want to display info for the file. 2759625d08cSGreg Clayton TimeValue curr_mod_time (m_file_spec.GetModificationTime()); 2769625d08cSGreg Clayton if (m_mod_time != curr_mod_time) 2779625d08cSGreg Clayton { 2789625d08cSGreg Clayton m_mod_time = curr_mod_time; 2799625d08cSGreg Clayton m_data_sp = m_file_spec.ReadFileContents (); 2809625d08cSGreg Clayton m_offsets.clear(); 2819625d08cSGreg Clayton } 2829625d08cSGreg Clayton 28330fdc8d8SChris Lattner const uint32_t start_line = line <= context_before ? 1 : line - context_before; 28430fdc8d8SChris Lattner const uint32_t start_line_offset = GetLineOffset (start_line); 28530fdc8d8SChris Lattner if (start_line_offset != UINT32_MAX) 28630fdc8d8SChris Lattner { 28730fdc8d8SChris Lattner const uint32_t end_line = line + context_after; 28830fdc8d8SChris Lattner uint32_t end_line_offset = GetLineOffset (end_line + 1); 28930fdc8d8SChris Lattner if (end_line_offset == UINT32_MAX) 29030fdc8d8SChris Lattner end_line_offset = m_data_sp->GetByteSize(); 29130fdc8d8SChris Lattner 29230fdc8d8SChris Lattner assert (start_line_offset <= end_line_offset); 29330fdc8d8SChris Lattner size_t bytes_written = 0; 29430fdc8d8SChris Lattner if (start_line_offset < end_line_offset) 29530fdc8d8SChris Lattner { 29630fdc8d8SChris Lattner size_t count = end_line_offset - start_line_offset; 29730fdc8d8SChris Lattner const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset; 29830fdc8d8SChris Lattner bytes_written = s->Write(cstr, count); 29930fdc8d8SChris Lattner if (!is_newline_char(cstr[count-1])) 30030fdc8d8SChris Lattner bytes_written += s->EOL(); 30130fdc8d8SChris Lattner } 30230fdc8d8SChris Lattner return bytes_written; 30330fdc8d8SChris Lattner } 30430fdc8d8SChris Lattner return 0; 30530fdc8d8SChris Lattner } 30630fdc8d8SChris Lattner 30730fdc8d8SChris Lattner bool 30830fdc8d8SChris Lattner SourceManager::File::FileSpecMatches (const FileSpec &file_spec) 30930fdc8d8SChris Lattner { 310644247c1SGreg Clayton return FileSpec::Equal (m_file_spec, file_spec, false); 31130fdc8d8SChris Lattner } 31230fdc8d8SChris Lattner 31330fdc8d8SChris Lattner 31430fdc8d8SChris Lattner bool 31530fdc8d8SChris Lattner SourceManager::File::CalculateLineOffsets (uint32_t line) 31630fdc8d8SChris Lattner { 31730fdc8d8SChris Lattner line = UINT32_MAX; // TODO: take this line out when we support partial indexing 31830fdc8d8SChris Lattner if (line == UINT32_MAX) 31930fdc8d8SChris Lattner { 32030fdc8d8SChris Lattner // Already done? 32130fdc8d8SChris Lattner if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX) 32230fdc8d8SChris Lattner return true; 32330fdc8d8SChris Lattner 32430fdc8d8SChris Lattner if (m_offsets.empty()) 32530fdc8d8SChris Lattner { 32630fdc8d8SChris Lattner if (m_data_sp.get() == NULL) 32730fdc8d8SChris Lattner return false; 32830fdc8d8SChris Lattner 32930fdc8d8SChris Lattner const char *start = (char *)m_data_sp->GetBytes(); 33030fdc8d8SChris Lattner if (start) 33130fdc8d8SChris Lattner { 33230fdc8d8SChris Lattner const char *end = start + m_data_sp->GetByteSize(); 33330fdc8d8SChris Lattner 33430fdc8d8SChris Lattner // Calculate all line offsets from scratch 33530fdc8d8SChris Lattner 33630fdc8d8SChris Lattner // Push a 1 at index zero to indicate the file has been completely indexed. 33730fdc8d8SChris Lattner m_offsets.push_back(UINT32_MAX); 33830fdc8d8SChris Lattner register const char *s; 33930fdc8d8SChris Lattner for (s = start; s < end; ++s) 34030fdc8d8SChris Lattner { 34130fdc8d8SChris Lattner register char curr_ch = *s; 34230fdc8d8SChris Lattner if (is_newline_char (curr_ch)) 34330fdc8d8SChris Lattner { 34430fdc8d8SChris Lattner register char next_ch = s[1]; 34530fdc8d8SChris Lattner if (is_newline_char (next_ch)) 34630fdc8d8SChris Lattner { 34730fdc8d8SChris Lattner if (curr_ch != next_ch) 34830fdc8d8SChris Lattner ++s; 34930fdc8d8SChris Lattner } 35030fdc8d8SChris Lattner m_offsets.push_back(s + 1 - start); 35130fdc8d8SChris Lattner } 35230fdc8d8SChris Lattner } 35330fdc8d8SChris Lattner if (!m_offsets.empty()) 35430fdc8d8SChris Lattner { 35530fdc8d8SChris Lattner if (m_offsets.back() < end - start) 35630fdc8d8SChris Lattner m_offsets.push_back(end - start); 35730fdc8d8SChris Lattner } 35830fdc8d8SChris Lattner return true; 35930fdc8d8SChris Lattner } 36030fdc8d8SChris Lattner } 36130fdc8d8SChris Lattner else 36230fdc8d8SChris Lattner { 36330fdc8d8SChris Lattner // Some lines have been populated, start where we last left off 36430fdc8d8SChris Lattner assert(!"Not implemented yet"); 36530fdc8d8SChris Lattner } 36630fdc8d8SChris Lattner 36730fdc8d8SChris Lattner } 36830fdc8d8SChris Lattner else 36930fdc8d8SChris Lattner { 37030fdc8d8SChris Lattner // Calculate all line offsets up to "line" 37130fdc8d8SChris Lattner assert(!"Not implemented yet"); 37230fdc8d8SChris Lattner } 37330fdc8d8SChris Lattner return false; 37430fdc8d8SChris Lattner } 375