dawn created this revision.
dawn added reviewers: clayborg, ki.stfu, abidh.
dawn added a subscriber: lldb-commits.
dawn set the repository for this revision to rL LLVM.

This adds support for the new command:
    target modules dump line-entries <file>
which dumps the line entries found for 'file' for all CUs in all modules.
This command is used to fix the MI command:
    -symbol-list-lines <file>
which didn't work for header files because it called:
    target modules dump line-table <file>
which only dumps line tables for a compilation unit.

Repository:
  rL LLVM

http://reviews.llvm.org/D15593

Files:
  packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py
  
packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h
  source/Commands/CommandObjectTarget.cpp
  tools/lldb-mi/MICmdCmdSymbol.cpp

Index: tools/lldb-mi/MICmdCmdSymbol.cpp
===================================================================
--- tools/lldb-mi/MICmdCmdSymbol.cpp
+++ tools/lldb-mi/MICmdCmdSymbol.cpp
@@ -82,11 +82,7 @@
     CMICMDBASE_GETOPTION(pArgFile, File, m_constStrArgNameFile);
 
     const CMIUtilString &strFilePath(pArgFile->GetValue());
-    // FIXME: this won't work for header files!  To try and use existing
-    // commands to get this to work for header files would be too slow.
-    // Instead, this code should be rewritten to use APIs and/or support
-    // should be added to lldb which would work for header files.
-    const CMIUtilString strCmd(CMIUtilString::Format("target modules dump line-table \"%s\"", strFilePath.AddSlashes().c_str()));
+    const CMIUtilString strCmd(CMIUtilString::Format("target modules dump line-entries \"%s\"", strFilePath.AddSlashes().c_str()));
 
     CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance());
     const lldb::ReturnStatus rtn = rSessionInfo.GetDebugger().GetCommandInterpreter().HandleCommand(strCmd.c_str(), m_lldbResult);
@@ -110,10 +106,10 @@
 {
     // Match LineEntry using regex.
     static MIUtilParse::CRegexParser g_lineentry_header_regex( 
-        "^ *Line table for (.+) in `(.+)$");
-        //                 ^1=file  ^2=module
+        "^ *Lines for file (.+) in compilation unit (.+) in `(.+)$");
+        //                 ^1=file                  ^2=cu    ^3=module
 
-    MIUtilParse::CRegexParser::Match match(3);
+    MIUtilParse::CRegexParser::Match match(4);
 
     const bool ok = g_lineentry_header_regex.Execute(input, match);
     if (ok)
@@ -146,12 +142,12 @@
 
     // Match LineEntry using regex.
     static MIUtilParse::CRegexParser g_lineentry_nocol_regex( 
-        "^ *(0x[0-9a-fA-F]+): (.+):([0-9]+)$");
+        "^ *\\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+)$");
     static MIUtilParse::CRegexParser g_lineentry_col_regex( 
-        "^ *(0x[0-9a-fA-F]+): (.+):([0-9]+):[0-9]+$");
-        //  ^1=addr           ^2=f ^3=line ^4=:col(opt)
+        "^ *\\[(0x[0-9a-fA-F]+)-(0x[0-9a-fA-F]+)\\): (.+):([0-9]+):[0-9]+$");
+        //     ^1=start         ^2=end               ^3=f ^4=line ^5=:col(opt)
 
-    MIUtilParse::CRegexParser::Match match(5);
+    MIUtilParse::CRegexParser::Match match(6);
 
     // First try matching the LineEntry with the column,
     // then try without the column.
@@ -160,8 +156,8 @@
     if (ok)
     {
         addr = match.GetMatchAtIndex(1);
-        file = match.GetMatchAtIndex(2);
-        line = match.GetMatchAtIndex(3);
+        file = match.GetMatchAtIndex(3);
+        line = match.GetMatchAtIndex(4);
     }
     return ok;
 }
@@ -222,10 +218,6 @@
             if (!ParseLLDBLineAddressEntry(rLine.c_str(), strAddr, strFile, strLine))
                 continue;
 
-            // Skip entries which don't match the desired source.
-            if (strWantFile != strFile)
-                continue;
-
             const CMICmnMIValueConst miValueConst(strAddr);
             const CMICmnMIValueResult miValueResult("pc", miValueConst);
             CMICmnMIValueTuple miValueTuple(miValueResult);
Index: source/Commands/CommandObjectTarget.cpp
===================================================================
--- source/Commands/CommandObjectTarget.cpp
+++ source/Commands/CommandObjectTarget.cpp
@@ -1524,6 +1524,91 @@
     return num_matches;
 }
 
+static uint32_t
+DumpFileLineEntries (CommandInterpreter &interpreter,
+                     Stream &strm,
+                     Module *module,
+                     const FileSpec &file_spec,
+                     bool load_addresses)
+{
+    uint32_t num_matches = 0;
+    if (module)
+    {
+        // Look through all the compilation units (CUs) for ones that contain
+        // lines of code from this source file.
+        assert(file_spec.GetFilename().AsCString());
+        bool has_path = (file_spec.GetDirectory().AsCString() != 0);
+        int ncus = module->GetNumCompileUnits();
+        for (int i = 0; i < ncus; i++)
+        {
+            // Look for a matching source file in this CU.
+            CompUnitSP cu_sp(module->GetCompileUnitAtIndex(i));
+            if (!cu_sp)
+                continue;
+            CompileUnit *cu = cu_sp.get();
+            const FileSpecList &cu_file_list = cu->GetSupportFiles();
+            size_t file_idx = cu_file_list.FindFileIndex(0, file_spec, has_path);
+            if (file_idx == UINT32_MAX)
+                // No such file in this CU.
+                continue;
+
+            // Update the file to how it appears in the CU.
+            const FileSpec &cu_file_spec = cu_file_list.GetFileSpecAtIndex(file_idx);
+
+            // Dump all the line entries for the file in the CU.
+            const ConstString &file_spec_name = file_spec.GetFilename();
+            const ConstString &module_file_name = module->GetFileSpec().GetFilename();
+            uint32_t line = 0;
+            bool cu_header_printed = false;
+            while (true)
+            {
+                LineEntry line_entry;
+
+                // Find the lowest index of a line entry with a line equal to
+                // or higher than 'line'.
+                uint32_t start_idx = 0;
+                start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
+                                              /*exact=*/false, &line_entry);
+                if (start_idx == UINT32_MAX)
+                    // No more line entries for our file in this CU.
+                    break;
+
+                // Loop through to find any other entries for this line, dumping each.
+                line = line_entry.line;
+                do
+                {
+                    assert(lldb_private::FileSpec::Equal(cu_file_spec, line_entry.file, has_path));
+                    if (cu_header_printed == false)
+                    {
+                        if (num_matches > 0)
+                            strm << "\n\n";
+                        strm << "Lines for file " << file_spec_name
+                             << " in compilation unit " << cu->GetFilename()
+                             << " in `" << module_file_name << "\n";
+                        cu_header_printed = true;
+                    }
+                    line_entry.GetDescription(&strm,
+                                              lldb::eDescriptionLevelBrief,
+                                              cu,
+                                              interpreter.GetExecutionContext().GetTargetPtr(),
+                                              /*show_address_only=*/false);
+                    strm << "\n";
+                    num_matches++;
+
+                    // Anymore after this one?
+                    start_idx++;
+                    start_idx = cu->FindLineEntry(start_idx, line, &cu_file_spec,
+                                                  /*exact=*/true, &line_entry);
+                } while (start_idx != UINT32_MAX);
+
+                // Try the next higher line, starting over at start_idx 0.
+                line++;
+            }
+        }
+    }
+    return num_matches;
+}
+
 static void
 DumpFullpath (Stream &strm, const FileSpec *file_spec_ptr, uint32_t width)
 {
@@ -2622,6 +2707,80 @@
     }
 };
 
+class CommandObjectTargetModulesDumpLineEntries : public CommandObjectTargetModulesSourceFileAutoComplete
+{
+public:
+    CommandObjectTargetModulesDumpLineEntries (CommandInterpreter &interpreter) :
+    CommandObjectTargetModulesSourceFileAutoComplete (interpreter,
+                                                      "target modules dump line-entries",
+                                                      "Dump the line entries for one or more files.",
+                                                      NULL,
+                                                      eCommandRequiresTarget)
+    {
+    }
+
+    ~CommandObjectTargetModulesDumpLineEntries () override
+    {
+    }
+
+protected:
+    bool
+    DoExecute (Args& command, CommandReturnObject &result) override
+    {
+        Target *target = m_exe_ctx.GetTargetPtr();
+        uint32_t total_num_dumped = 0;
+
+        uint32_t addr_byte_size = target->GetArchitecture().GetAddressByteSize();
+        result.GetOutputStream().SetAddressByteSize(addr_byte_size);
+        result.GetErrorStream().SetAddressByteSize(addr_byte_size);
+
+        if (command.GetArgumentCount() == 0)
+        {
+            result.AppendErrorWithFormat ("\nSyntax: %s\n", m_cmd_syntax.c_str());
+            result.SetStatus (eReturnStatusFailed);
+        }
+        else
+        {
+            // Dump specified images (by basename or fullpath)
+            const char *arg_cstr;
+            for (int arg_idx = 0; (arg_cstr = command.GetArgumentAtIndex(arg_idx)) != NULL; ++arg_idx)
+            {
+                FileSpec file_spec(arg_cstr, false);
+
+                const ModuleList &target_modules = target->GetImages();
+                Mutex::Locker modules_locker(target_modules.GetMutex());
+                const size_t num_modules = target_modules.GetSize();
+                if (num_modules > 0)
+                {
+                    uint32_t num_dumped = 0;
+                    for (uint32_t i = 0; i<num_modules; ++i)
+                    {
+                        if (DumpFileLineEntries (m_interpreter,
+                                                 result.GetOutputStream(),
+                                                 target_modules.GetModulePointerAtIndexUnlocked(i),
+                                                 file_spec,
+                                                 m_exe_ctx.GetProcessPtr() && m_exe_ctx.GetProcessRef().IsAlive()))
+                            num_dumped++;
+                    }
+                    if (num_dumped == 0)
+                        result.AppendWarningWithFormat ("No source filenames matched '%s'.\n", arg_cstr);
+                    else
+                        total_num_dumped += num_dumped;
+                }
+            }
+        }
+
+        if (total_num_dumped > 0)
+            result.SetStatus (eReturnStatusSuccessFinishResult);
+        else
+        {
+            result.AppendError ("no source filenames matched any command arguments");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+};
+
 
 #pragma mark CommandObjectTargetModulesDump
 
@@ -2645,6 +2804,7 @@
         LoadSubCommand ("sections",    CommandObjectSP (new CommandObjectTargetModulesDumpSections (interpreter)));
         LoadSubCommand ("symfile",     CommandObjectSP (new CommandObjectTargetModulesDumpSymfile (interpreter)));
         LoadSubCommand ("line-table",  CommandObjectSP (new CommandObjectTargetModulesDumpLineTable (interpreter)));
+        LoadSubCommand ("line-entries", CommandObjectSP (new CommandObjectTargetModulesDumpLineEntries (interpreter)));
     }
 
     ~CommandObjectTargetModulesDump() override
Index: packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h
===================================================================
--- packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h
+++ packages/Python/lldbsuite/test/tools/lldb-mi/symbol/symbol_list_lines_inline_test.h
@@ -2,7 +2,7 @@
 {
 inline int
 ifunc(int i)
-{
+{ // FUNC_ifunc
     return i;
 }
 struct S
@@ -17,7 +17,7 @@
     int
     mfunc()
     {
-        return a + b;
+        return a + b; // FUNC_mfunc
     }
 };
 extern S s;
Index: packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py
===================================================================
--- packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py
+++ packages/Python/lldbsuite/test/tools/lldb-mi/symbol/TestMiSymbol.py
@@ -48,12 +48,19 @@
         eline = line_number('symbol_list_lines_inline_test2.cpp', '// END_gfunc2')
         self.runCmd("-symbol-list-lines symbol_list_lines_inline_test2.cpp")
         self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*\]" % (sline, eline))
-        ##FIXME: This doesn't work for symbol_list_lines_inline_test.cpp due to clang bug llvm.org/pr24716
+        ##FIXME: This doesn't work for symbol_list_lines_inline_test.cpp due to clang bug llvm.org/pr24716 (fixed in newer versions of clang)
         ##sline = line_number('symbol_list_lines_inline_test.cpp', '// FUNC_gfunc')
         ##eline = line_number('symbol_list_lines_inline_test.cpp', '// STRUCT_s')
         ##self.runCmd("-symbol-list-lines symbol_list_lines_inline_test.cpp")
         ##self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"3\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}\]" % (sline, eline))
 
+        # Test that -symbol-list-lines works on header files by checking the first
+        # and last line, and making sure the other lines are under 29.
+        sline = line_number('symbol_list_lines_inline_test.h', '// FUNC_ifunc')
+        eline = line_number('symbol_list_lines_inline_test.h', '// FUNC_mfunc')
+        self.runCmd("-symbol-list-lines symbol_list_lines_inline_test.h")
+        self.expect("\^done,lines=\[\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"\d\"\})*(,\{pc=\"0x[0-9a-f]+\",line=\"1\d\"\})*,\{pc=\"0x[0-9a-f]+\",line=\"%d\"\}(,\{pc=\"0x[0-9a-f]+\",line=\"2\d\"\})*\]" % (sline, eline))
+
         # Test that -symbol-list-lines fails when file doesn't exist
         self.runCmd("-symbol-list-lines unknown_file")
         self.expect("\^error,message=\"warning: No source filenames matched 'unknown_file'\. error: no source filenames matched any command arguments \"")
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to