Index: test/tools/lldb-mi/TestMiLibraryLoaded.py =================================================================== --- /dev/null +++ test/tools/lldb-mi/TestMiLibraryLoaded.py @@ -0,0 +1,33 @@ +""" +Test lldb-mi =library-loaded notifications. +""" + +import lldbmi_testcase +from lldbtest import * +import unittest2 + +class MiLibraryLoadedTestCase(lldbmi_testcase.MiTestCaseBase): + + mydir = TestBase.compute_mydir(__file__) + + @lldbmi_test + @expectedFailureWindows("llvm.org/pr22274: need a pexpect replacement for windows") + @skipIfFreeBSD # llvm.org/pr22411: Failure presumably due to known thread races + def test_lldbmi_library_loaded(self): + """Test that 'lldb-mi --interpreter' shows the =library-loaded notifications.""" + + self.spawnLldbMi(args = None) + + # Load executable + self.runCmd("-file-exec-and-symbols %s" % self.myexe) + self.expect("\^done") + + # Test =library-loaded + import os + path = os.path.join(os.getcwd(), self.myexe) + symbols_path = os.path.join(path + ".dSYM", "Contents", "Resources", "DWARF", self.myexe) + self.expect("=library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded=\"1\",symbols-path=\"%s\",loaded_addr=\"-\"" % (path, path, path, symbols_path), + exactly = True) + +if __name__ == '__main__': + unittest2.main() Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h =================================================================== --- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h +++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.h @@ -71,8 +71,8 @@ bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent); bool HandleTargetEventBroadcastBitModulesLoaded(const lldb::SBEvent &vEvent); bool HandleTargetEventBroadcastBitModulesUnloaded(const lldb::SBEvent &vEvent); - bool MiHelpGetModuleInfo(const lldb::SBModule &vModule, const MIuint nModuleNum, - CMICmnMIValueList &vwrMiValueList); + bool MiHelpGetModuleInfo(const lldb::SBModule &vModule, const bool vbWithExtraFields, + CMICmnMIOutOfBandRecord &vwrMiOutOfBandRecord); bool MiHelpGetCurrentThreadFrame(CMICmnMIValueTuple &vwrMiValueTuple); bool MiResultRecordToStdout(const CMICmnMIResultRecord &vrMiResultRecord); bool MiOutOfBandRecordToStdout(const CMICmnMIOutOfBandRecord &vrMiResultRecord); Index: tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp =================================================================== --- tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp +++ tools/lldb-mi/MICmnLLDBDebuggerHandleEvents.cpp @@ -618,114 +618,118 @@ } //++ ------------------------------------------------------------------------------------ -// Details: Print to stdout "=shlibs-added,shlib-info=[key=\"value\"...]" +// Details: Print to stdout "=library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" PRIx64"\"" // Type: Method. // Args: None. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. +// Return: MIstatus::success - Function succeeded. +// MIstatus::failure - Function failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleTargetEventBroadcastBitModulesLoaded(const lldb::SBEvent &vEvent) { - static MIuint s_nModulesLoadedNumber(0); - const MIuint nSize(lldb::SBTarget::GetNumModulesFromEvent(vEvent)); - bool bOk = MIstatus::success; - for (MIuint nIndex(0); bOk && (nIndex < nSize); ++nIndex) + bool bOk = MIstatus::failure; + const MIuint nSize = lldb::SBTarget::GetNumModulesFromEvent(vEvent); + for (MIuint nIndex = 0; nIndex < nSize; ++nIndex) { const lldb::SBModule sbModule = lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent); - CMICmnMIValueList miValueList(true); - bOk = MiHelpGetModuleInfo(sbModule, ++s_nModulesLoadedNumber, miValueList); - const CMICmnMIValueResult miValueResult("shlib-info", miValueList); - const CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesLoaded, miValueResult); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleLoaded); + const bool bWithExtraFields = true; // Build extra fields like symbols-loaded/symbols-path and loaded_addr + bOk = MiHelpGetModuleInfo(sbModule, bWithExtraFields, miOutOfBandRecord); bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); + if (!bOk) + break; } return bOk; } //++ ------------------------------------------------------------------------------------ -// Details: Print to stdout "=shlibs-removed,shlib-info=[key=\"value\"...]" +// Details: Print to stdout "=library-unloaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" PRIx64"\"" // Type: Method. // Args: None. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. +// Return: MIstatus::success - Function succeeded. +// MIstatus::failure - Function failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleTargetEventBroadcastBitModulesUnloaded(const lldb::SBEvent &vEvent) { - static MIuint s_nModulesUnloadedNumber(0); - const MIuint nSize(lldb::SBTarget::GetNumModulesFromEvent(vEvent)); - bool bOk = MIstatus::success; - for (MIuint nIndex(0); bOk && (nIndex < nSize); ++nIndex) + bool bOk = MIstatus::failure; + const MIuint nSize = lldb::SBTarget::GetNumModulesFromEvent(vEvent); + for (MIuint nIndex = 0; nIndex < nSize; ++nIndex) { const lldb::SBModule sbModule = lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent); - CMICmnMIValueList miValueList(true); - bOk = MiHelpGetModuleInfo(sbModule, ++s_nModulesUnloadedNumber, miValueList); - const CMICmnMIValueResult miValueResult("shlib-info", miValueList); - const CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesUnloaded, miValueResult); + CMICmnMIOutOfBandRecord miOutOfBandRecord(CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleUnloaded); + const bool bWithExtraFields = false; // Skip extra fields like symbols-loaded/symbols-path and loaded_addr + bOk = MiHelpGetModuleInfo(sbModule, bWithExtraFields, miOutOfBandRecord); bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); + if (!bOk) + break; } return bOk; } //++ ------------------------------------------------------------------------------------ -// Details: Build module information for shlib-info "[num=\"%ld\",name=\"%s\",dyld-addr=\"%#lx\",reason=\"dyld\",path=\"%s\",loaded_addr=\"%#lx\",dsym-objpath=\"%s\"]" +// Details: Build module information for =library-loaded/=library-unloaded: "id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" PRIx64"\"" // Type: Method. // Args: vwrMiValueList - (W) MI value list object. -// Return: MIstatus::success - Functional succeeded. -// MIstatus::failure - Functional failed. +// Return: MIstatus::success - Function succeeded. +// MIstatus::failure - Function failed. // Throws: None. //-- bool -CMICmnLLDBDebuggerHandleEvents::MiHelpGetModuleInfo(const lldb::SBModule &vModule, const MIuint nModuleNum, - CMICmnMIValueList &vwrMiValueList) +CMICmnLLDBDebuggerHandleEvents::MiHelpGetModuleInfo(const lldb::SBModule &vModule, const bool vbWithExtraFields, + CMICmnMIOutOfBandRecord &vwrMiOutOfBandRecord) { bool bOk = MIstatus::success; - // Build "num" field - const CMIUtilString strNum(CMIUtilString::Format("%ld", nModuleNum)); - const CMICmnMIValueConst miValueConst(strNum); - const CMICmnMIValueResult miValueResult("num", miValueConst); - bOk = bOk && vwrMiValueList.Add(miValueResult); - // Build "name" field - const CMICmnMIValueConst miValueConst2(vModule.GetPlatformFileSpec().GetFilename()); - const CMICmnMIValueResult miValueResult2("name", miValueConst2); - bOk = bOk && vwrMiValueList.Add(miValueResult2); - // Build "dyld-addr" field - const lldb::SBAddress sbAddress(vModule.GetObjectFileHeaderAddress()); - const CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); - const lldb::addr_t nLoadAddress(sbAddress.GetLoadAddress(rSessionInfo.GetTarget())); - const CMIUtilString strDyldAddr(CMIUtilString::Format("%#lx", nLoadAddress)); - const CMICmnMIValueConst miValueConst3(nLoadAddress != LLDB_INVALID_ADDRESS ? strDyldAddr : "-"); - const CMICmnMIValueResult miValueResult3("dyld-addr", miValueConst3); - bOk = bOk && vwrMiValueList.Add(miValueResult3); - // Build "reason" field - const CMICmnMIValueConst miValueConst4("dyld"); - const CMICmnMIValueResult miValueResult4("reason", miValueConst4); - bOk = bOk && vwrMiValueList.Add(miValueResult4); - // Build "path" field - char path[PATH_MAX]; - vModule.GetPlatformFileSpec().GetPath(path, sizeof(path)); - const CMIUtilString strPlatformPath(path); - const CMICmnMIValueConst miValueConst5(strPlatformPath); - const CMICmnMIValueResult miValueResult5("path", miValueConst5); - bOk = bOk && vwrMiValueList.Add(miValueResult5); - // Build "loaded_addr" field - const CMIUtilString strLoadedAddr(CMIUtilString::Format("%#lx", nLoadAddress)); - const CMICmnMIValueConst miValueConst6(nLoadAddress != LLDB_INVALID_ADDRESS ? strDyldAddr : "-"); - const CMICmnMIValueResult miValueResult6("loaded_addr", miValueConst6); - bOk = bOk && vwrMiValueList.Add(miValueResult6); - // Build "dsym-objpath" field - vModule.GetSymbolFileSpec().GetPath(path, sizeof(path)); - const CMIUtilString strSymbolFilePath(path); - if (!CMIUtilString::Compare(strPlatformPath, strSymbolFilePath)) - { - const CMICmnMIValueConst miValueConst7(strSymbolFilePath); - const CMICmnMIValueResult miValueResult7("dsym-objpath", miValueConst7); - bOk = bOk && vwrMiValueList.Add(miValueResult7); + // First, build standard fields: + // Build "id" field + std::unique_ptr apPath(new char[PATH_MAX]); + vModule.GetFileSpec().GetPath(apPath.get(), PATH_MAX); + const CMIUtilString strTargetPath(apPath.get()); + const CMICmnMIValueConst miValueConst(strTargetPath); + const CMICmnMIValueResult miValueResult("id", miValueConst); + bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult); + // Build "target-name" field + const CMICmnMIValueConst miValueConst2(strTargetPath); + const CMICmnMIValueResult miValueResult2("target-name", miValueConst2); + bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult2); + // Build "host-name" field + vModule.GetPlatformFileSpec().GetPath(apPath.get(), PATH_MAX); + const CMIUtilString strHostPath(apPath.get()); + const CMICmnMIValueConst miValueConst3(strHostPath); + const CMICmnMIValueResult miValueResult3("host-name", miValueConst3); + bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult3); + + // Then build extra fields if needed: + if (vbWithExtraFields) + { + // Build "symbols-loaded" field + vModule.GetSymbolFileSpec().GetPath(apPath.get(), PATH_MAX); + const CMIUtilString strSymbolsPath(apPath.get()); + const bool bSymbolsLoaded = !CMIUtilString::Compare(strHostPath, strSymbolsPath); + const CMICmnMIValueConst miValueConst4(CMIUtilString::Format("%d", bSymbolsLoaded)); + const CMICmnMIValueResult miValueResult4("symbols-loaded", miValueConst4); + bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult4); + // Build "symbols-path" field + if (bSymbolsLoaded) + { + const CMICmnMIValueConst miValueConst5(strSymbolsPath); + const CMICmnMIValueResult miValueResult5("symbols-path", miValueConst5); + bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult5); + } + // Build "loaded_addr" field + const lldb::SBAddress sbAddress(vModule.GetObjectFileHeaderAddress()); + CMICmnLLDBDebugSessionInfo &rSessionInfo(CMICmnLLDBDebugSessionInfo::Instance()); + const lldb::addr_t nLoadAddress(sbAddress.GetLoadAddress(rSessionInfo.GetTarget())); + const CMIUtilString strLoadedAddr(nLoadAddress != LLDB_INVALID_ADDRESS ? + CMIUtilString::Format("0x%016" PRIx64, nLoadAddress) : "-"); + const CMICmnMIValueConst miValueConst6(strLoadedAddr); + const CMICmnMIValueResult miValueResult6("loaded_addr", miValueConst6); + bOk = bOk && vwrMiOutOfBandRecord.Add(miValueResult6); } return bOk; Index: tools/lldb-mi/MICmnMIOutOfBandRecord.h =================================================================== --- tools/lldb-mi/MICmnMIOutOfBandRecord.h +++ tools/lldb-mi/MICmnMIOutOfBandRecord.h @@ -62,8 +62,8 @@ eOutOfBand_ThreadCreated, eOutOfBand_ThreadExited, eOutOfBand_ThreadSelected, - eOutOfBand_TargetModulesLoaded, - eOutOfBand_TargetModulesUnloaded, + eOutOfBand_TargetModuleLoaded, + eOutOfBand_TargetModuleUnloaded, eOutOfBand_TargetStreamOutput, eOutOfBand_count // Always the last one }; Index: tools/lldb-mi/MICmnMIOutOfBandRecord.cpp =================================================================== --- tools/lldb-mi/MICmnMIOutOfBandRecord.cpp +++ tools/lldb-mi/MICmnMIOutOfBandRecord.cpp @@ -25,8 +25,8 @@ {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "thread-created"}, {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "thread-exited"}, {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "thread-selected"}, - {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesLoaded, "shlibs-added"}, - {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesUnloaded, "shlibs-removed"}, + {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleLoaded, "library-loaded"}, + {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleUnloaded, "library-unloaded"}, {CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, ""}}; CMICmnMIOutOfBandRecord::MapOutOfBandToOutOfBandText_t ms_constMapAsyncRecordTextToToken = { {CMICmnMIOutOfBandRecord::eOutOfBand_Running, "*"}, @@ -41,8 +41,8 @@ {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, "="}, {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, "="}, {CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, "="}, - {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesLoaded, "="}, - {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModulesUnloaded, "="}, + {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleLoaded, "="}, + {CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleUnloaded, "="}, {CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, "@"}}; //++ ------------------------------------------------------------------------------------ Index: tools/lldb-mi/MIExtensions.txt =================================================================== --- tools/lldb-mi/MIExtensions.txt +++ tools/lldb-mi/MIExtensions.txt @@ -31,3 +31,14 @@ -data-info-line hello.cpp:15 ^done,start="0x0000000100000f80",end="0x0000000100000f94",file="/Users/IliaK/p/hello.cpp",line="15" + +# =library-loaded notification + +The =library-loaded notification has 3 extra fields: + symbols-loaded - indicates that there are symbols for the loaded library + symbols-path - if symbols are exist then it contains a path for symbols of the loaded library + loaded_addr - contains an address of the loaded library or "-" if address isn't resolved yet + +For example: + =library-loaded,id="/Users/IliaK/p/hello",target-name="/Users/IliaK/p/hello",host-name="/Users/IliaK/p/hello",symbols-loaded="1",symbols-path="/Users/IliaK/p/hello.dSYM/Contents/Resources/DWARF/hello",loaded_addr="-" + =library-loaded,id="/usr/lib/dyld",target-name="/usr/lib/dyld",host-name="/usr/lib/dyld",symbols-loaded="0",loaded_addr="0x00007fff5fc00000"