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 1093a64300SDaniel Malea #include "lldb/lldb-python.h" 1193a64300SDaniel Malea 1230fdc8d8SChris Lattner #include "lldb/Core/SourceManager.h" 1330fdc8d8SChris Lattner 1430fdc8d8SChris Lattner // C Includes 1530fdc8d8SChris Lattner // C++ Includes 1630fdc8d8SChris Lattner // Other libraries and framework includes 1730fdc8d8SChris Lattner // Project includes 1830fdc8d8SChris Lattner #include "lldb/Core/DataBuffer.h" 19e37d605eSJim Ingham #include "lldb/Core/Debugger.h" 201f746071SGreg Clayton #include "lldb/Core/Module.h" 2130fdc8d8SChris Lattner #include "lldb/Core/Stream.h" 22b6d70ebcSSean Callanan #include "lldb/Symbol/ClangNamespaceDecl.h" 231f746071SGreg Clayton #include "lldb/Symbol/CompileUnit.h" 241f746071SGreg Clayton #include "lldb/Symbol/Function.h" 25176761e5SGreg Clayton #include "lldb/Symbol/SymbolContext.h" 267e14f91dSGreg Clayton #include "lldb/Target/Target.h" 2730fdc8d8SChris Lattner 2830fdc8d8SChris Lattner using namespace lldb_private; 2930fdc8d8SChris Lattner 3030fdc8d8SChris Lattner static inline bool is_newline_char(char ch) 3130fdc8d8SChris Lattner { 3230fdc8d8SChris Lattner return ch == '\n' || ch == '\r'; 3330fdc8d8SChris Lattner } 3430fdc8d8SChris Lattner 3530fdc8d8SChris Lattner 3630fdc8d8SChris Lattner //---------------------------------------------------------------------- 3730fdc8d8SChris Lattner // SourceManager constructor 3830fdc8d8SChris Lattner //---------------------------------------------------------------------- 39e37d605eSJim Ingham SourceManager::SourceManager(Target &target) : 4030fdc8d8SChris Lattner m_last_file_sp (), 4130fdc8d8SChris Lattner m_last_file_line (0), 4230fdc8d8SChris Lattner m_last_file_context_before (0), 43b7f6b2faSJim Ingham m_last_file_context_after (10), 44f3277750SJim Ingham m_default_set(false), 45*196bbc25SJim Ingham m_first_reverse(true), 46e37d605eSJim Ingham m_target (&target), 47e37d605eSJim Ingham m_debugger(NULL) 48e37d605eSJim Ingham { 49e37d605eSJim Ingham m_debugger = &(m_target->GetDebugger()); 50e37d605eSJim Ingham } 51e37d605eSJim Ingham 52e37d605eSJim Ingham SourceManager::SourceManager(Debugger &debugger) : 53e37d605eSJim Ingham m_last_file_sp (), 54e37d605eSJim Ingham m_last_file_line (0), 55e37d605eSJim Ingham m_last_file_context_before (0), 56e37d605eSJim Ingham m_last_file_context_after (10), 57f3277750SJim Ingham m_default_set(false), 58*196bbc25SJim Ingham m_first_reverse (true), 59e37d605eSJim Ingham m_target (NULL), 60e37d605eSJim Ingham m_debugger (&debugger) 6130fdc8d8SChris Lattner { 6230fdc8d8SChris Lattner } 6330fdc8d8SChris Lattner 6430fdc8d8SChris Lattner //---------------------------------------------------------------------- 6530fdc8d8SChris Lattner // Destructor 6630fdc8d8SChris Lattner //---------------------------------------------------------------------- 6730fdc8d8SChris Lattner SourceManager::~SourceManager() 6830fdc8d8SChris Lattner { 6930fdc8d8SChris Lattner } 7030fdc8d8SChris Lattner 7130fdc8d8SChris Lattner SourceManager::FileSP 72b7f6b2faSJim Ingham SourceManager::GetFile (const FileSpec &file_spec) 7330fdc8d8SChris Lattner { 7430fdc8d8SChris Lattner FileSP file_sp; 75e37d605eSJim Ingham file_sp = m_debugger->GetSourceFileCache().FindSourceFile (file_spec); 7664bab489SJohnny Chen // If file_sp is no good or it points to a non-existent file, reset it. 7764bab489SJohnny Chen if (!file_sp || !file_sp->GetFileSpec().Exists()) 7830fdc8d8SChris Lattner { 79b7f6b2faSJim Ingham file_sp.reset (new File (file_spec, m_target)); 80e37d605eSJim Ingham 81e37d605eSJim Ingham m_debugger->GetSourceFileCache().AddSourceFile(file_sp); 8230fdc8d8SChris Lattner } 8330fdc8d8SChris Lattner return file_sp; 8430fdc8d8SChris Lattner } 8530fdc8d8SChris Lattner 8630fdc8d8SChris Lattner size_t 8730fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile 8830fdc8d8SChris Lattner ( 8930fdc8d8SChris Lattner uint32_t line, 9030fdc8d8SChris Lattner uint32_t context_before, 9130fdc8d8SChris Lattner uint32_t context_after, 9230fdc8d8SChris Lattner const char* current_line_cstr, 93176761e5SGreg Clayton Stream *s, 94176761e5SGreg Clayton const SymbolContextList *bp_locs 9530fdc8d8SChris Lattner ) 9630fdc8d8SChris Lattner { 97*196bbc25SJim Ingham m_first_reverse = true; 98e37d605eSJim Ingham size_t return_value = 0; 9930fdc8d8SChris Lattner if (line == 0) 10030fdc8d8SChris Lattner { 10130fdc8d8SChris Lattner if (m_last_file_line != 0 10230fdc8d8SChris Lattner && m_last_file_line != UINT32_MAX) 10330fdc8d8SChris Lattner line = m_last_file_line + context_before; 10430fdc8d8SChris Lattner else 10530fdc8d8SChris Lattner line = 1; 10630fdc8d8SChris Lattner } 10730fdc8d8SChris Lattner 10830fdc8d8SChris Lattner m_last_file_line = line + context_after + 1; 10930fdc8d8SChris Lattner m_last_file_context_before = context_before; 11030fdc8d8SChris Lattner m_last_file_context_after = context_after; 11130fdc8d8SChris Lattner 11230fdc8d8SChris Lattner if (context_before == UINT32_MAX) 11330fdc8d8SChris Lattner context_before = 0; 11430fdc8d8SChris Lattner if (context_after == UINT32_MAX) 11530fdc8d8SChris Lattner context_after = 10; 11630fdc8d8SChris Lattner 11730fdc8d8SChris Lattner if (m_last_file_sp.get()) 11830fdc8d8SChris Lattner { 11930fdc8d8SChris Lattner const uint32_t start_line = line <= context_before ? 1 : line - context_before; 12030fdc8d8SChris Lattner const uint32_t end_line = line + context_after; 12130fdc8d8SChris Lattner uint32_t curr_line; 12230fdc8d8SChris Lattner for (curr_line = start_line; curr_line <= end_line; ++curr_line) 12330fdc8d8SChris Lattner { 12430fdc8d8SChris Lattner if (!m_last_file_sp->LineIsValid (curr_line)) 12530fdc8d8SChris Lattner { 12630fdc8d8SChris Lattner m_last_file_line = UINT32_MAX; 12730fdc8d8SChris Lattner break; 12830fdc8d8SChris Lattner } 12930fdc8d8SChris Lattner 130176761e5SGreg Clayton char prefix[32] = ""; 131176761e5SGreg Clayton if (bp_locs) 132176761e5SGreg Clayton { 133176761e5SGreg Clayton uint32_t bp_count = bp_locs->NumLineEntriesWithLine (curr_line); 134176761e5SGreg Clayton 135176761e5SGreg Clayton if (bp_count > 0) 136176761e5SGreg Clayton ::snprintf (prefix, sizeof (prefix), "[%u] ", bp_count); 137176761e5SGreg Clayton else 138176761e5SGreg Clayton ::snprintf (prefix, sizeof (prefix), " "); 139176761e5SGreg Clayton } 140176761e5SGreg Clayton 141e37d605eSJim Ingham return_value += s->Printf("%s%2.2s %-4u\t", 142176761e5SGreg Clayton prefix, 143176761e5SGreg Clayton curr_line == line ? current_line_cstr : "", 144176761e5SGreg Clayton curr_line); 145e37d605eSJim Ingham size_t this_line_size = m_last_file_sp->DisplaySourceLines (curr_line, 0, 0, s); 146e37d605eSJim Ingham if (this_line_size == 0) 14730fdc8d8SChris Lattner { 14830fdc8d8SChris Lattner m_last_file_line = UINT32_MAX; 14930fdc8d8SChris Lattner break; 15030fdc8d8SChris Lattner } 151e37d605eSJim Ingham else 152e37d605eSJim Ingham return_value += this_line_size; 15330fdc8d8SChris Lattner } 15430fdc8d8SChris Lattner } 155e37d605eSJim Ingham return return_value; 15630fdc8d8SChris Lattner } 15730fdc8d8SChris Lattner 15830fdc8d8SChris Lattner size_t 15930fdc8d8SChris Lattner SourceManager::DisplaySourceLinesWithLineNumbers 16030fdc8d8SChris Lattner ( 16130fdc8d8SChris Lattner const FileSpec &file_spec, 16230fdc8d8SChris Lattner uint32_t line, 16330fdc8d8SChris Lattner uint32_t context_before, 16430fdc8d8SChris Lattner uint32_t context_after, 16530fdc8d8SChris Lattner const char* current_line_cstr, 166176761e5SGreg Clayton Stream *s, 167176761e5SGreg Clayton const SymbolContextList *bp_locs 16830fdc8d8SChris Lattner ) 16930fdc8d8SChris Lattner { 17030fdc8d8SChris Lattner bool same_as_previous = m_last_file_sp && m_last_file_sp->FileSpecMatches (file_spec); 17130fdc8d8SChris Lattner 17230fdc8d8SChris Lattner if (!same_as_previous) 173b7f6b2faSJim Ingham m_last_file_sp = GetFile (file_spec); 17430fdc8d8SChris Lattner 17530fdc8d8SChris Lattner if (line == 0) 17630fdc8d8SChris Lattner { 17730fdc8d8SChris Lattner if (!same_as_previous) 17830fdc8d8SChris Lattner m_last_file_line = 0; 17930fdc8d8SChris Lattner } 18030fdc8d8SChris Lattner 181176761e5SGreg Clayton return DisplaySourceLinesWithLineNumbersUsingLastFile (line, context_before, context_after, current_line_cstr, s, bp_locs); 18230fdc8d8SChris Lattner } 18330fdc8d8SChris Lattner 18430fdc8d8SChris Lattner size_t 185*196bbc25SJim Ingham SourceManager::DisplayMoreWithLineNumbers (Stream *s, const SymbolContextList *bp_locs, bool reverse) 18630fdc8d8SChris Lattner { 187*196bbc25SJim Ingham // If we get called before anybody has set a default file and line, then try to figure it out here. 188*196bbc25SJim Ingham if (!m_default_set) 189*196bbc25SJim Ingham { 190*196bbc25SJim Ingham FileSpec tmp_spec; 191*196bbc25SJim Ingham uint32_t tmp_line; 192*196bbc25SJim Ingham GetDefaultFileAndLine(tmp_spec, tmp_line); 193*196bbc25SJim Ingham } 194*196bbc25SJim Ingham 19530fdc8d8SChris Lattner if (m_last_file_sp) 19630fdc8d8SChris Lattner { 19730fdc8d8SChris Lattner if (m_last_file_line == UINT32_MAX) 19830fdc8d8SChris Lattner return 0; 199*196bbc25SJim Ingham 200*196bbc25SJim Ingham if (reverse && m_last_file_line == 1) 201*196bbc25SJim Ingham return 0; 202*196bbc25SJim Ingham 203*196bbc25SJim Ingham uint32_t line; 204*196bbc25SJim Ingham uint32_t new_last_file_line = 0; 205*196bbc25SJim Ingham 206*196bbc25SJim Ingham if (m_last_file_line != 0 207*196bbc25SJim Ingham && m_last_file_line != UINT32_MAX) 208*196bbc25SJim Ingham { 209*196bbc25SJim Ingham if (reverse) 210*196bbc25SJim Ingham { 211*196bbc25SJim Ingham // If this is the first time we've done a reverse, then back up one more time so we end 212*196bbc25SJim Ingham // up showing the chunk before the last one we've shown: 213*196bbc25SJim Ingham if (m_first_reverse) 214*196bbc25SJim Ingham { 215*196bbc25SJim Ingham if (m_last_file_line > m_last_file_context_after) 216*196bbc25SJim Ingham m_last_file_line -= m_last_file_context_after + 1; 217*196bbc25SJim Ingham } 218*196bbc25SJim Ingham 219*196bbc25SJim Ingham if (m_last_file_line > m_last_file_context_after) 220*196bbc25SJim Ingham { 221*196bbc25SJim Ingham line = m_last_file_line - m_last_file_context_after; 222*196bbc25SJim Ingham if (line > m_last_file_context_before) 223*196bbc25SJim Ingham new_last_file_line = line - m_last_file_context_before - 1; 224*196bbc25SJim Ingham else 225*196bbc25SJim Ingham new_last_file_line = 1; 226*196bbc25SJim Ingham } 227*196bbc25SJim Ingham else 228*196bbc25SJim Ingham { 229*196bbc25SJim Ingham line = 1; 230*196bbc25SJim Ingham new_last_file_line = 1; 231*196bbc25SJim Ingham } 232*196bbc25SJim Ingham } 233*196bbc25SJim Ingham else 234*196bbc25SJim Ingham line = m_last_file_line + m_last_file_context_before; 235*196bbc25SJim Ingham } 236*196bbc25SJim Ingham else 237*196bbc25SJim Ingham line = 1; 238*196bbc25SJim Ingham 239*196bbc25SJim Ingham size_t num_chars_shown = DisplaySourceLinesWithLineNumbersUsingLastFile (line, m_last_file_context_before, m_last_file_context_after, "", s, bp_locs); 240*196bbc25SJim Ingham if (new_last_file_line != 0) 241*196bbc25SJim Ingham m_last_file_line = new_last_file_line; 242*196bbc25SJim Ingham if (reverse) 243*196bbc25SJim Ingham m_first_reverse = false; 244*196bbc25SJim Ingham 245*196bbc25SJim Ingham return num_chars_shown; 24630fdc8d8SChris Lattner } 24730fdc8d8SChris Lattner return 0; 24830fdc8d8SChris Lattner } 24930fdc8d8SChris Lattner 250b7f6b2faSJim Ingham bool 251b7f6b2faSJim Ingham SourceManager::SetDefaultFileAndLine (const FileSpec &file_spec, uint32_t line) 252b7f6b2faSJim Ingham { 253b7f6b2faSJim Ingham FileSP old_file_sp = m_last_file_sp; 254b7f6b2faSJim Ingham m_last_file_sp = GetFile (file_spec); 255f3277750SJim Ingham 256f3277750SJim Ingham m_default_set = true; 257b7f6b2faSJim Ingham if (m_last_file_sp) 258b7f6b2faSJim Ingham { 259b7f6b2faSJim Ingham m_last_file_line = line; 260b7f6b2faSJim Ingham return true; 261b7f6b2faSJim Ingham } 262b7f6b2faSJim Ingham else 263b7f6b2faSJim Ingham { 264b7f6b2faSJim Ingham m_last_file_sp = old_file_sp; 265b7f6b2faSJim Ingham return false; 266b7f6b2faSJim Ingham } 267b7f6b2faSJim Ingham } 268b7f6b2faSJim Ingham 269b7f6b2faSJim Ingham bool 270b7f6b2faSJim Ingham SourceManager::GetDefaultFileAndLine (FileSpec &file_spec, uint32_t &line) 271b7f6b2faSJim Ingham { 272b7f6b2faSJim Ingham if (m_last_file_sp) 273b7f6b2faSJim Ingham { 274b7f6b2faSJim Ingham file_spec = m_last_file_sp->GetFileSpec(); 275b7f6b2faSJim Ingham line = m_last_file_line; 276b7f6b2faSJim Ingham return true; 277b7f6b2faSJim Ingham } 278f3277750SJim Ingham else if (!m_default_set) 279f3277750SJim Ingham { 280f3277750SJim Ingham // If nobody has set the default file and line then try here. If there's no executable, then we 281f3277750SJim Ingham // will try again later when there is one. Otherwise, if we can't find it we won't look again, 282f3277750SJim Ingham // somebody will have to set it (for instance when we stop somewhere...) 283f3277750SJim Ingham Module *executable_ptr = m_target->GetExecutableModulePointer(); 284f3277750SJim Ingham if (executable_ptr) 285f3277750SJim Ingham { 286f3277750SJim Ingham SymbolContextList sc_list; 287f3277750SJim Ingham uint32_t num_matches; 288f3277750SJim Ingham ConstString main_name("main"); 289f3277750SJim Ingham bool symbols_okay = false; // Force it to be a debug symbol. 2909df05fbbSSean Callanan bool inlines_okay = true; 291f3277750SJim Ingham bool append = false; 2929df05fbbSSean Callanan num_matches = executable_ptr->FindFunctions (main_name, NULL, lldb::eFunctionNameTypeBase, inlines_okay, symbols_okay, append, sc_list); 293f3277750SJim Ingham for (uint32_t idx = 0; idx < num_matches; idx++) 294f3277750SJim Ingham { 295f3277750SJim Ingham SymbolContext sc; 296f3277750SJim Ingham sc_list.GetContextAtIndex(idx, sc); 2976f6bf26aSGreg Clayton if (sc.function) 298f3277750SJim Ingham { 2996f6bf26aSGreg Clayton lldb_private::LineEntry line_entry; 3006f6bf26aSGreg Clayton if (sc.function->GetAddressRange().GetBaseAddress().CalculateSymbolContextLineEntry (line_entry)) 3016f6bf26aSGreg Clayton { 3026f6bf26aSGreg Clayton SetDefaultFileAndLine (line_entry.file, 3036f6bf26aSGreg Clayton line_entry.line); 3046f6bf26aSGreg Clayton file_spec = m_last_file_sp->GetFileSpec(); 3056f6bf26aSGreg Clayton line = m_last_file_line; 3066f6bf26aSGreg Clayton return true; 307f3277750SJim Ingham } 308f3277750SJim Ingham } 309f3277750SJim Ingham } 310f3277750SJim Ingham } 3116f6bf26aSGreg Clayton } 312b7f6b2faSJim Ingham return false; 313b7f6b2faSJim Ingham } 31430fdc8d8SChris Lattner 315969795f1SJim Ingham void 316969795f1SJim Ingham SourceManager::FindLinesMatchingRegex (FileSpec &file_spec, 317969795f1SJim Ingham RegularExpression& regex, 318969795f1SJim Ingham uint32_t start_line, 319969795f1SJim Ingham uint32_t end_line, 320969795f1SJim Ingham std::vector<uint32_t> &match_lines) 321969795f1SJim Ingham { 322969795f1SJim Ingham match_lines.clear(); 323969795f1SJim Ingham FileSP file_sp = GetFile (file_spec); 324969795f1SJim Ingham if (!file_sp) 325969795f1SJim Ingham return; 326969795f1SJim Ingham return file_sp->FindLinesMatchingRegex (regex, start_line, end_line, match_lines); 327969795f1SJim Ingham } 32830fdc8d8SChris Lattner 3297e14f91dSGreg Clayton SourceManager::File::File(const FileSpec &file_spec, Target *target) : 3307e14f91dSGreg Clayton m_file_spec_orig (file_spec), 33130fdc8d8SChris Lattner m_file_spec(file_spec), 3327e14f91dSGreg Clayton m_mod_time (file_spec.GetModificationTime()), 3337e14f91dSGreg Clayton m_data_sp(), 33430fdc8d8SChris Lattner m_offsets() 33530fdc8d8SChris Lattner { 3367e14f91dSGreg Clayton if (!m_mod_time.IsValid()) 3377e14f91dSGreg Clayton { 338e37d605eSJim Ingham if (target) 339e37d605eSJim Ingham { 340e37d605eSJim Ingham if (!file_spec.GetDirectory() && file_spec.GetFilename()) 341e37d605eSJim Ingham { 342e37d605eSJim Ingham // If this is just a file name, lets see if we can find it in the target: 343e37d605eSJim Ingham bool check_inlines = false; 344e37d605eSJim Ingham SymbolContextList sc_list; 345e37d605eSJim Ingham size_t num_matches = target->GetImages().ResolveSymbolContextForFilePath (file_spec.GetFilename().AsCString(), 346e37d605eSJim Ingham 0, 347e37d605eSJim Ingham check_inlines, 348e37d605eSJim Ingham lldb::eSymbolContextModule | lldb::eSymbolContextCompUnit, 349e37d605eSJim Ingham sc_list); 350e37d605eSJim Ingham bool got_multiple = false; 351e37d605eSJim Ingham if (num_matches != 0) 352e37d605eSJim Ingham { 353e37d605eSJim Ingham if (num_matches > 1) 354e37d605eSJim Ingham { 355e37d605eSJim Ingham SymbolContext sc; 356e37d605eSJim Ingham FileSpec *test_cu_spec = NULL; 357e37d605eSJim Ingham 358e37d605eSJim Ingham for (unsigned i = 0; i < num_matches; i++) 359e37d605eSJim Ingham { 360e37d605eSJim Ingham sc_list.GetContextAtIndex(i, sc); 361e37d605eSJim Ingham if (sc.comp_unit) 362e37d605eSJim Ingham { 363e37d605eSJim Ingham if (test_cu_spec) 364e37d605eSJim Ingham { 365e37d605eSJim Ingham if (test_cu_spec != static_cast<FileSpec *> (sc.comp_unit)) 366e37d605eSJim Ingham got_multiple = true; 367e37d605eSJim Ingham break; 368e37d605eSJim Ingham } 369e37d605eSJim Ingham else 370e37d605eSJim Ingham test_cu_spec = sc.comp_unit; 371e37d605eSJim Ingham } 372e37d605eSJim Ingham } 373e37d605eSJim Ingham } 374e37d605eSJim Ingham if (!got_multiple) 375e37d605eSJim Ingham { 376e37d605eSJim Ingham SymbolContext sc; 377e37d605eSJim Ingham sc_list.GetContextAtIndex (0, sc); 378d804d285SGreg Clayton m_file_spec = sc.comp_unit; 379e37d605eSJim Ingham m_mod_time = m_file_spec.GetModificationTime(); 380e37d605eSJim Ingham } 381e37d605eSJim Ingham } 382e37d605eSJim Ingham } 38364bab489SJohnny Chen // Try remapping if m_file_spec does not correspond to an existing file. 38464bab489SJohnny Chen if (!m_file_spec.Exists()) 385e37d605eSJim Ingham { 386d804d285SGreg Clayton FileSpec new_file_spec; 387d804d285SGreg Clayton // Check target specific source remappings first, then fall back to 388d804d285SGreg Clayton // modules objects can have individual path remappings that were detected 389d804d285SGreg Clayton // when the debug info for a module was found. 390d804d285SGreg Clayton // then 391d804d285SGreg Clayton if (target->GetSourcePathMap().FindFile (m_file_spec, new_file_spec) || 392d804d285SGreg Clayton target->GetImages().FindSourceFile (m_file_spec, new_file_spec)) 39364bab489SJohnny Chen { 394d804d285SGreg Clayton m_file_spec = new_file_spec; 39564bab489SJohnny Chen m_mod_time = m_file_spec.GetModificationTime(); 39664bab489SJohnny Chen } 3977e14f91dSGreg Clayton } 398e37d605eSJim Ingham } 399e37d605eSJim Ingham } 4007e14f91dSGreg Clayton 4017e14f91dSGreg Clayton if (m_mod_time.IsValid()) 4027e14f91dSGreg Clayton m_data_sp = m_file_spec.ReadFileContents (); 40330fdc8d8SChris Lattner } 40430fdc8d8SChris Lattner 40530fdc8d8SChris Lattner SourceManager::File::~File() 40630fdc8d8SChris Lattner { 40730fdc8d8SChris Lattner } 40830fdc8d8SChris Lattner 40930fdc8d8SChris Lattner uint32_t 41030fdc8d8SChris Lattner SourceManager::File::GetLineOffset (uint32_t line) 41130fdc8d8SChris Lattner { 41230fdc8d8SChris Lattner if (line == 0) 41330fdc8d8SChris Lattner return UINT32_MAX; 41430fdc8d8SChris Lattner 41530fdc8d8SChris Lattner if (line == 1) 41630fdc8d8SChris Lattner return 0; 41730fdc8d8SChris Lattner 41830fdc8d8SChris Lattner if (CalculateLineOffsets (line)) 41930fdc8d8SChris Lattner { 42030fdc8d8SChris Lattner if (line < m_offsets.size()) 42130fdc8d8SChris Lattner return m_offsets[line - 1]; // yes we want "line - 1" in the index 42230fdc8d8SChris Lattner } 42330fdc8d8SChris Lattner return UINT32_MAX; 42430fdc8d8SChris Lattner } 42530fdc8d8SChris Lattner 42630fdc8d8SChris Lattner bool 42730fdc8d8SChris Lattner SourceManager::File::LineIsValid (uint32_t line) 42830fdc8d8SChris Lattner { 42930fdc8d8SChris Lattner if (line == 0) 43030fdc8d8SChris Lattner return false; 43130fdc8d8SChris Lattner 43230fdc8d8SChris Lattner if (CalculateLineOffsets (line)) 43330fdc8d8SChris Lattner return line < m_offsets.size(); 43430fdc8d8SChris Lattner return false; 43530fdc8d8SChris Lattner } 43630fdc8d8SChris Lattner 43730fdc8d8SChris Lattner size_t 43830fdc8d8SChris Lattner SourceManager::File::DisplaySourceLines (uint32_t line, uint32_t context_before, uint32_t context_after, Stream *s) 43930fdc8d8SChris Lattner { 4409625d08cSGreg Clayton // TODO: use host API to sign up for file modifications to anything in our 4419625d08cSGreg Clayton // source cache and only update when we determine a file has been updated. 4429625d08cSGreg Clayton // For now we check each time we want to display info for the file. 4439625d08cSGreg Clayton TimeValue curr_mod_time (m_file_spec.GetModificationTime()); 44464bab489SJohnny Chen 44564bab489SJohnny Chen if (curr_mod_time.IsValid() && m_mod_time != curr_mod_time) 4469625d08cSGreg Clayton { 4479625d08cSGreg Clayton m_mod_time = curr_mod_time; 4489625d08cSGreg Clayton m_data_sp = m_file_spec.ReadFileContents (); 4499625d08cSGreg Clayton m_offsets.clear(); 4509625d08cSGreg Clayton } 4519625d08cSGreg Clayton 45264bab489SJohnny Chen // Sanity check m_data_sp before proceeding. 45364bab489SJohnny Chen if (!m_data_sp) 45464bab489SJohnny Chen return 0; 45564bab489SJohnny Chen 45630fdc8d8SChris Lattner const uint32_t start_line = line <= context_before ? 1 : line - context_before; 45730fdc8d8SChris Lattner const uint32_t start_line_offset = GetLineOffset (start_line); 45830fdc8d8SChris Lattner if (start_line_offset != UINT32_MAX) 45930fdc8d8SChris Lattner { 46030fdc8d8SChris Lattner const uint32_t end_line = line + context_after; 46130fdc8d8SChris Lattner uint32_t end_line_offset = GetLineOffset (end_line + 1); 46230fdc8d8SChris Lattner if (end_line_offset == UINT32_MAX) 46330fdc8d8SChris Lattner end_line_offset = m_data_sp->GetByteSize(); 46430fdc8d8SChris Lattner 46530fdc8d8SChris Lattner assert (start_line_offset <= end_line_offset); 46630fdc8d8SChris Lattner size_t bytes_written = 0; 46730fdc8d8SChris Lattner if (start_line_offset < end_line_offset) 46830fdc8d8SChris Lattner { 46930fdc8d8SChris Lattner size_t count = end_line_offset - start_line_offset; 47030fdc8d8SChris Lattner const uint8_t *cstr = m_data_sp->GetBytes() + start_line_offset; 47130fdc8d8SChris Lattner bytes_written = s->Write(cstr, count); 47230fdc8d8SChris Lattner if (!is_newline_char(cstr[count-1])) 47330fdc8d8SChris Lattner bytes_written += s->EOL(); 47430fdc8d8SChris Lattner } 47530fdc8d8SChris Lattner return bytes_written; 47630fdc8d8SChris Lattner } 47730fdc8d8SChris Lattner return 0; 47830fdc8d8SChris Lattner } 47930fdc8d8SChris Lattner 480969795f1SJim Ingham void 481969795f1SJim Ingham SourceManager::File::FindLinesMatchingRegex (RegularExpression& regex, uint32_t start_line, uint32_t end_line, std::vector<uint32_t> &match_lines) 482969795f1SJim Ingham { 483969795f1SJim Ingham TimeValue curr_mod_time (m_file_spec.GetModificationTime()); 484969795f1SJim Ingham if (m_mod_time != curr_mod_time) 485969795f1SJim Ingham { 486969795f1SJim Ingham m_mod_time = curr_mod_time; 487969795f1SJim Ingham m_data_sp = m_file_spec.ReadFileContents (); 488969795f1SJim Ingham m_offsets.clear(); 489969795f1SJim Ingham } 490969795f1SJim Ingham 491969795f1SJim Ingham match_lines.clear(); 492969795f1SJim Ingham 493969795f1SJim Ingham if (!LineIsValid(start_line) || (end_line != UINT32_MAX && !LineIsValid(end_line))) 494969795f1SJim Ingham return; 495969795f1SJim Ingham if (start_line > end_line) 496969795f1SJim Ingham return; 497969795f1SJim Ingham 498969795f1SJim Ingham for (uint32_t line_no = start_line; line_no < end_line; line_no++) 499969795f1SJim Ingham { 500969795f1SJim Ingham std::string buffer; 501969795f1SJim Ingham if (!GetLine (line_no, buffer)) 502969795f1SJim Ingham break; 503969795f1SJim Ingham if (regex.Execute(buffer.c_str())) 504969795f1SJim Ingham { 505969795f1SJim Ingham match_lines.push_back(line_no); 506969795f1SJim Ingham } 507969795f1SJim Ingham } 508969795f1SJim Ingham } 509969795f1SJim Ingham 51030fdc8d8SChris Lattner bool 51130fdc8d8SChris Lattner SourceManager::File::FileSpecMatches (const FileSpec &file_spec) 51230fdc8d8SChris Lattner { 513644247c1SGreg Clayton return FileSpec::Equal (m_file_spec, file_spec, false); 51430fdc8d8SChris Lattner } 51530fdc8d8SChris Lattner 516e37d605eSJim Ingham bool 517e37d605eSJim Ingham lldb_private::operator== (const SourceManager::File &lhs, const SourceManager::File &rhs) 518e37d605eSJim Ingham { 519e37d605eSJim Ingham if (lhs.m_file_spec == rhs.m_file_spec) 520e37d605eSJim Ingham { 521e37d605eSJim Ingham if (lhs.m_mod_time.IsValid()) 522e37d605eSJim Ingham { 523e37d605eSJim Ingham if (rhs.m_mod_time.IsValid()) 524e37d605eSJim Ingham return lhs.m_mod_time == rhs.m_mod_time; 525e37d605eSJim Ingham else 526e37d605eSJim Ingham return false; 527e37d605eSJim Ingham } 528e37d605eSJim Ingham else if (rhs.m_mod_time.IsValid()) 529e37d605eSJim Ingham return false; 530e37d605eSJim Ingham else 531e37d605eSJim Ingham return true; 532e37d605eSJim Ingham } 533e37d605eSJim Ingham else 534e37d605eSJim Ingham return false; 535e37d605eSJim Ingham } 53630fdc8d8SChris Lattner 53730fdc8d8SChris Lattner bool 53830fdc8d8SChris Lattner SourceManager::File::CalculateLineOffsets (uint32_t line) 53930fdc8d8SChris Lattner { 54030fdc8d8SChris Lattner line = UINT32_MAX; // TODO: take this line out when we support partial indexing 54130fdc8d8SChris Lattner if (line == UINT32_MAX) 54230fdc8d8SChris Lattner { 54330fdc8d8SChris Lattner // Already done? 54430fdc8d8SChris Lattner if (!m_offsets.empty() && m_offsets[0] == UINT32_MAX) 54530fdc8d8SChris Lattner return true; 54630fdc8d8SChris Lattner 54730fdc8d8SChris Lattner if (m_offsets.empty()) 54830fdc8d8SChris Lattner { 54930fdc8d8SChris Lattner if (m_data_sp.get() == NULL) 55030fdc8d8SChris Lattner return false; 55130fdc8d8SChris Lattner 55230fdc8d8SChris Lattner const char *start = (char *)m_data_sp->GetBytes(); 55330fdc8d8SChris Lattner if (start) 55430fdc8d8SChris Lattner { 55530fdc8d8SChris Lattner const char *end = start + m_data_sp->GetByteSize(); 55630fdc8d8SChris Lattner 55730fdc8d8SChris Lattner // Calculate all line offsets from scratch 55830fdc8d8SChris Lattner 55930fdc8d8SChris Lattner // Push a 1 at index zero to indicate the file has been completely indexed. 56030fdc8d8SChris Lattner m_offsets.push_back(UINT32_MAX); 56130fdc8d8SChris Lattner register const char *s; 56230fdc8d8SChris Lattner for (s = start; s < end; ++s) 56330fdc8d8SChris Lattner { 56430fdc8d8SChris Lattner register char curr_ch = *s; 56530fdc8d8SChris Lattner if (is_newline_char (curr_ch)) 56630fdc8d8SChris Lattner { 56730fdc8d8SChris Lattner register char next_ch = s[1]; 56830fdc8d8SChris Lattner if (is_newline_char (next_ch)) 56930fdc8d8SChris Lattner { 57030fdc8d8SChris Lattner if (curr_ch != next_ch) 57130fdc8d8SChris Lattner ++s; 57230fdc8d8SChris Lattner } 57330fdc8d8SChris Lattner m_offsets.push_back(s + 1 - start); 57430fdc8d8SChris Lattner } 57530fdc8d8SChris Lattner } 57630fdc8d8SChris Lattner if (!m_offsets.empty()) 57730fdc8d8SChris Lattner { 57830fdc8d8SChris Lattner if (m_offsets.back() < end - start) 57930fdc8d8SChris Lattner m_offsets.push_back(end - start); 58030fdc8d8SChris Lattner } 58130fdc8d8SChris Lattner return true; 58230fdc8d8SChris Lattner } 58330fdc8d8SChris Lattner } 58430fdc8d8SChris Lattner else 58530fdc8d8SChris Lattner { 58630fdc8d8SChris Lattner // Some lines have been populated, start where we last left off 58730fdc8d8SChris Lattner assert(!"Not implemented yet"); 58830fdc8d8SChris Lattner } 58930fdc8d8SChris Lattner 59030fdc8d8SChris Lattner } 59130fdc8d8SChris Lattner else 59230fdc8d8SChris Lattner { 59330fdc8d8SChris Lattner // Calculate all line offsets up to "line" 59430fdc8d8SChris Lattner assert(!"Not implemented yet"); 59530fdc8d8SChris Lattner } 59630fdc8d8SChris Lattner return false; 59730fdc8d8SChris Lattner } 598e37d605eSJim Ingham 599969795f1SJim Ingham bool 600969795f1SJim Ingham SourceManager::File::GetLine (uint32_t line_no, std::string &buffer) 601969795f1SJim Ingham { 602969795f1SJim Ingham if (!LineIsValid(line_no)) 603969795f1SJim Ingham return false; 604969795f1SJim Ingham 605969795f1SJim Ingham uint32_t start_offset = GetLineOffset (line_no); 606969795f1SJim Ingham uint32_t end_offset = GetLineOffset (line_no + 1); 607969795f1SJim Ingham if (end_offset == UINT32_MAX) 608969795f1SJim Ingham { 609969795f1SJim Ingham end_offset = m_data_sp->GetByteSize(); 610969795f1SJim Ingham } 611969795f1SJim Ingham buffer.assign((char *) m_data_sp->GetBytes() + start_offset, end_offset - start_offset); 612969795f1SJim Ingham 613969795f1SJim Ingham return true; 614969795f1SJim Ingham } 615969795f1SJim Ingham 616e37d605eSJim Ingham void 617e37d605eSJim Ingham SourceManager::SourceFileCache::AddSourceFile (const FileSP &file_sp) 618e37d605eSJim Ingham { 619e37d605eSJim Ingham FileSpec file_spec; 620e37d605eSJim Ingham FileCache::iterator pos = m_file_cache.find(file_spec); 621e37d605eSJim Ingham if (pos == m_file_cache.end()) 622e37d605eSJim Ingham m_file_cache[file_spec] = file_sp; 623e37d605eSJim Ingham else 624e37d605eSJim Ingham { 625e37d605eSJim Ingham if (file_sp != pos->second) 626e37d605eSJim Ingham m_file_cache[file_spec] = file_sp; 627e37d605eSJim Ingham } 628e37d605eSJim Ingham } 629e37d605eSJim Ingham 630e37d605eSJim Ingham SourceManager::FileSP 631e37d605eSJim Ingham SourceManager::SourceFileCache::FindSourceFile (const FileSpec &file_spec) const 632e37d605eSJim Ingham { 633e37d605eSJim Ingham FileSP file_sp; 634e37d605eSJim Ingham FileCache::const_iterator pos = m_file_cache.find(file_spec); 635e37d605eSJim Ingham if (pos != m_file_cache.end()) 636e37d605eSJim Ingham file_sp = pos->second; 637e37d605eSJim Ingham return file_sp; 638e37d605eSJim Ingham } 639e37d605eSJim Ingham 640