From johnny.chen at apple.com Mon Jan 10 11:44:09 2011 From: johnny.chen at apple.com (Johnny Chen) Date: Mon, 10 Jan 2011 17:44:09 -0000 Subject: [Lldb-commits] [lldb] r123181 - in /lldb/trunk/test/python_api/frame: TestFrames.py main.c Message-ID: <20110110174409.140C22A6C12C@llvm.org> Author: johnny Date: Mon Jan 10 11:44:08 2011 New Revision: 123181 URL: http://llvm.org/viewvc/llvm-project?rev=123181&view=rev Log: Fix wrong test case in main.c. Oops! Modified: lldb/trunk/test/python_api/frame/TestFrames.py lldb/trunk/test/python_api/frame/main.c Modified: lldb/trunk/test/python_api/frame/TestFrames.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/frame/TestFrames.py?rev=123181&r1=123180&r2=123181&view=diff ============================================================================== --- lldb/trunk/test/python_api/frame/TestFrames.py (original) +++ lldb/trunk/test/python_api/frame/TestFrames.py Mon Jan 10 11:44:08 2011 @@ -12,7 +12,6 @@ mydir = os.path.join("python_api", "frame") - @unittest2.expectedFailure @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @python_api_test def test_get_arg_vals_for_call_stack_with_dsym(self): @@ -20,7 +19,6 @@ self.buildDsym() self.do_get_arg_vals() - @unittest2.expectedFailure @python_api_test def test_get_arg_vals_for_call_stack_with_dwarf(self): """Exercise SBFrame.GetVariables() API to get argument vals.""" @@ -103,8 +101,6 @@ # o a((int)val=3, (char)ch='A') print "Full stack traces when stopped on the breakpoint 'c':" print session.getvalue() - # rdar://problem/8801262 - # test failure: ./dotest.py -v -w -t -p TestFrames (argument values are wrong) self.expect(session.getvalue(), "Argugment values displayed correctly", exe=False, substrs = ["a((int)val=1, (char)ch='A')", Modified: lldb/trunk/test/python_api/frame/main.c URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/python_api/frame/main.c?rev=123181&r1=123180&r2=123181&view=diff ============================================================================== --- lldb/trunk/test/python_api/frame/main.c (original) +++ lldb/trunk/test/python_api/frame/main.c Mon Jan 10 11:44:08 2011 @@ -20,9 +20,9 @@ char my_ch = ch; printf("a(val=%d, ch='%c')\n", val, ch); if (val <= 1) - return b(++val, ++ch); + return b(val+1, ch+1); else if (val >= 3) - return c(++val, ++ch); + return c(val+1, ch+1); return val; } @@ -32,7 +32,7 @@ int my_val = val; char my_ch = ch; printf("b(val=%d, ch='%c')\n", val, ch); - return c(++val, ++ch); + return c(val+1, ch+1); } int c(int val, char ch) From gclayton at apple.com Mon Jan 10 13:28:56 2011 From: gclayton at apple.com (Greg Clayton) Date: Mon, 10 Jan 2011 19:28:56 -0000 Subject: [Lldb-commits] [lldb] r123187 - in /lldb/trunk: lldb.xcodeproj/project.pbxproj resources/LLDB-Info.plist tools/debugserver/debugserver.xcodeproj/project.pbxproj Message-ID: <20110110192856.3C88D2A6C12C@llvm.org> Author: gclayton Date: Mon Jan 10 13:28:56 2011 New Revision: 123187 URL: http://llvm.org/viewvc/llvm-project?rev=123187&view=rev Log: Bumped Xcode versions to lldb-39 and debugserver-125. Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj lldb/trunk/resources/LLDB-Info.plist lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=123187&r1=123186&r2=123187&view=diff ============================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original) +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Mon Jan 10 13:28:56 2011 @@ -2926,9 +2926,9 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 38; + DYLIB_CURRENT_VERSION = 39; EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2978,11 +2978,11 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 38; + DYLIB_CURRENT_VERSION = 39; EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3052,7 +3052,7 @@ isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3087,11 +3087,11 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 38; + DYLIB_CURRENT_VERSION = 39; EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3140,7 +3140,7 @@ buildSettings = { CODE_SIGN_IDENTITY = lldb_codesign; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", @@ -3178,7 +3178,7 @@ ); CODE_SIGN_IDENTITY = lldb_codesign; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 38; + CURRENT_PROJECT_VERSION = 39; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", Modified: lldb/trunk/resources/LLDB-Info.plist URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/resources/LLDB-Info.plist?rev=123187&r1=123186&r2=123187&view=diff ============================================================================== --- lldb/trunk/resources/LLDB-Info.plist (original) +++ lldb/trunk/resources/LLDB-Info.plist Mon Jan 10 13:28:56 2011 @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 38 + 39 CFBundleName ${EXECUTABLE_NAME} Modified: lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj?rev=123187&r1=123186&r2=123187&view=diff ============================================================================== --- lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj (original) +++ lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj Mon Jan 10 13:28:56 2011 @@ -460,7 +460,7 @@ i386, ); COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; STRIP_INSTALLED_PRODUCT = NO; @@ -478,7 +478,7 @@ x86_64, i386, ); - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEAD_CODE_STRIPPING = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; @@ -498,7 +498,7 @@ x86_64, i386, ); - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEAD_CODE_STRIPPING = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; @@ -515,7 +515,7 @@ buildSettings = { "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -556,7 +556,7 @@ "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = lldb_codesign; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -597,7 +597,7 @@ "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = lldb_codesign; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 124; + CURRENT_PROJECT_VERSION = 125; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( From gclayton at apple.com Tue Jan 11 20:25:42 2011 From: gclayton at apple.com (Greg Clayton) Date: Wed, 12 Jan 2011 02:25:42 -0000 Subject: [Lldb-commits] [lldb] r123300 - in /lldb/trunk: include/lldb/API/SBThread.h include/lldb/Target/Thread.h include/lldb/lldb-defines.h source/API/SBThread.cpp source/Target/Thread.cpp Message-ID: <20110112022543.0E8DD2A6C12C@llvm.org> Author: gclayton Date: Tue Jan 11 20:25:42 2011 New Revision: 123300 URL: http://llvm.org/viewvc/llvm-project?rev=123300&view=rev Log: Added the following functions to SBThread to allow threads to be suspended when a process is resumed: bool SBThread::Suspend(); bool SBThread::Resume(); bool SBThread::IsSuspended(); Modified: lldb/trunk/include/lldb/API/SBThread.h lldb/trunk/include/lldb/Target/Thread.h lldb/trunk/include/lldb/lldb-defines.h lldb/trunk/source/API/SBThread.cpp lldb/trunk/source/Target/Thread.cpp Modified: lldb/trunk/include/lldb/API/SBThread.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBThread.h?rev=123300&r1=123299&r2=123300&view=diff ============================================================================== --- lldb/trunk/include/lldb/API/SBThread.h (original) +++ lldb/trunk/include/lldb/API/SBThread.h Tue Jan 11 20:25:42 2011 @@ -90,6 +90,36 @@ void RunToAddress (lldb::addr_t addr); + //-------------------------------------------------------------------------- + // LLDB currently supports process centric debugging which means when any + // thread in a process stops, all other threads are stopped. The Suspend() + // call here tells our process to suspend a thread and not let it run when + // the other threads in a process are allowed to run. So when + // SBProcess::Continue() is called, any threads that aren't suspended will + // be allowed to run. If any of the SBThread functions for stepping are + // called (StepOver, StepInto, StepOut, StepInstruction, RunToAddres), the + // thread will now be allowed to run and these funtions will simply return. + // + // Eventually we plan to add support for thread centric debugging where each + // thread is controlled individually and each thread would broadcast its + // state, but we haven't implemented this yet. + // + // Likewise the SBThread::Resume() call will again allow the thread to run + // when the process is continued. + // + // The Suspend() and Resume() functions are not currently reference counted, + // if anyone has the need for them to be reference counted, please let us + // know. + //-------------------------------------------------------------------------- + bool + Suspend(); + + bool + Resume (); + + bool + IsSuspended(); + uint32_t GetNumFrames (); Modified: lldb/trunk/include/lldb/Target/Thread.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Thread.h?rev=123300&r1=123299&r2=123300&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/Thread.h (original) +++ lldb/trunk/include/lldb/Target/Thread.h Tue Jan 11 20:25:42 2011 @@ -186,10 +186,16 @@ GetProcess() const { return m_process; } int - GetResumeSignal () const; + GetResumeSignal () const + { + return m_resume_signal; + } void - SetResumeSignal (int signal); + SetResumeSignal (int signal) + { + m_resume_signal = signal; + } lldb::StateType GetState() const; @@ -201,10 +207,16 @@ SetState (lldb::StateType state); lldb::StateType - GetResumeState () const; + GetResumeState () const + { + return m_resume_state; + } void - SetResumeState (lldb::StateType state); + SetResumeState (lldb::StateType state) + { + m_resume_state = state; + } // This function is called on all the threads before "WillResume" in case // a thread needs to change its state before the ThreadList polls all the Modified: lldb/trunk/include/lldb/lldb-defines.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-defines.h?rev=123300&r1=123299&r2=123300&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-defines.h (original) +++ lldb/trunk/include/lldb/lldb-defines.h Tue Jan 11 20:25:42 2011 @@ -21,7 +21,14 @@ #endif //---------------------------------------------------------------------- -// lldb defines +// LLDB version +// +// A build script phase can modify this version number if needed. +//---------------------------------------------------------------------- +//#define LLDB_VERSION + +//---------------------------------------------------------------------- +// LLDB defines //---------------------------------------------------------------------- #define LLDB_GENERIC_ERROR UINT32_MAX Modified: lldb/trunk/source/API/SBThread.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBThread.cpp?rev=123300&r1=123299&r2=123300&view=diff ============================================================================== --- lldb/trunk/source/API/SBThread.cpp (original) +++ lldb/trunk/source/API/SBThread.cpp Tue Jan 11 20:25:42 2011 @@ -562,6 +562,36 @@ } +bool +SBThread::Suspend() +{ + if (m_opaque_sp) + { + m_opaque_sp->SetResumeState (eStateSuspended); + return true; + } + return false; +} + +bool +SBThread::Resume () +{ + if (m_opaque_sp) + { + m_opaque_sp->SetResumeState (eStateRunning); + return true; + } + return false; +} + +bool +SBThread::IsSuspended() +{ + if (m_opaque_sp) + m_opaque_sp->GetResumeState () == eStateSuspended; + return false; +} + SBProcess SBThread::GetProcess () { Modified: lldb/trunk/source/Target/Thread.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Thread.cpp?rev=123300&r1=123299&r2=123300&view=diff ============================================================================== --- lldb/trunk/source/Target/Thread.cpp (original) +++ lldb/trunk/source/Target/Thread.cpp Tue Jan 11 20:25:42 2011 @@ -85,30 +85,6 @@ m_destroy_called = true; } -int -Thread::GetResumeSignal () const -{ - return m_resume_signal; -} - -void -Thread::SetResumeSignal (int signal) -{ - m_resume_signal = signal; -} - -StateType -Thread::GetResumeState () const -{ - return m_resume_state; -} - -void -Thread::SetResumeState (StateType state) -{ - m_resume_state = state; -} - lldb::StopInfoSP Thread::GetStopInfo () { From wilsons at start.ca Tue Jan 11 21:51:27 2011 From: wilsons at start.ca (Stephen Wilson) Date: Tue, 11 Jan 2011 22:51:27 -0500 Subject: [Lldb-commits] [PATCH] Log diagnostic when setting software breakpoints only on failure. Message-ID: Previously we would be posting a "FAILED" message to the log channel even when the operation succeeded. Also, take this opportunity to add braces thus eliminating an "ambiguous else" compiler warning. diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index 36f21ac..42e0cf7 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -1080,7 +1080,7 @@ Process::EnableSoftwareBreakpoint (BreakpointSite *bp_site) else error.SetErrorString("Unable to read memory at breakpoint address."); } - if (log) + if (log && error.Fail()) log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- FAILED: %s", bp_site->GetID(), (uint64_t)bp_addr, @@ -2628,13 +2628,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, // Right now this is the only way to tell we've timed out... // We should interrupt the process here... // Not really sure what to do if Halt fails here... - if (log) + if (log) { if (try_all_threads) log->Printf ("Running function with timeout: %d timed out, trying with all threads enabled.", single_thread_timeout_usec); else log->Printf ("Running function with timeout: %d timed out, abandoning execution.", single_thread_timeout_usec); + } if (exe_ctx.process->Halt().Success()) { -- 1.7.3.5 From wilsons at start.ca Tue Jan 11 21:52:45 2011 From: wilsons at start.ca (Stephen Wilson) Date: Tue, 11 Jan 2011 22:52:45 -0500 Subject: [Lldb-commits] [PATCH] linux: Null terminate path returned by readlink() Message-ID: diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index 8d82097..f7a1a24 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -620,9 +620,11 @@ Host::GetProgramFileSpec () } #elif defined (__linux__) char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); - if (len >= 0) + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) { + exe_path[len] = 0; g_program_filespec = FileSpec(exe_path, true); + } #elif defined (__FreeBSD__) int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() }; size_t exe_path_size; -- 1.7.3.5 From wilsons at start.ca Tue Jan 11 21:53:28 2011 From: wilsons at start.ca (Stephen Wilson) Date: Tue, 11 Jan 2011 22:53:28 -0500 Subject: [Lldb-commits] [PATCH] Initialize SymbolFileDWARFDebugMap on Apple platforms only. Message-ID: SymbolFileDWARFDebugMap handles the parsing of OSO stabs which are effectively a Mach-O specific feature and is incompatible with other object file formats. diff --git a/source/lldb.cpp b/source/lldb.cpp index 137ad86..47f403d 100644 --- a/source/lldb.cpp +++ b/source/lldb.cpp @@ -71,7 +71,6 @@ lldb_private::Initialize () ObjectContainerBSDArchive::Initialize(); ObjectFileELF::Initialize(); SymbolFileDWARF::Initialize(); - SymbolFileDWARFDebugMap::Initialize(); SymbolFileSymtab::Initialize(); UnwindAssemblyProfiler_x86::Initialize(); ArchDefaultUnwindPlan_x86::Initialize(); @@ -81,6 +80,7 @@ lldb_private::Initialize () ABIMacOSX_i386::Initialize(); ABISysV_x86_64::Initialize(); DynamicLoaderMacOSXDYLD::Initialize(); + SymbolFileDWARFDebugMap::Initialize(); ItaniumABILanguageRuntime::Initialize(); AppleObjCRuntimeV2::Initialize(); AppleObjCRuntimeV1::Initialize(); @@ -110,7 +110,6 @@ lldb_private::Terminate () ObjectContainerBSDArchive::Terminate(); ObjectFileELF::Terminate(); SymbolFileDWARF::Terminate(); - SymbolFileDWARFDebugMap::Terminate(); SymbolFileSymtab::Terminate(); UnwindAssemblyProfiler_x86::Terminate(); ArchDefaultUnwindPlan_x86::Terminate(); @@ -118,6 +117,7 @@ lldb_private::Terminate () #ifdef __APPLE__ DynamicLoaderMacOSXDYLD::Terminate(); + SymbolFileDWARFDebugMap::Terminate(); ItaniumABILanguageRuntime::Terminate(); AppleObjCRuntimeV2::Terminate(); AppleObjCRuntimeV1::Terminate(); -- 1.7.3.5 -- steve From wilsons at start.ca Tue Jan 11 21:54:44 2011 From: wilsons at start.ca (Stephen Wilson) Date: Tue, 11 Jan 2011 22:54:44 -0500 Subject: [Lldb-commits] [PATCH] Do not pass an invalid thread to Thread{Cancel, Join}. Message-ID: A race condition exists between StopReadThread and the reader thread proper. When StopReadThread sets m_read_thread_enabled to false the reader thread can terminate and set m_read_thread to LLDB_INVALID_HOST_THREAD on exit. Thus calls to ThreadCancel or ThreadJoin in StopReadThread can be passed an invalid handle. This patch removes the race by using m_read_thread_enabled as the flag thru which the reader thread can notify the parent thread of early/abnormal termination. diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp index 99c619d..b178657 100644 --- a/source/Core/Communication.cpp +++ b/source/Core/Communication.cpp @@ -138,7 +138,7 @@ Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, Connectio timeout_usec, m_connection_sp.get()); - if (m_read_thread != LLDB_INVALID_HOST_THREAD) + if (m_read_thread_enabled) { // We have a dedicated read thread that is getting data for us size_t cached_bytes = GetCachedBytes (dst, dst_len); @@ -257,8 +257,9 @@ Communication::StopReadThread (Error *error_ptr) Host::ThreadCancel (m_read_thread, error_ptr); - return Host::ThreadJoin (m_read_thread, NULL, error_ptr); + bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr); m_read_thread = LLDB_INVALID_HOST_THREAD; + return status; } @@ -317,7 +318,7 @@ Communication::ReadFromConnection (void *dst, size_t dst_len, ConnectionStatus & bool Communication::ReadThreadIsRunning () { - return m_read_thread != LLDB_INVALID_HOST_THREAD; + return m_read_thread_enabled; } void * @@ -370,7 +371,7 @@ Communication::ReadThread (void *p) // Let clients know that this thread is exiting comm->BroadcastEvent (eBroadcastBitReadThreadDidExit); - comm->m_read_thread = LLDB_INVALID_HOST_THREAD; + comm->m_read_thread_enabled = false; comm->Disconnect(); return NULL; } -- 1.7.3.5 From gclayton at apple.com Tue Jan 11 22:05:42 2011 From: gclayton at apple.com (Greg Clayton) Date: Tue, 11 Jan 2011 20:05:42 -0800 Subject: [Lldb-commits] [PATCH] Do not pass an invalid thread to Thread{Cancel, Join}. In-Reply-To: References: Message-ID: All patches look good. Feel free to submit them anytime. On Jan 11, 2011, at 7:54 PM, Stephen Wilson wrote: > > A race condition exists between StopReadThread and the reader thread proper. > When StopReadThread sets m_read_thread_enabled to false the reader thread can > terminate and set m_read_thread to LLDB_INVALID_HOST_THREAD on exit. Thus calls > to ThreadCancel or ThreadJoin in StopReadThread can be passed an invalid handle. > > This patch removes the race by using m_read_thread_enabled as the flag thru > which the reader thread can notify the parent thread of early/abnormal > termination. > > > diff --git a/source/Core/Communication.cpp b/source/Core/Communication.cpp > index 99c619d..b178657 100644 > --- a/source/Core/Communication.cpp > +++ b/source/Core/Communication.cpp > @@ -138,7 +138,7 @@ Communication::Read (void *dst, size_t dst_len, uint32_t timeout_usec, Connectio > timeout_usec, > m_connection_sp.get()); > > - if (m_read_thread != LLDB_INVALID_HOST_THREAD) > + if (m_read_thread_enabled) > { > // We have a dedicated read thread that is getting data for us > size_t cached_bytes = GetCachedBytes (dst, dst_len); > @@ -257,8 +257,9 @@ Communication::StopReadThread (Error *error_ptr) > > Host::ThreadCancel (m_read_thread, error_ptr); > > - return Host::ThreadJoin (m_read_thread, NULL, error_ptr); > + bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr); > m_read_thread = LLDB_INVALID_HOST_THREAD; > + return status; > } > > > @@ -317,7 +318,7 @@ Communication::ReadFromConnection (void *dst, size_t dst_len, ConnectionStatus & > bool > Communication::ReadThreadIsRunning () > { > - return m_read_thread != LLDB_INVALID_HOST_THREAD; > + return m_read_thread_enabled; > } > > void * > @@ -370,7 +371,7 @@ Communication::ReadThread (void *p) > > // Let clients know that this thread is exiting > comm->BroadcastEvent (eBroadcastBitReadThreadDidExit); > - comm->m_read_thread = LLDB_INVALID_HOST_THREAD; > + comm->m_read_thread_enabled = false; > comm->Disconnect(); > return NULL; > } > -- > 1.7.3.5 > > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From gclayton at apple.com Tue Jan 11 22:03:58 2011 From: gclayton at apple.com (Greg Clayton) Date: Wed, 12 Jan 2011 04:03:58 -0000 Subject: [Lldb-commits] [lldb] r123305 - in /lldb/trunk: lldb.xcodeproj/project.pbxproj resources/LLDB-Info.plist Message-ID: <20110112040359.0AC0B2A6C12C@llvm.org> Author: gclayton Date: Tue Jan 11 22:03:58 2011 New Revision: 123305 URL: http://llvm.org/viewvc/llvm-project?rev=123305&view=rev Log: Bumped Xcode project version to 40 for lldb-40. Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj lldb/trunk/resources/LLDB-Info.plist Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=123305&r1=123304&r2=123305&view=diff ============================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original) +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Tue Jan 11 22:03:58 2011 @@ -2420,7 +2420,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "cd \"${TARGET_BUILD_DIR}/${PUBLIC_HEADERS_FOLDER_PATH}\"\nfor file in *.h\ndo\n\t/usr/bin/sed -i '' 's/\\(#include\\)[ ]*\"lldb\\/\\(API\\/\\)\\{0,1\\}\\(.*\\)\"/\\1 /1' \"$file\"\n\t/usr/bin/sed -i '' 's|/1' \"$file\"\n\t/usr/bin/sed -i '' 's|CFBundleSignature ???? CFBundleVersion - 39 + 40 CFBundleName ${EXECUTABLE_NAME} From wilsons at start.ca Tue Jan 11 22:20:03 2011 From: wilsons at start.ca (Stephen Wilson) Date: Wed, 12 Jan 2011 04:20:03 -0000 Subject: [Lldb-commits] [lldb] r123306 - /lldb/trunk/source/Target/Process.cpp Message-ID: <20110112042003.DD6FA2A6C12C@llvm.org> Author: wilsons Date: Tue Jan 11 22:20:03 2011 New Revision: 123306 URL: http://llvm.org/viewvc/llvm-project?rev=123306&view=rev Log: Log diagnostic when setting software breakpoints only on failure. Previously we would be posting a "FAILED" message to the log channel even when the operation succeeded. Also, take this opportunity to add braces thus eliminating an "ambiguous else" compiler warning. Modified: lldb/trunk/source/Target/Process.cpp Modified: lldb/trunk/source/Target/Process.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=123306&r1=123305&r2=123306&view=diff ============================================================================== --- lldb/trunk/source/Target/Process.cpp (original) +++ lldb/trunk/source/Target/Process.cpp Tue Jan 11 22:20:03 2011 @@ -1080,7 +1080,7 @@ else error.SetErrorString("Unable to read memory at breakpoint address."); } - if (log) + if (log && error.Fail()) log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%llx -- FAILED: %s", bp_site->GetID(), (uint64_t)bp_addr, @@ -2628,13 +2628,14 @@ // Right now this is the only way to tell we've timed out... // We should interrupt the process here... // Not really sure what to do if Halt fails here... - if (log) + if (log) { if (try_all_threads) log->Printf ("Running function with timeout: %d timed out, trying with all threads enabled.", single_thread_timeout_usec); else log->Printf ("Running function with timeout: %d timed out, abandoning execution.", single_thread_timeout_usec); + } if (exe_ctx.process->Halt().Success()) { From wilsons at start.ca Tue Jan 11 22:21:22 2011 From: wilsons at start.ca (Stephen Wilson) Date: Wed, 12 Jan 2011 04:21:22 -0000 Subject: [Lldb-commits] [lldb] r123307 - /lldb/trunk/source/Host/common/Host.cpp Message-ID: <20110112042122.0EEC92A6C12C@llvm.org> Author: wilsons Date: Tue Jan 11 22:21:21 2011 New Revision: 123307 URL: http://llvm.org/viewvc/llvm-project?rev=123307&view=rev Log: Null terminate path returned by readlink(). Modified: lldb/trunk/source/Host/common/Host.cpp Modified: lldb/trunk/source/Host/common/Host.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=123307&r1=123306&r2=123307&view=diff ============================================================================== --- lldb/trunk/source/Host/common/Host.cpp (original) +++ lldb/trunk/source/Host/common/Host.cpp Tue Jan 11 22:21:21 2011 @@ -620,9 +620,11 @@ } #elif defined (__linux__) char exe_path[PATH_MAX]; - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); - if (len >= 0) + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if (len > 0) { + exe_path[len] = 0; g_program_filespec = FileSpec(exe_path, true); + } #elif defined (__FreeBSD__) int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() }; size_t exe_path_size; From wilsons at start.ca Tue Jan 11 22:22:09 2011 From: wilsons at start.ca (Stephen Wilson) Date: Wed, 12 Jan 2011 04:22:09 -0000 Subject: [Lldb-commits] [lldb] r123308 - /lldb/trunk/source/lldb.cpp Message-ID: <20110112042209.BEBD92A6C12C@llvm.org> Author: wilsons Date: Tue Jan 11 22:22:09 2011 New Revision: 123308 URL: http://llvm.org/viewvc/llvm-project?rev=123308&view=rev Log: Initialize SymbolFileDWARFDebugMap on Apple platforms only. SymbolFileDWARFDebugMap handles the parsing of OSO stabs which are effectively a Mach-O specific feature and is incompatible with other object file formats. Modified: lldb/trunk/source/lldb.cpp Modified: lldb/trunk/source/lldb.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=123308&r1=123307&r2=123308&view=diff ============================================================================== --- lldb/trunk/source/lldb.cpp (original) +++ lldb/trunk/source/lldb.cpp Tue Jan 11 22:22:09 2011 @@ -71,7 +71,6 @@ ObjectContainerBSDArchive::Initialize(); ObjectFileELF::Initialize(); SymbolFileDWARF::Initialize(); - SymbolFileDWARFDebugMap::Initialize(); SymbolFileSymtab::Initialize(); UnwindAssemblyProfiler_x86::Initialize(); ArchDefaultUnwindPlan_x86::Initialize(); @@ -81,6 +80,7 @@ ABIMacOSX_i386::Initialize(); ABISysV_x86_64::Initialize(); DynamicLoaderMacOSXDYLD::Initialize(); + SymbolFileDWARFDebugMap::Initialize(); ItaniumABILanguageRuntime::Initialize(); AppleObjCRuntimeV2::Initialize(); AppleObjCRuntimeV1::Initialize(); @@ -110,7 +110,6 @@ ObjectContainerBSDArchive::Terminate(); ObjectFileELF::Terminate(); SymbolFileDWARF::Terminate(); - SymbolFileDWARFDebugMap::Terminate(); SymbolFileSymtab::Terminate(); UnwindAssemblyProfiler_x86::Terminate(); ArchDefaultUnwindPlan_x86::Terminate(); @@ -118,6 +117,7 @@ #ifdef __APPLE__ DynamicLoaderMacOSXDYLD::Terminate(); + SymbolFileDWARFDebugMap::Terminate(); ItaniumABILanguageRuntime::Terminate(); AppleObjCRuntimeV2::Terminate(); AppleObjCRuntimeV1::Terminate(); From wilsons at start.ca Tue Jan 11 22:22:54 2011 From: wilsons at start.ca (Stephen Wilson) Date: Wed, 12 Jan 2011 04:22:54 -0000 Subject: [Lldb-commits] [lldb] r123309 - /lldb/trunk/source/Core/Communication.cpp Message-ID: <20110112042254.DC7D92A6C12C@llvm.org> Author: wilsons Date: Tue Jan 11 22:22:54 2011 New Revision: 123309 URL: http://llvm.org/viewvc/llvm-project?rev=123309&view=rev Log: Do not pass an invalid thread to Thread{Cancel,Join}. A race condition exists between StopReadThread and the reader thread proper. When StopReadThread sets m_read_thread_enabled to false the reader thread can terminate and set m_read_thread to LLDB_INVALID_HOST_THREAD on exit. Thus calls to ThreadCancel or ThreadJoin in StopReadThread can be passed an invalid handle. This patch removes the race by using m_read_thread_enabled as the flag thru which the reader thread can notify the parent thread of early/abnormal termination. Modified: lldb/trunk/source/Core/Communication.cpp Modified: lldb/trunk/source/Core/Communication.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Communication.cpp?rev=123309&r1=123308&r2=123309&view=diff ============================================================================== --- lldb/trunk/source/Core/Communication.cpp (original) +++ lldb/trunk/source/Core/Communication.cpp Tue Jan 11 22:22:54 2011 @@ -138,7 +138,7 @@ timeout_usec, m_connection_sp.get()); - if (m_read_thread != LLDB_INVALID_HOST_THREAD) + if (m_read_thread_enabled) { // We have a dedicated read thread that is getting data for us size_t cached_bytes = GetCachedBytes (dst, dst_len); @@ -257,8 +257,9 @@ Host::ThreadCancel (m_read_thread, error_ptr); - return Host::ThreadJoin (m_read_thread, NULL, error_ptr); + bool status = Host::ThreadJoin (m_read_thread, NULL, error_ptr); m_read_thread = LLDB_INVALID_HOST_THREAD; + return status; } @@ -317,7 +318,7 @@ bool Communication::ReadThreadIsRunning () { - return m_read_thread != LLDB_INVALID_HOST_THREAD; + return m_read_thread_enabled; } void * @@ -370,7 +371,7 @@ // Let clients know that this thread is exiting comm->BroadcastEvent (eBroadcastBitReadThreadDidExit); - comm->m_read_thread = LLDB_INVALID_HOST_THREAD; + comm->m_read_thread_enabled = false; comm->Disconnect(); return NULL; } From gclayton at apple.com Wed Jan 12 12:36:46 2011 From: gclayton at apple.com (Greg Clayton) Date: Wed, 12 Jan 2011 10:36:46 -0800 Subject: [Lldb-commits] [lldb] r123307 - /lldb/trunk/source/Host/common/Host.cpp In-Reply-To: <20110112042122.0EEC92A6C12C@llvm.org> References: <20110112042122.0EEC92A6C12C@llvm.org> Message-ID: Quick possible optimization on the code below: I am guessing that readlink() returns a path that is already resolved? If so then passing true to the FileSpec constructor line: g_program_filespec = FileSpec(exe_path, true); will cause realpath() to be called on exe_path to try and resolve the path (which is typically meant for paths that might be symlinks, or "~/path/to/file", or "relative/path/to/file") which is probably redundant. We can pass false to this if the path is already resolved and avoid this: g_program_filespec = FileSpec(exe_path, false); Better yet, since the FileSpec constructor calls FileSpec::SetFile(...) anyway, this could just become: g_program_filespec.SetFile (exe_path, false); On Jan 11, 2011, at 8:21 PM, Stephen Wilson wrote: > Author: wilsons > Date: Tue Jan 11 22:21:21 2011 > New Revision: 123307 > > URL: http://llvm.org/viewvc/llvm-project?rev=123307&view=rev > Log: > Null terminate path returned by readlink(). > > > Modified: > lldb/trunk/source/Host/common/Host.cpp > > Modified: lldb/trunk/source/Host/common/Host.cpp > URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=123307&r1=123306&r2=123307&view=diff > ============================================================================== > --- lldb/trunk/source/Host/common/Host.cpp (original) > +++ lldb/trunk/source/Host/common/Host.cpp Tue Jan 11 22:21:21 2011 > @@ -620,9 +620,11 @@ > } > #elif defined (__linux__) > char exe_path[PATH_MAX]; > - ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path)); > - if (len >= 0) > + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); > + if (len > 0) { > + exe_path[len] = 0; > g_program_filespec = FileSpec(exe_path, true); > + } > #elif defined (__FreeBSD__) > int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() }; > size_t exe_path_size; > > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From wilsons at start.ca Wed Jan 12 17:04:23 2011 From: wilsons at start.ca (Stephen Wilson) Date: Wed, 12 Jan 2011 18:04:23 -0500 Subject: [Lldb-commits] [lldb] r123307 - /lldb/trunk/source/Host/common/Host.cpp In-Reply-To: (Greg Clayton's message of "Wed, 12 Jan 2011 10:36:46 -0800") References: <20110112042122.0EEC92A6C12C@llvm.org> Message-ID: Greg Clayton writes: > Quick possible optimization on the code below: I am guessing that > readlink() returns a path that is already resolved? If so then passing > true to the FileSpec constructor line: > > g_program_filespec = FileSpec(exe_path, true); > > will cause realpath() to be called on exe_path to try and resolve the > path (which is typically meant for paths that might be symlinks, or > "~/path/to/file", or "relative/path/to/file") which is probably > redundant. We can pass false to this if the path is already resolved > and avoid this: > > g_program_filespec = FileSpec(exe_path, false); > > Better yet, since the FileSpec constructor calls > FileSpec::SetFile(...) anyway, this could just become: > > g_program_filespec.SetFile (exe_path, false); > Yes, absolutely. The following has been tested and works fine. I can commit the patch in a few hours if you wish (running a bit short on time ATM). diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp index de0883c..a47a14c 100644 --- a/source/Host/common/Host.cpp +++ b/source/Host/common/Host.cpp @@ -624,7 +624,7 @@ Host::GetProgramFileSpec () ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); if (len > 0) { exe_path[len] = 0; - g_program_filespec = FileSpec(exe_path, true); + g_program_filespec.SetFile(exe_path, false); } #elif defined (__FreeBSD__) int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() }; From gclayton at apple.com Wed Jan 12 19:23:43 2011 From: gclayton at apple.com (Greg Clayton) Date: Thu, 13 Jan 2011 01:23:43 -0000 Subject: [Lldb-commits] [lldb] r123355 - /lldb/trunk/source/Host/common/Host.cpp Message-ID: <20110113012344.01D7F2A6C12C@llvm.org> Author: gclayton Date: Wed Jan 12 19:23:43 2011 New Revision: 123355 URL: http://llvm.org/viewvc/llvm-project?rev=123355&view=rev Log: Don't have the program path be resolved when they already are when assigning g_program_filespec in the Host calls. Modified: lldb/trunk/source/Host/common/Host.cpp Modified: lldb/trunk/source/Host/common/Host.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=123355&r1=123354&r2=123355&view=diff ============================================================================== --- lldb/trunk/source/Host/common/Host.cpp (original) +++ lldb/trunk/source/Host/common/Host.cpp Wed Jan 12 19:23:43 2011 @@ -607,14 +607,14 @@ uint32_t len = sizeof(program_fullpath); int err = _NSGetExecutablePath (program_fullpath, &len); if (err == 0) - g_program_filespec.SetFile (program_fullpath, true); + g_program_filespec.SetFile (program_fullpath, false); else if (err == -1) { char *large_program_fullpath = (char *)::malloc (len + 1); err = _NSGetExecutablePath (large_program_fullpath, &len); if (err == 0) - g_program_filespec.SetFile (large_program_fullpath, true); + g_program_filespec.SetFile (large_program_fullpath, false); ::free (large_program_fullpath); } @@ -623,7 +623,7 @@ ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); if (len > 0) { exe_path[len] = 0; - g_program_filespec = FileSpec(exe_path, true); + g_program_filespec.SetFile(exe_path, false); } #elif defined (__FreeBSD__) int exe_path_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, getpid() }; @@ -632,7 +632,7 @@ { char *exe_path = new char[exe_path_size]; if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0) - g_program_filespec = FileSpec(exe_path, true); + g_program_filespec = FileSpec(exe_path, false); } #endif } From gclayton at apple.com Wed Jan 12 19:25:48 2011 From: gclayton at apple.com (Greg Clayton) Date: Thu, 13 Jan 2011 01:25:48 -0000 Subject: [Lldb-commits] [lldb] r123356 - /lldb/trunk/source/Host/common/Host.cpp Message-ID: <20110113012548.A96102A6C12C@llvm.org> Author: gclayton Date: Wed Jan 12 19:25:48 2011 New Revision: 123356 URL: http://llvm.org/viewvc/llvm-project?rev=123356&view=rev Log: Call SetFile instead of constructing a temp object and assigning to g_program_filespec for Free BSD port. Modified: lldb/trunk/source/Host/common/Host.cpp Modified: lldb/trunk/source/Host/common/Host.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=123356&r1=123355&r2=123356&view=diff ============================================================================== --- lldb/trunk/source/Host/common/Host.cpp (original) +++ lldb/trunk/source/Host/common/Host.cpp Wed Jan 12 19:25:48 2011 @@ -632,7 +632,7 @@ { char *exe_path = new char[exe_path_size]; if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0) - g_program_filespec = FileSpec(exe_path, false); + g_program_filespec.SetFile(exe_path, false); } #endif } From gclayton at apple.com Wed Jan 12 19:27:55 2011 From: gclayton at apple.com (Greg Clayton) Date: Thu, 13 Jan 2011 01:27:55 -0000 Subject: [Lldb-commits] [lldb] r123357 - /lldb/trunk/source/Host/common/Host.cpp Message-ID: <20110113012755.E7EF92A6C12C@llvm.org> Author: gclayton Date: Wed Jan 12 19:27:55 2011 New Revision: 123357 URL: http://llvm.org/viewvc/llvm-project?rev=123357&view=rev Log: Plug Free BSD memory leak. Modified: lldb/trunk/source/Host/common/Host.cpp Modified: lldb/trunk/source/Host/common/Host.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=123357&r1=123356&r2=123357&view=diff ============================================================================== --- lldb/trunk/source/Host/common/Host.cpp (original) +++ lldb/trunk/source/Host/common/Host.cpp Wed Jan 12 19:27:55 2011 @@ -630,9 +630,10 @@ size_t exe_path_size; if (sysctl(exe_path_mib, 4, NULL, &exe_path_size, NULL, 0) == 0) { - char *exe_path = new char[exe_path_size]; - if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0) - g_program_filespec.SetFile(exe_path, false); + char *exe_path = new char[exe_path_size]; + if (sysctl(exe_path_mib, 4, exe_path, &exe_path_size, NULL, 0) == 0) + g_program_filespec.SetFile(exe_path, false); + delete[] exe_path; } #endif } From scallanan at apple.com Thu Jan 13 02:53:35 2011 From: scallanan at apple.com (Sean Callanan) Date: Thu, 13 Jan 2011 08:53:35 -0000 Subject: [Lldb-commits] [lldb] r123371 - in /lldb/trunk: include/lldb/Expression/ include/lldb/Symbol/ include/lldb/Target/ source/API/ source/Breakpoint/ source/Commands/ source/Core/ source/Expression/ source/Plugins/Process/gdb-remote/ source/Symbol/ source/Target/ Message-ID: <20110113085335.AFFD12A6C12D@llvm.org> Author: spyffe Date: Thu Jan 13 02:53:35 2011 New Revision: 123371 URL: http://llvm.org/viewvc/llvm-project?rev=123371&view=rev Log: Implemented a major overhaul of the way variables are handled by LLDB. Instead of being materialized into the input structure passed to the expression, variables are left in place and pointers to them are materialzied into the structure. Variables not resident in memory (notably, registers) get temporary memory regions allocated for them. Persistent variables are the most complex part of this, because they are made in various ways and there are different expectations about their lifetime. Persistent variables now have flags indicating their status and what the expectations for longevity are. They can be marked as residing in target memory permanently -- this is the default for result variables from expressions entered on the command line and for explicitly declared persistent variables (but more on that below). Other result variables have their memory freed. Some major improvements resulting from this include being able to properly take the address of variables, better and cleaner support for functions that return references, and cleaner C++ support in general. One problem that remains is the problem of explicitly declared persistent variables; I have not yet implemented the code that makes references to them into indirect references, so currently materialization and dematerialization of these variables is broken. Modified: lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h lldb/trunk/include/lldb/Expression/ClangExpressionVariable.h lldb/trunk/include/lldb/Expression/ClangUserExpression.h lldb/trunk/include/lldb/Expression/IRForTarget.h lldb/trunk/include/lldb/Symbol/ClangASTContext.h lldb/trunk/include/lldb/Target/Target.h lldb/trunk/source/API/SBFrame.cpp lldb/trunk/source/Breakpoint/BreakpointOptions.cpp lldb/trunk/source/Commands/CommandObjectExpression.cpp lldb/trunk/source/Core/ValueObject.cpp lldb/trunk/source/Expression/ASTResultSynthesizer.cpp lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp lldb/trunk/source/Expression/ClangExpressionVariable.cpp lldb/trunk/source/Expression/ClangUserExpression.cpp lldb/trunk/source/Expression/ClangUtilityFunction.cpp lldb/trunk/source/Expression/IRForTarget.cpp lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp lldb/trunk/source/Symbol/ClangASTContext.cpp lldb/trunk/source/Target/Process.cpp lldb/trunk/source/Target/Target.cpp Modified: lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h (original) +++ lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h Thu Jan 13 02:53:35 2011 @@ -70,9 +70,14 @@ //------------------------------------------------------------------ /// Constructor /// - /// Initializes class variabes. + /// Initializes class variables. + /// + /// @param[in] keep_result_in_memory + /// If true, inhibits the normal deallocation of the memory for + /// the result persistent variable, and instead marks the variable + /// as persisting. //------------------------------------------------------------------ - ClangExpressionDeclMap (); + ClangExpressionDeclMap (bool keep_result_in_memory); //------------------------------------------------------------------ /// Destructor @@ -151,7 +156,9 @@ bool AddPersistentVariable (const clang::NamedDecl *decl, const ConstString &name, - TypeFromParser type); + TypeFromParser type, + bool is_result, + bool is_lvalue); //------------------------------------------------------------------ /// [Used by IRForTarget] Add a variable to the struct that needs to @@ -443,6 +450,7 @@ private: ClangExpressionVariableList m_found_entities; ///< All entities that were looked up for the parser. ClangExpressionVariableList m_struct_members; ///< All entities that need to be placed in the struct. + bool m_keep_result_in_memory; ///< True if result persistent variables generated by this expression should stay in memory. //---------------------------------------------------------------------- /// The following values should not live beyond parsing @@ -797,11 +805,11 @@ /// @param[in] sym_ctx /// The symbol context to use (for looking the variable up). /// - /// @param[in] name - /// The name of the variable (for looking the variable up). - /// - /// @param[in] type - /// The required type of the variable (for looking the variable up). + /// @param[in] expr_var + /// The entity that the expression parser uses for the variable. + /// In case the variable needs to be copied into the target's + /// memory, this location is stored in the variable during + /// materialization and cleared when it is demateralized. /// /// @param[in] addr /// The address at which to materialize the variable. @@ -817,8 +825,7 @@ DoMaterializeOneVariable (bool dematerialize, ExecutionContext &exe_ctx, const SymbolContext &sym_ctx, - const ConstString &name, - TypeFromUser type, + lldb::ClangExpressionVariableSP &expr_var, lldb::addr_t addr, Error &err); Modified: lldb/trunk/include/lldb/Expression/ClangExpressionVariable.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ClangExpressionVariable.h?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/ClangExpressionVariable.h (original) +++ lldb/trunk/include/lldb/Expression/ClangExpressionVariable.h Thu Jan 13 02:53:35 2011 @@ -199,7 +199,6 @@ void ValueUpdated (); - typedef lldb::SharedPtr::Type ValueObjectConstResultSP; //---------------------------------------------------------------------- @@ -207,9 +206,22 @@ //---------------------------------------------------------------------- std::auto_ptr m_parser_vars; std::auto_ptr m_jit_vars; - //ValueObjectConstResultSP m_valojb_sp; - lldb::ValueObjectSP m_valojb_sp; - + + enum Flags + { + EVNone = 0, + EVIsLLDBAllocated = 1 << 0, ///< This variable is resident in a location specifically allocated for it by LLDB in the target process + EVIsProgramReference = 1 << 1, ///< This variable is a reference to a (possibly invalid) area managed by the target program + EVNeedsAllocation = 1 << 2, ///< Space for this variable has yet to be allocated in the target process + EVIsFreezeDried = 1 << 3, ///< This variable's authoritative version is in m_frozen_sp (for example, for statically-computed results) + EVNeedsFreezeDry = 1 << 4, ///< Copy from m_live_sp to m_frozen_sp during dematerialization + EVKeepInTarget = 1 << 5 ///< Keep the allocation after the expression is complete rather than freeze drying its contents and freeing it + }; + + uint16_t m_flags; // takes elements of Flags + + lldb::ValueObjectSP m_frozen_sp; + lldb::ValueObjectSP m_live_sp; private: DISALLOW_COPY_AND_ASSIGN (ClangExpressionVariable); }; Modified: lldb/trunk/include/lldb/Expression/ClangUserExpression.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ClangUserExpression.h?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/ClangUserExpression.h (original) +++ lldb/trunk/include/lldb/Expression/ClangUserExpression.h Thu Jan 13 02:53:35 2011 @@ -81,6 +81,10 @@ /// The type that the expression should be coerced to. If NULL, /// inferred from the expression itself. /// + /// @param[in] keep_result_in_memory + /// True if the resulting persistent variable should reside in + /// target memory, if applicable. + /// /// @param[out] const_result /// If this is non-NULL, the expression has no side effects, and /// the expression returns a constant result, then that result @@ -93,6 +97,7 @@ Parse (Stream &error_stream, ExecutionContext &exe_ctx, TypeFromUser desired_type, + bool keep_result_in_memory, lldb::ClangExpressionVariableSP *const_result = NULL); //------------------------------------------------------------------ @@ -109,6 +114,7 @@ /// If true, and the execution stops before completion, we unwind the /// function call, and return the program state to what it was before the /// execution. If false, we leave the program in the stopped state. + /// /// @param[in] shared_ptr_to_me /// This is a shared pointer to this ClangUserExpression. This is /// needed because Execute can push a thread plan that will hold onto @@ -127,12 +133,14 @@ Execute (Stream &error_stream, ExecutionContext &exe_ctx, bool discard_on_error, + bool keep_in_memory, ClangUserExpressionSP &shared_ptr_to_me, lldb::ClangExpressionVariableSP &result); ThreadPlan * GetThreadPlanToExecuteJITExpression (Stream &error_stream, ExecutionContext &exe_ctx); + bool FinalizeJITExecution (Stream &error_stream, ExecutionContext &exe_ctx, @@ -232,6 +240,14 @@ /// @param[in] exe_ctx /// The execution context to use when evaluating the expression. /// + /// @param[in] discard_on_error + /// True if the thread's state should be restored in the case + /// of an error. + /// + /// @param[in] keep_in_memory + /// True if the resulting persistent variable should reside in + /// target memory, if applicable. + /// /// @param[in] expr_cstr /// A C string containing the expression to be evaluated. /// @@ -248,6 +264,7 @@ static lldb::ExecutionResults Evaluate (ExecutionContext &exe_ctx, bool discard_on_error, + bool keep_in_memory, const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp); Modified: lldb/trunk/include/lldb/Expression/IRForTarget.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/IRForTarget.h?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/IRForTarget.h (original) +++ lldb/trunk/include/lldb/Expression/IRForTarget.h Thu Jan 13 02:53:35 2011 @@ -448,12 +448,14 @@ /// Flags bool m_resolve_vars; ///< True if external variable references and persistent variable references should be resolved std::string m_func_name; ///< The name of the function to translate + lldb_private::ConstString m_result_name; ///< The name of the result variable ($0, $1, ...) lldb_private::ClangExpressionDeclMap *m_decl_map; ///< The DeclMap containing the Decls llvm::Constant *m_CFStringCreateWithBytes; ///< The address of the function CFStringCreateWithBytes, cast to the appropriate function pointer type llvm::Constant *m_sel_registerName; ///< The address of the function sel_registerName, cast to the appropriate function pointer type lldb::ClangExpressionVariableSP *m_const_result; ///< If non-NULL, this value should be set to the return value of the expression if it is constant and the expression has no side effects bool m_has_side_effects; ///< True if the function's result cannot be simply determined statically + bool m_result_is_pointer; ///< True if the function's result in the AST is a pointer (see comments in ASTResultSynthesizer::SynthesizeBodyResult) private: //------------------------------------------------------------------ Modified: lldb/trunk/include/lldb/Symbol/ClangASTContext.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangASTContext.h?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/ClangASTContext.h (original) +++ lldb/trunk/include/lldb/Symbol/ClangASTContext.h Thu Jan 13 02:53:35 2011 @@ -529,11 +529,25 @@ CreatePointerType (clang::ASTContext *ast, lldb::clang_type_t clang_type); + static lldb::clang_type_t + CreateLValueReferenceType (clang::ASTContext *ast_context, + lldb::clang_type_t clang_type); + + static lldb::clang_type_t + CreateRValueReferenceType (clang::ASTContext *ast_context, + lldb::clang_type_t clang_type); + lldb::clang_type_t - CreateLValueReferenceType (lldb::clang_type_t clang_type); + CreateLValueReferenceType (lldb::clang_type_t clang_type) + { + return ClangASTContext::CreateLValueReferenceType(getASTContext(), clang_type); + } lldb::clang_type_t - CreateRValueReferenceType (lldb::clang_type_t clang_type); + CreateRValueReferenceType (lldb::clang_type_t clang_type) + { + return ClangASTContext::CreateRValueReferenceType(getASTContext(), clang_type); + } lldb::clang_type_t CreateMemberPointerType (lldb::clang_type_t clang_pointee_type, Modified: lldb/trunk/include/lldb/Target/Target.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/include/lldb/Target/Target.h (original) +++ lldb/trunk/include/lldb/Target/Target.h Thu Jan 13 02:53:35 2011 @@ -476,6 +476,7 @@ EvaluateExpression (const char *expression, StackFrame *frame, bool unwind_on_error, + bool keep_in_memory, lldb::ValueObjectSP &result_valobj_sp); ClangPersistentVariables & Modified: lldb/trunk/source/API/SBFrame.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBFrame.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/API/SBFrame.cpp (original) +++ lldb/trunk/source/API/SBFrame.cpp Thu Jan 13 02:53:35 2011 @@ -689,8 +689,9 @@ { ExecutionResults exe_results; const bool unwind_on_error = true; + const bool keep_in_memory = false; - exe_results = m_opaque_sp->GetThread().GetProcess().GetTarget().EvaluateExpression(expr, m_opaque_sp.get(), unwind_on_error, *expr_result); + exe_results = m_opaque_sp->GetThread().GetProcess().GetTarget().EvaluateExpression(expr, m_opaque_sp.get(), unwind_on_error, keep_in_memory, *expr_result); } if (expr_log) Modified: lldb/trunk/source/Breakpoint/BreakpointOptions.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Breakpoint/BreakpointOptions.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Breakpoint/BreakpointOptions.cpp (original) +++ lldb/trunk/source/Breakpoint/BreakpointOptions.cpp Thu Jan 13 02:53:35 2011 @@ -199,7 +199,7 @@ ClangASTContext *ast_context = exe_ctx.target->GetScratchClangASTContext(); TypeFromUser bool_type(ast_context->GetBuiltInType_bool(), ast_context->getASTContext()); - if (!m_condition_ap->Parse (error_stream, exe_ctx, bool_type)) + if (!m_condition_ap->Parse (error_stream, exe_ctx, bool_type, false /* keep_in_memory */)) { // Errors mean we should stop. return NULL; Modified: lldb/trunk/source/Commands/CommandObjectExpression.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectExpression.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectExpression.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectExpression.cpp Thu Jan 13 02:53:35 2011 @@ -237,7 +237,10 @@ lldb::ValueObjectSP result_valobj_sp; lldb::ExecutionResults exe_results; - exe_results = m_exe_ctx.target->EvaluateExpression(expr, m_exe_ctx.frame, m_options.unwind_on_error, result_valobj_sp); + + bool keep_in_memory = true; + + exe_results = m_exe_ctx.target->EvaluateExpression(expr, m_exe_ctx.frame, m_options.unwind_on_error, keep_in_memory, result_valobj_sp); if (exe_results == eExecutionInterrupted && !m_options.unwind_on_error) { Modified: lldb/trunk/source/Core/ValueObject.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Core/ValueObject.cpp (original) +++ lldb/trunk/source/Core/ValueObject.cpp Thu Jan 13 02:53:35 2011 @@ -1316,7 +1316,7 @@ ClangASTContext::CreatePointerType (ast, clang_type), ConstString (name.c_str()), addr, - address_type, + eAddressTypeInvalid, m_data.GetAddressByteSize())); } } Modified: lldb/trunk/source/Expression/ASTResultSynthesizer.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ASTResultSynthesizer.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Expression/ASTResultSynthesizer.cpp (original) +++ lldb/trunk/source/Expression/ASTResultSynthesizer.cpp Thu Jan 13 02:53:35 2011 @@ -246,6 +246,49 @@ // No auxiliary variable necessary; expression returns void return true; + // is_lvalue is used to record whether the expression returns an assignable Lvalue or an + // Rvalue. This is relevant because they are handled differently. + // + // For Lvalues + // + // - In AST result synthesis (here!) the expression E is transformed into an initialization + // T *$__lldb_expr_result_ptr = &E. + // + // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be + // passed into the expression. + // + // - In IR transformations, reads and writes to $__lldb_expr_result_ptr are redirected at + // an entry in the struct ($__lldb_arg) passed into the expression. (Other persistent + // variables are treated similarly, having been materialized as references, but in those + // cases the value of the reference itself is never modified.) + // + // - During materialization, $0 (the result persistent variable) is ignored. + // + // - During dematerialization, $0 is marked up as a load address with value equal to the + // contents of the structure entry. + // + // For Rvalues + // + // - In AST result synthesis the expression E is transformed into an initialization + // static T $__lldb_expr_result = E. + // + // - In structure allocation, a pointer-sized slot is allocated in the struct that is to be + // passed into the expression. + // + // - In IR transformations, an instruction is inserted at the beginning of the function to + // dereference the pointer resident in the slot. Reads and writes to $__lldb_expr_result + // are redirected at that dereferenced version. Guard variables for the static variable + // are excised. + // + // - During materialization, $0 (the result persistent variable) is populated with the location + // of a newly-allocated area of memory. + // + // - During dematerialization, $0 is ignored. + + bool is_lvalue = + (last_expr->getValueKind() == VK_LValue || last_expr->getValueKind() == VK_XValue) && + (last_expr->getObjectKind() == OK_Ordinary); + QualType expr_qual_type = last_expr->getType(); clang::Type *expr_type = expr_qual_type.getTypePtr(); @@ -259,22 +302,51 @@ { std::string s = expr_qual_type.getAsString(); - log->Printf("Last statement's type: %s", s.c_str()); + log->Printf("Last statement is an %s with type: %s", (is_lvalue ? "lvalue" : "rvalue"), s.c_str()); } - IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result"); - - clang::VarDecl *result_decl = VarDecl::Create(Ctx, - DC, - SourceLocation(), - &result_id, - expr_qual_type, - NULL, - SC_Static, - SC_Static); + clang::VarDecl *result_decl; - if (!result_decl) - return false; + if (is_lvalue) + { + IdentifierInfo &result_ptr_id = Ctx.Idents.get("$__lldb_expr_result_ptr"); + + QualType ptr_qual_type = Ctx.getPointerType(expr_qual_type); + + result_decl = VarDecl::Create(Ctx, + DC, + SourceLocation(), + &result_ptr_id, + ptr_qual_type, + NULL, + SC_Static, + SC_Static); + + if (!result_decl) + return false; + + ExprResult address_of_expr = m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr); + + m_sema->AddInitializerToDecl(result_decl, address_of_expr.take()); + } + else + { + IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result"); + + result_decl = VarDecl::Create(Ctx, + DC, + SourceLocation(), + &result_id, + expr_qual_type, + NULL, + SC_Static, + SC_Static); + + if (!result_decl) + return false; + + m_sema->AddInitializerToDecl(result_decl, last_expr); + } DC->addDecl(result_decl); @@ -282,7 +354,7 @@ // call AddInitializerToDecl // - m_sema->AddInitializerToDecl(result_decl, last_expr); + //m_sema->AddInitializerToDecl(result_decl, last_expr); ///////////////////////////////// // call ConvertDeclToDeclGroup Modified: lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp (original) +++ lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp Thu Jan 13 02:53:35 2011 @@ -45,11 +45,12 @@ using namespace lldb_private; using namespace clang; -ClangExpressionDeclMap::ClangExpressionDeclMap () : +ClangExpressionDeclMap::ClangExpressionDeclMap (bool keep_result_in_memory) : m_found_entities (), m_struct_members (), m_parser_vars (), - m_struct_vars () + m_struct_vars (), + m_keep_result_in_memory (keep_result_in_memory) { EnableStructVars(); } @@ -187,6 +188,8 @@ return lldb::ClangExpressionVariableSP(); } } + + pvar_sp->m_flags |= ClangExpressionVariable::EVIsFreezeDried; return pvar_sp; } @@ -196,11 +199,15 @@ ( const clang::NamedDecl *decl, const ConstString &name, - TypeFromParser parser_type + TypeFromParser parser_type, + bool is_result, + bool is_lvalue ) { assert (m_parser_vars.get()); + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + clang::ASTContext *context(m_parser_vars->m_exe_ctx->target->GetScratchClangASTContext()->getASTContext()); TypeFromUser user_type(ClangASTContext::CopyType(context, @@ -219,6 +226,24 @@ if (!var_sp) return false; + if (is_result) + var_sp->m_flags |= ClangExpressionVariable::EVNeedsFreezeDry; + else + var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget; // explicitly-declared persistent variables should persist + + if (is_lvalue) + { + var_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference; + } + else + { + var_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; + var_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation; + } + + if (log) + log->Printf("Created persistent variable with flags 0x%hx", var_sp->m_flags); + var_sp->EnableParserVars(); var_sp->m_parser_vars->m_named_decl = decl; @@ -441,7 +466,7 @@ m_material_vars->m_process = exe_ctx.process; - bool result = DoMaterialize(false, exe_ctx, NULL, err); + bool result = DoMaterialize(false /* dematerialize */, exe_ctx, NULL, err); if (result) struct_address = m_material_vars->m_materialized_location; @@ -740,9 +765,8 @@ if (!DoMaterializeOneVariable (dematerialize, exe_ctx, - sym_ctx, - member_sp->GetName(), - member_sp->GetTypeFromUser(), + sym_ctx, + member_sp, m_material_vars->m_materialized_location + member_sp->m_jit_vars->m_offset, err)) return false; @@ -754,20 +778,21 @@ // with with a '$' character... if (member_sp->GetName().AsCString ("!")[0] == '$' && persistent_vars.ContainsVariable(member_sp)) { + bool keep_this_in_memory = false; + if (member_sp->GetName() == m_struct_vars->m_result_name) { - if (!dematerialize) - continue; - if (log) log->PutCString("Found result member in the struct"); - + if (result_sp_ptr) *result_sp_ptr = member_sp; + + keep_this_in_memory = m_keep_result_in_memory; } if (!DoMaterializeOnePersistentVariable (dematerialize, - exe_ctx, + exe_ctx, member_sp, m_material_vars->m_materialized_location + member_sp->m_jit_vars->m_offset, err)) @@ -784,6 +809,63 @@ return true; } +static bool WriteAddressInto +( + ExecutionContext &exe_ctx, + lldb::addr_t target, + lldb::addr_t address, + Error &err +) +{ + size_t pointer_byte_size = exe_ctx.process->GetAddressByteSize(); + + StreamString str (0 | Stream::eBinary, + pointer_byte_size, + exe_ctx.process->GetByteOrder()); + + switch (pointer_byte_size) + { + default: + assert(!"Unhandled byte size"); + case 4: + { + uint32_t address32 = address & 0xffffffffll; + str.PutRawBytes(&address32, sizeof(address32), eByteOrderHost, eByteOrderInvalid); + } + break; + case 8: + { + uint64_t address64 = address; + str.PutRawBytes(&address64, sizeof(address64), eByteOrderHost, eByteOrderInvalid); + } + break; + } + + return (exe_ctx.process->WriteMemory (target, str.GetData(), pointer_byte_size, err) == pointer_byte_size); +} + +static lldb::addr_t ReadAddressFrom +( + ExecutionContext &exe_ctx, + lldb::addr_t source, + Error &err +) +{ + size_t pointer_byte_size = exe_ctx.process->GetAddressByteSize(); + + DataBufferHeap *buf = new DataBufferHeap(pointer_byte_size, 0); + DataBufferSP buf_sp(buf); + + if (exe_ctx.process->ReadMemory (source, buf->GetBytes(), pointer_byte_size, err) != pointer_byte_size) + return LLDB_INVALID_ADDRESS; + + DataExtractor extractor (buf_sp, exe_ctx.process->GetByteOrder(), exe_ctx.process->GetAddressByteSize()); + + uint32_t offset = 0; + + return (lldb::addr_t)extractor.GetPointer(&offset); +} + bool ClangExpressionDeclMap::DoMaterializeOnePersistentVariable ( @@ -794,6 +876,8 @@ Error &err ) { + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + if (!var_sp) { err.SetErrorString("Invalid persistent variable"); @@ -808,20 +892,167 @@ Error error; + lldb::addr_t mem; // The address of a spare memory area used to hold the persistent variable. + if (dematerialize) { - var_sp->ValueUpdated (); - if (exe_ctx.process->ReadMemory (addr, pvar_data, pvar_byte_size, error) != pvar_byte_size) + if (log) + log->Printf("Dematerializing persistent variable with flags 0x%hx", var_sp->m_flags); + + if ((var_sp->m_flags & ClangExpressionVariable::EVIsLLDBAllocated) || + (var_sp->m_flags & ClangExpressionVariable::EVIsProgramReference)) { - err.SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString()); + // Get the location of the target out of the struct. + + Error read_error; + mem = ReadAddressFrom(exe_ctx, addr, read_error); + + if (mem == LLDB_INVALID_ADDRESS) + { + err.SetErrorStringWithFormat("Couldn't read address of %s from struct: %s", var_sp->GetName().GetCString(), error.AsCString()); + return false; + } + + if (var_sp->m_flags & ClangExpressionVariable::EVIsProgramReference && + !var_sp->m_live_sp) + { + // If the reference comes from the program, then the ClangExpressionVariable's + // live variable data hasn't been set up yet. Do this now. + + var_sp->m_live_sp.reset(new lldb_private::ValueObjectConstResult(var_sp->GetTypeFromUser().GetASTContext(), + var_sp->GetTypeFromUser().GetOpaqueQualType(), + var_sp->GetName(), + mem, + lldb::eAddressTypeLoad, + pvar_byte_size)); + } + + if (!var_sp->m_live_sp) + { + err.SetErrorStringWithFormat("Couldn't find the memory area used to store %s", var_sp->GetName().GetCString()); + return false; + } + + if (var_sp->m_live_sp->GetValue().GetValueAddressType() != lldb::eAddressTypeLoad) + { + err.SetErrorStringWithFormat("The address of the memory area for %s is in an incorrect format", var_sp->GetName().GetCString()); + return false; + } + + if (var_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry) + { + mem = var_sp->m_live_sp->GetValue().GetScalar().ULongLong(); + + if (log) + log->Printf("Dematerializing %s from 0x%llx", var_sp->GetName().GetCString(), (uint64_t)mem); + + // Read the contents of the spare memory area + + if (log) + log->Printf("Read"); + + var_sp->ValueUpdated (); + if (exe_ctx.process->ReadMemory (mem, pvar_data, pvar_byte_size, error) != pvar_byte_size) + { + err.SetErrorStringWithFormat ("Couldn't read a composite type from the target: %s", error.AsCString()); + return false; + } + + var_sp->m_flags &= ~ClangExpressionVariable::EVNeedsFreezeDry; + } + + if (var_sp->m_flags & ClangExpressionVariable::EVNeedsAllocation && + !(var_sp->m_flags & ClangExpressionVariable::EVKeepInTarget)) + { + if (m_keep_result_in_memory) + { + var_sp->m_flags |= ClangExpressionVariable::EVKeepInTarget; + } + else + { + Error deallocate_error = exe_ctx.process->DeallocateMemory(mem); + + if (!err.Success()) + { + err.SetErrorStringWithFormat ("Couldn't deallocate memory for %s: %s", var_sp->GetName().GetCString(), deallocate_error.AsCString()); + return false; + } + } + } + } + else + { + err.SetErrorStringWithFormat("Persistent variables without separate allocations are not currently supported."); return false; } } else { - if (exe_ctx.process->WriteMemory (addr, pvar_data, pvar_byte_size, error) != pvar_byte_size) + if (log) + log->Printf("Materializing persistent variable with flags 0x%hx", var_sp->m_flags); + + if (var_sp->m_flags & ClangExpressionVariable::EVNeedsAllocation) + { + // Allocate a spare memory area to store the persistent variable's contents. + + Error allocate_error; + + mem = exe_ctx.process->AllocateMemory(pvar_byte_size, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + allocate_error); + + if (mem == LLDB_INVALID_ADDRESS) + { + err.SetErrorStringWithFormat("Couldn't allocate a memory area to store %s: %s", var_sp->GetName().GetCString(), allocate_error.AsCString()); + return false; + } + + if (log) + log->Printf("Allocated %s (0x%llx) sucessfully", var_sp->GetName().GetCString(), mem); + + // Put the location of the spare memory into the live data of the ValueObject. + + var_sp->m_live_sp.reset(new lldb_private::ValueObjectConstResult(var_sp->GetTypeFromUser().GetASTContext(), + var_sp->GetTypeFromUser().GetOpaqueQualType(), + var_sp->GetName(), + mem, + lldb::eAddressTypeLoad, + pvar_byte_size)); + + // Clear the flag if the variable will never be deallocated. + + if (var_sp->m_flags & ClangExpressionVariable::EVKeepInTarget) + var_sp->m_flags &= ~ClangExpressionVariable::EVNeedsAllocation; + + // Write the contents of the variable to the area. + + if (exe_ctx.process->WriteMemory (mem, pvar_data, pvar_byte_size, error) != pvar_byte_size) + { + err.SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString()); + return false; + } + } + + if ((var_sp->m_flags & ClangExpressionVariable::EVIsProgramReference && var_sp->m_live_sp) || + var_sp->m_flags & ClangExpressionVariable::EVIsLLDBAllocated) { - err.SetErrorStringWithFormat ("Couldn't write a composite type to the target: %s", error.AsCString()); + mem = var_sp->m_live_sp->GetValue().GetScalar().ULongLong(); + + // Now write the location of the area into the struct. + + Error write_error; + if (!WriteAddressInto(exe_ctx, addr, mem, write_error)) + { + err.SetErrorStringWithFormat ("Couldn't write %s to the target: %s", var_sp->GetName().GetCString(), write_error.AsCString()); + return false; + } + + if (log) + log->Printf("Materialized %s into 0x%llx", var_sp->GetName().GetCString(), (uint64_t)mem); + } + else if (!var_sp->m_flags & ClangExpressionVariable::EVIsProgramReference) + { + err.SetErrorStringWithFormat("Persistent variables without separate allocations are not currently supported."); return false; } } @@ -835,8 +1066,7 @@ bool dematerialize, ExecutionContext &exe_ctx, const SymbolContext &sym_ctx, - const ConstString &name, - TypeFromUser type, + ClangExpressionVariableSP &expr_var, lldb::addr_t addr, Error &err ) @@ -846,6 +1076,11 @@ if (!exe_ctx.frame || !exe_ctx.process) return false; + // Vital information about the value + + const ConstString &name(expr_var->GetName()); + TypeFromUser type(expr_var->GetTypeFromUser()); + Variable *var = FindVariableInScope (*exe_ctx.frame, name, &type); if (!var) @@ -869,8 +1104,8 @@ // The size of the type contained in addr - size_t addr_bit_size = ClangASTType::GetClangTypeBitWidth(type.GetASTContext(), type.GetOpaqueQualType()); - size_t addr_byte_size = addr_bit_size % 8 ? ((addr_bit_size + 8) / 8) : (addr_bit_size / 8); + size_t value_bit_size = ClangASTType::GetClangTypeBitWidth(type.GetASTContext(), type.GetOpaqueQualType()); + size_t value_byte_size = value_bit_size % 8 ? ((value_bit_size + 8) / 8) : (value_bit_size / 8); Value::ValueType value_type = location_value->GetValueType(); @@ -888,40 +1123,21 @@ break; case Value::eValueTypeLoadAddress: { - lldb::addr_t value_addr = location_value->GetScalar().ULongLong(); - - DataBufferHeap data; - data.SetByteSize(addr_byte_size); - - lldb::addr_t src_addr; - lldb::addr_t dest_addr; - - if (dematerialize) - { - src_addr = addr; - dest_addr = value_addr; - } - else - { - src_addr = value_addr; - dest_addr = addr; - } - - Error error; - if (exe_ctx.process->ReadMemory (src_addr, data.GetBytes(), addr_byte_size, error) != addr_byte_size) - { - err.SetErrorStringWithFormat ("Couldn't read %s from the target: %s", name.GetCString(), error.AsCString()); - return false; - } - - if (exe_ctx.process->WriteMemory (dest_addr, data.GetBytes(), addr_byte_size, error) != addr_byte_size) + if (!dematerialize) { - err.SetErrorStringWithFormat ("Couldn't write %s to the target: %s", name.GetCString(), error.AsCString()); - return false; + lldb::addr_t value_addr = location_value->GetScalar().ULongLong(); + + Error error; + + if (!WriteAddressInto(exe_ctx, + addr, + value_addr, + error)) + { + err.SetErrorStringWithFormat ("Couldn't write %s to the target: %s", name.GetCString(), error.AsCString()); + return false; + } } - - if (log) - log->Printf("Copied from 0x%llx to 0x%llx", (uint64_t)src_addr, (uint64_t)addr); } break; case Value::eValueTypeScalar: @@ -929,13 +1145,14 @@ if (location_value->GetContextType() != Value::eContextTypeRegisterInfo) { StreamString ss; - location_value->Dump(&ss); err.SetErrorStringWithFormat("%s is a scalar of unhandled type: %s", name.GetCString(), ss.GetString().c_str()); return false; } + lldb::addr_t mem; // The address of a spare memory area aused to hold the variable. + lldb::RegisterInfo *register_info = location_value->GetRegisterInfo(); if (!register_info) @@ -957,6 +1174,22 @@ if (dematerialize) { + // Get the location of the spare memory area out of the variable's live data. + + if (!expr_var->m_live_sp) + { + err.SetErrorStringWithFormat("Couldn't find the memory area used to store %s", name.GetCString()); + return false; + } + + if (expr_var->m_live_sp->GetValue().GetValueAddressType() != lldb::eAddressTypeLoad) + { + err.SetErrorStringWithFormat("The address of the memory area for %s is in an incorrect format", name.GetCString()); + return false; + } + + mem = expr_var->m_live_sp->GetValue().GetScalar().ULongLong(); + // Moving from addr into a register // // Case 1: addr_byte_size and register_byte_size are the same @@ -974,7 +1207,7 @@ // |AABB0000| Register contents [on little-endian hardware] // |0000AABB| Register contents [on big-endian hardware] - if (addr_byte_size > register_byte_size) + if (value_byte_size > register_byte_size) { err.SetErrorStringWithFormat("%s is too big to store in %s", name.GetCString(), register_info->name); return false; @@ -991,14 +1224,14 @@ register_offset = 0; break; case lldb::eByteOrderBig: - register_offset = register_byte_size - addr_byte_size; + register_offset = register_byte_size - value_byte_size; break; } DataBufferHeap register_data (register_byte_size, 0); Error error; - if (exe_ctx.process->ReadMemory (addr, register_data.GetBytes() + register_offset, addr_byte_size, error) != addr_byte_size) + if (exe_ctx.process->ReadMemory (mem, register_data.GetBytes() + register_offset, value_byte_size, error) != value_byte_size) { err.SetErrorStringWithFormat ("Couldn't read %s from the target: %s", name.GetCString(), error.AsCString()); return false; @@ -1011,9 +1244,54 @@ err.SetErrorStringWithFormat("Couldn't read %s from %s", name.GetCString(), register_info->name); return false; } + + // Deallocate the spare area and clear the variable's live data. + + Error deallocate_error = exe_ctx.process->DeallocateMemory(mem); + + if (!deallocate_error.Success()) + { + err.SetErrorStringWithFormat("Couldn't deallocate spare memory area for %s: %s", name.GetCString(), deallocate_error.AsCString()); + return false; + } + + expr_var->m_live_sp.reset(); } else { + // Allocate a spare memory area to place the register's contents into. This memory area will be pointed to by the slot in the + // struct. + + Error allocate_error; + + mem = exe_ctx.process->AllocateMemory(value_byte_size, + lldb::ePermissionsReadable | lldb::ePermissionsWritable, + allocate_error); + + if (mem == LLDB_INVALID_ADDRESS) + { + err.SetErrorStringWithFormat("Couldn't allocate a memory area to store %s: %s", name.GetCString(), allocate_error.AsCString()); + return false; + } + + // Put the location of the spare memory into the live data of the ValueObject. + + expr_var->m_live_sp.reset(new lldb_private::ValueObjectConstResult(type.GetASTContext(), + type.GetOpaqueQualType(), + name, + mem, + lldb::eAddressTypeLoad, + value_byte_size)); + + // Now write the location of the area into the struct. + + Error write_error; + if (!WriteAddressInto(exe_ctx, addr, mem, write_error)) + { + err.SetErrorStringWithFormat ("Couldn't write %s to the target: %s", name.GetCString(), write_error.AsCString()); + return false; + } + // Moving from a register into addr // // Case 1: addr_byte_size and register_byte_size are the same @@ -1031,7 +1309,7 @@ // |AABB| Address contents on little-endian hardware // |CCDD| Address contents on big-endian hardware - if (addr_byte_size > register_byte_size) + if (value_byte_size > register_byte_size) { err.SetErrorStringWithFormat("%s is too big to store in %s", name.GetCString(), register_info->name); return false; @@ -1048,7 +1326,7 @@ register_offset = 0; break; case lldb::eByteOrderBig: - register_offset = register_byte_size - addr_byte_size; + register_offset = register_byte_size - value_byte_size; break; } @@ -1060,7 +1338,7 @@ return false; } - const void *register_data = register_extractor.GetData(®ister_offset, addr_byte_size); + const void *register_data = register_extractor.GetData(®ister_offset, value_byte_size); if (!register_data) { @@ -1068,10 +1346,9 @@ return false; } - Error error; - if (exe_ctx.process->WriteMemory (addr, register_data, addr_byte_size, error) != addr_byte_size) + if (exe_ctx.process->WriteMemory (mem, register_data, value_byte_size, write_error) != value_byte_size) { - err.SetErrorStringWithFormat ("Couldn't write %s to the target: %s", error.AsCString()); + err.SetErrorStringWithFormat ("Couldn't write %s to the target: %s", write_error.AsCString()); return false; } } @@ -1581,7 +1858,7 @@ if (!var_location) return; - NamedDecl *var_decl = context.AddVarDecl(pt.GetOpaqueQualType()); + NamedDecl *var_decl = context.AddVarDecl(ClangASTContext::CreateLValueReferenceType(pt.GetASTContext(), pt.GetOpaqueQualType())); std::string decl_name(context.m_decl_name.getAsString()); ConstString entity_name(decl_name.c_str()); ClangExpressionVariableSP entity(m_found_entities.CreateVariable (entity_name, @@ -1619,7 +1896,7 @@ user_type.GetOpaqueQualType()), context.GetASTContext()); - NamedDecl *var_decl = context.AddVarDecl(parser_type.GetOpaqueQualType()); + NamedDecl *var_decl = context.AddVarDecl(ClangASTContext::CreateLValueReferenceType(parser_type.GetASTContext(), parser_type.GetOpaqueQualType())); pvar_sp->EnableParserVars(); pvar_sp->m_parser_vars->m_parser_type = parser_type; Modified: lldb/trunk/source/Expression/ClangExpressionVariable.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionVariable.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangExpressionVariable.cpp (original) +++ lldb/trunk/source/Expression/ClangExpressionVariable.cpp Thu Jan 13 02:53:35 2011 @@ -28,14 +28,16 @@ ClangExpressionVariable::ClangExpressionVariable(lldb::ByteOrder byte_order, uint32_t addr_byte_size) : m_parser_vars(), m_jit_vars (), - m_valojb_sp (new ValueObjectConstResult(byte_order, addr_byte_size)) + m_frozen_sp (new ValueObjectConstResult(byte_order, addr_byte_size)), + m_flags (EVNone) { } ClangExpressionVariable::ClangExpressionVariable (const lldb::ValueObjectSP &valobj_sp) : m_parser_vars(), m_jit_vars (), - m_valojb_sp (valobj_sp) + m_frozen_sp (valobj_sp), + m_flags (EVNone) { } @@ -45,76 +47,76 @@ size_t ClangExpressionVariable::GetByteSize () { - return m_valojb_sp->GetByteSize(); + return m_frozen_sp->GetByteSize(); } const ConstString & ClangExpressionVariable::GetName () { - return m_valojb_sp->GetName(); + return m_frozen_sp->GetName(); } lldb::ValueObjectSP ClangExpressionVariable::GetValueObject() { - return m_valojb_sp; + return m_frozen_sp; } lldb::RegisterInfo * ClangExpressionVariable::GetRegisterInfo() { - return m_valojb_sp->GetValue().GetRegisterInfo(); + return m_frozen_sp->GetValue().GetRegisterInfo(); } void ClangExpressionVariable::SetRegisterInfo (const lldb::RegisterInfo *reg_info) { - return m_valojb_sp->GetValue().SetContext (Value::eContextTypeRegisterInfo, const_cast(reg_info)); + return m_frozen_sp->GetValue().SetContext (Value::eContextTypeRegisterInfo, const_cast(reg_info)); } lldb::clang_type_t ClangExpressionVariable::GetClangType() { - return m_valojb_sp->GetClangType(); + return m_frozen_sp->GetClangType(); } void ClangExpressionVariable::SetClangType(lldb::clang_type_t clang_type) { - m_valojb_sp->GetValue().SetContext(Value::eContextTypeClangType, clang_type); + m_frozen_sp->GetValue().SetContext(Value::eContextTypeClangType, clang_type); } clang::ASTContext * ClangExpressionVariable::GetClangAST() { - return m_valojb_sp->GetClangAST(); + return m_frozen_sp->GetClangAST(); } void ClangExpressionVariable::SetClangAST (clang::ASTContext *ast) { - m_valojb_sp->SetClangAST (ast); + m_frozen_sp->SetClangAST (ast); } TypeFromUser ClangExpressionVariable::GetTypeFromUser() { - TypeFromUser tfu (m_valojb_sp->GetClangType(), m_valojb_sp->GetClangAST()); + TypeFromUser tfu (m_frozen_sp->GetClangType(), m_frozen_sp->GetClangAST()); return tfu; } uint8_t * ClangExpressionVariable::GetValueBytes() { - const size_t byte_size = m_valojb_sp->GetByteSize(); + const size_t byte_size = m_frozen_sp->GetByteSize(); if (byte_size > 0) { - if (m_valojb_sp->GetDataExtractor().GetByteSize() < byte_size) + if (m_frozen_sp->GetDataExtractor().GetByteSize() < byte_size) { - m_valojb_sp->GetValue().ResizeData(byte_size); - m_valojb_sp->GetValue().GetData (m_valojb_sp->GetDataExtractor()); + m_frozen_sp->GetValue().ResizeData(byte_size); + m_frozen_sp->GetValue().GetData (m_frozen_sp->GetDataExtractor()); } - return const_cast(m_valojb_sp->GetDataExtractor().GetDataStart()); + return const_cast(m_frozen_sp->GetDataExtractor().GetDataStart()); } return NULL; } @@ -122,12 +124,12 @@ void ClangExpressionVariable::SetName (const ConstString &name) { - m_valojb_sp->SetName (name); + m_frozen_sp->SetName (name); } void ClangExpressionVariable::ValueUpdated () { - m_valojb_sp->ValueUpdated (); + m_frozen_sp->ValueUpdated (); } Modified: lldb/trunk/source/Expression/ClangUserExpression.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangUserExpression.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangUserExpression.cpp (original) +++ lldb/trunk/source/Expression/ClangUserExpression.cpp Thu Jan 13 02:53:35 2011 @@ -144,6 +144,7 @@ ClangUserExpression::Parse (Stream &error_stream, ExecutionContext &exe_ctx, TypeFromUser desired_type, + bool keep_result_in_memory, lldb::ClangExpressionVariableSP *const_result) { lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); @@ -248,7 +249,7 @@ m_desired_type = desired_type; - m_expr_decl_map.reset(new ClangExpressionDeclMap()); + m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory)); m_expr_decl_map->WillParse(exe_ctx); @@ -398,7 +399,7 @@ ThreadPlan * ClangUserExpression::GetThreadPlanToExecuteJITExpression (Stream &error_stream, - ExecutionContext &exe_ctx) + ExecutionContext &exe_ctx) { lldb::addr_t struct_address; @@ -460,6 +461,7 @@ ClangUserExpression::Execute (Stream &error_stream, ExecutionContext &exe_ctx, bool discard_on_error, + bool keep_in_memory, ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me, lldb::ClangExpressionVariableSP &result) { @@ -556,6 +558,7 @@ lldb::ExecutionResults ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, bool discard_on_error, + bool keep_in_memory, const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp) @@ -619,7 +622,7 @@ { lldb::ClangExpressionVariableSP expr_result; - if (const_result.get()) + if (const_result.get() && !keep_in_memory) { if (log) log->Printf("== [ClangUserExpression::Evaluate] Expression evaluated as a constant =="); @@ -635,7 +638,8 @@ execution_results = user_expression_sp->Execute (error_stream, exe_ctx, - discard_on_error, + discard_on_error, + keep_in_memory, user_expression_sp, expr_result); Modified: lldb/trunk/source/Expression/ClangUtilityFunction.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangUtilityFunction.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangUtilityFunction.cpp (original) +++ lldb/trunk/source/Expression/ClangUtilityFunction.cpp Thu Jan 13 02:53:35 2011 @@ -99,7 +99,9 @@ // Parse the expression // - m_expr_decl_map.reset(new ClangExpressionDeclMap()); + bool keep_result_in_memory = false; + + m_expr_decl_map.reset(new ClangExpressionDeclMap(keep_result_in_memory)); m_expr_decl_map->WillParse(exe_ctx); Modified: lldb/trunk/source/Expression/IRForTarget.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRForTarget.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Expression/IRForTarget.cpp (original) +++ lldb/trunk/source/Expression/IRForTarget.cpp Thu Jan 13 02:53:35 2011 @@ -43,7 +43,8 @@ m_func_name(func_name), m_resolve_vars(resolve_vars), m_const_result(const_result), - m_has_side_effects(NULL) + m_has_side_effects(false), + m_result_is_pointer(false) { } @@ -153,10 +154,19 @@ vi != ve; ++vi) { + if (strstr(vi->first(), "$__lldb_expr_result_ptr") && + !strstr(vi->first(), "GV")) + { + result_name = vi->first(); + m_result_is_pointer = true; + break; + } + if (strstr(vi->first(), "$__lldb_expr_result") && !strstr(vi->first(), "GV")) { result_name = vi->first(); + m_result_is_pointer = false; break; } } @@ -178,7 +188,7 @@ { if (log) log->PutCString("Result variable had no data"); - + return false; } @@ -240,14 +250,43 @@ // Get the next available result name from m_decl_map and create the persistent // variable for it - lldb_private::TypeFromParser result_decl_type (result_decl->getType().getAsOpaquePtr(), - &result_decl->getASTContext()); - - lldb_private::ConstString new_result_name (m_decl_map->GetPersistentResultName()); - m_decl_map->AddPersistentVariable(result_decl, new_result_name, result_decl_type); + lldb_private::TypeFromParser result_decl_type; + + if (m_result_is_pointer) + { + clang::QualType pointer_qual_type = result_decl->getType(); + clang::Type *pointer_type = pointer_qual_type.getTypePtr(); + clang::PointerType *pointer_pointertype = dyn_cast(pointer_type); + + if (!pointer_pointertype) + { + if (log) + log->PutCString("Expected result to have pointer type, but it did not"); + return false; + } + + clang::QualType element_qual_type = pointer_pointertype->getPointeeType(); + + result_decl_type = lldb_private::TypeFromParser(element_qual_type.getAsOpaquePtr(), + &result_decl->getASTContext()); + } + else + { + result_decl_type = lldb_private::TypeFromParser(result_decl->getType().getAsOpaquePtr(), + &result_decl->getASTContext()); + } + + m_result_name = m_decl_map->GetPersistentResultName(); + // If the result is an Lvalue, it is emitted as a pointer; see + // ASTResultSynthesizer::SynthesizeBodyResult. + m_decl_map->AddPersistentVariable(result_decl, + m_result_name, + result_decl_type, + true, + m_result_is_pointer); if (log) - log->Printf("Creating a new result global: \"%s\"", new_result_name.GetCString()); + log->Printf("Creating a new result global: \"%s\"", m_result_name.GetCString()); // Construct a new result global and set up its metadata @@ -256,7 +295,7 @@ false, /* not constant */ GlobalValue::ExternalLinkage, NULL, /* no initializer */ - new_result_name.GetCString ()); + m_result_name.GetCString ()); // It's too late in compilation to create a new VarDecl for this, but we don't // need to. We point the metadata at the old VarDecl. This creates an odd @@ -307,7 +346,7 @@ if (!m_has_side_effects) { MaybeSetConstantResult (initializer, - new_result_name, + m_result_name, result_decl_type); } @@ -800,7 +839,7 @@ StringRef decl_name (decl->getName()); lldb_private::ConstString persistent_variable_name (decl_name.data(), decl_name.size()); - if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name, result_decl_type)) + if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name, result_decl_type, false, false)) return false; GlobalVariable *persistent_global = new GlobalVariable(llvm_module, @@ -964,9 +1003,27 @@ return false; } - clang::QualType qual_type(clang::QualType::getFromOpaquePtr(opaque_type)); + clang::QualType qual_type; + const Type *value_type; + + if (!name.compare("$__lldb_expr_result")) + { + // The $__lldb_expr_result name indicates the the return value has allocated as + // a static variable. Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, + // accesses to this static variable need to be redirected to the result of dereferencing + // a pointer that is passed in as one of the arguments. + // + // Consequently, when reporting the size of the type, we report a pointer type pointing + // to the type of $__lldb_expr_result, not the type itself. - const Type *value_type = global_variable->getType(); + qual_type = ast_context->getPointerType(clang::QualType::getFromOpaquePtr(opaque_type)); + value_type = PointerType::get(global_variable->getType(), 0); + } + else + { + qual_type = clang::QualType::getFromOpaquePtr(opaque_type); + value_type = global_variable->getType(); + } size_t value_size = (ast_context->getTypeSize(qual_type) + 7) / 8; off_t value_alignment = (ast_context->getTypeAlign(qual_type) + 7) / 8; @@ -1479,12 +1536,31 @@ ConstantInt *offset_int(ConstantInt::getSigned(offset_type, offset)); GetElementPtrInst *get_element_ptr = GetElementPtrInst::Create(argument, offset_int, "", FirstEntryInstruction); - BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", FirstEntryInstruction); + + Value *replacement; + + // Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, in cases where the result + // variable is an rvalue, we have to synthesize a dereference of the appropriate structure + // entry in order to produce the static variable that the AST thinks it is accessing. + if (name == m_result_name && !m_result_is_pointer) + { + BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType()->getPointerTo(), "", FirstEntryInstruction); + LoadInst *load = new LoadInst(bit_cast, "", FirstEntryInstruction); + + replacement = load; + } + else + { + BitCastInst *bit_cast = new BitCastInst(get_element_ptr, value->getType(), "", FirstEntryInstruction); + + replacement = bit_cast; + } + if (Constant *constant = dyn_cast(value)) - UnfoldConstant(constant, bit_cast, FirstEntryInstruction); + UnfoldConstant(constant, replacement, FirstEntryInstruction); else - value->replaceAllUsesWith(bit_cast); + value->replaceAllUsesWith(replacement); if (GlobalVariable *var = dyn_cast(value)) var->eraseFromParent(); @@ -1507,7 +1583,7 @@ { if (log) log->Printf("Couldn't find \"%s()\" in the module", m_func_name.c_str()); - + return false; } Modified: lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp Thu Jan 13 02:53:35 2011 @@ -859,7 +859,7 @@ StringExtractorGDBRemote response; if (SendPacketAndWaitForResponse (packet, response, timeout_seconds, false)) { - if (!response.IsOKPacket()) + if (response.IsOKPacket()) return true; } return false; Modified: lldb/trunk/source/Symbol/ClangASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTContext.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp (original) +++ lldb/trunk/source/Symbol/ClangASTContext.cpp Thu Jan 13 02:53:35 2011 @@ -3615,18 +3615,20 @@ } clang_type_t -ClangASTContext::CreateLValueReferenceType (clang_type_t clang_type) +ClangASTContext::CreateLValueReferenceType (clang::ASTContext *ast, + clang_type_t clang_type) { if (clang_type) - return getASTContext()->getLValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return ast->getLValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); return NULL; } clang_type_t -ClangASTContext::CreateRValueReferenceType (clang_type_t clang_type) +ClangASTContext::CreateRValueReferenceType (clang::ASTContext *ast, + clang_type_t clang_type) { if (clang_type) - return getASTContext()->getRValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); + return ast->getRValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr(); return NULL; } Modified: lldb/trunk/source/Target/Process.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Target/Process.cpp (original) +++ lldb/trunk/source/Target/Process.cpp Thu Jan 13 02:53:35 2011 @@ -709,13 +709,14 @@ ExecutionContext exe_ctx; frame_sp->CalculateExecutionContext (exe_ctx); bool unwind_on_error = true; + bool keep_in_memory = false; StreamString expr; char path[PATH_MAX]; image_spec.GetPath(path, sizeof(path)); expr.Printf("dlopen (\"%s\", 2)", path); const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n"; lldb::ValueObjectSP result_valobj_sp; - ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix, result_valobj_sp); + ClangUserExpression::Evaluate (exe_ctx, keep_in_memory, unwind_on_error, expr.GetData(), prefix, result_valobj_sp); if (result_valobj_sp->GetError().Success()) { Scalar scalar; @@ -776,11 +777,12 @@ ExecutionContext exe_ctx; frame_sp->CalculateExecutionContext (exe_ctx); bool unwind_on_error = true; + bool keep_in_memory = false; StreamString expr; expr.Printf("dlclose ((void *)0x%llx)", image_addr); const char *prefix = "extern \"C\" int dlclose(void* handle);\n"; lldb::ValueObjectSP result_valobj_sp; - ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, expr.GetData(), prefix, result_valobj_sp); + ClangUserExpression::Evaluate (exe_ctx, unwind_on_error, keep_in_memory, expr.GetData(), prefix, result_valobj_sp); if (result_valobj_sp->GetError().Success()) { Scalar scalar; Modified: lldb/trunk/source/Target/Target.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=123371&r1=123370&r2=123371&view=diff ============================================================================== --- lldb/trunk/source/Target/Target.cpp (original) +++ lldb/trunk/source/Target/Target.cpp Thu Jan 13 02:53:35 2011 @@ -910,6 +910,7 @@ const char *expr_cstr, StackFrame *frame, bool unwind_on_error, + bool keep_in_memory, lldb::ValueObjectSP &result_valobj_sp ) { @@ -952,10 +953,32 @@ const_valobj_sp = result_valobj_sp->CreateConstantValue (exe_ctx.GetBestExecutionContextScope(), persistent_variable_name); + lldb::ValueObjectSP live_valobj_sp = result_valobj_sp; + result_valobj_sp = const_valobj_sp; - ClangExpressionVariableSP clang_expr_variable_sp(m_persistent_variables.CreatePersistentVariable(result_valobj_sp)); - assert (clang_expr_variable_sp.get()); + ClangExpressionVariableSP clang_expr_variable_sp(m_persistent_variables.CreatePersistentVariable(result_valobj_sp)); + assert (clang_expr_variable_sp.get()); + + // Set flags and live data as appropriate + + const Value &result_value = live_valobj_sp->GetValue(); + + switch (result_value.GetValueType()) + { + case Value::eValueTypeHostAddress: + case Value::eValueTypeFileAddress: + // we don't do anything with these for now + break; + case Value::eValueTypeScalar: + clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; + clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation; + break; + case Value::eValueTypeLoadAddress: + clang_expr_variable_sp->m_live_sp = live_valobj_sp; + clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference; + break; + } } else { @@ -976,7 +999,8 @@ const char *prefix = GetExpressionPrefixContentsAsCString(); execution_results = ClangUserExpression::Evaluate (exe_ctx, - unwind_on_error, + unwind_on_error, + keep_in_memory, expr_cstr, prefix, result_valobj_sp); From scallanan at apple.com Thu Jan 13 15:23:32 2011 From: scallanan at apple.com (Sean Callanan) Date: Thu, 13 Jan 2011 21:23:32 -0000 Subject: [Lldb-commits] [lldb] r123398 - in /lldb/trunk/source/Expression: ClangExpressionDeclMap.cpp IRForTarget.cpp Message-ID: <20110113212332.C550A2A6C12C@llvm.org> Author: spyffe Date: Thu Jan 13 15:23:32 2011 New Revision: 123398 URL: http://llvm.org/viewvc/llvm-project?rev=123398&view=rev Log: Fixed handling of explicitly-declared persistent variables. Modified: lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp lldb/trunk/source/Expression/IRForTarget.cpp Modified: lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp?rev=123398&r1=123397&r2=123398&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp (original) +++ lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp Thu Jan 13 15:23:32 2011 @@ -213,7 +213,7 @@ TypeFromUser user_type(ClangASTContext::CopyType(context, parser_type.GetASTContext(), parser_type.GetOpaqueQualType()), - context); + context); if (!m_parser_vars->m_persistent_vars->CreatePersistentVariable (name, user_type, @@ -939,7 +939,8 @@ return false; } - if (var_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry) + if (var_sp->m_flags & ClangExpressionVariable::EVNeedsFreezeDry || + var_sp->m_flags & ClangExpressionVariable::EVKeepInTarget) { mem = var_sp->m_live_sp->GetValue().GetScalar().ULongLong(); Modified: lldb/trunk/source/Expression/IRForTarget.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/IRForTarget.cpp?rev=123398&r1=123397&r2=123398&view=diff ============================================================================== --- lldb/trunk/source/Expression/IRForTarget.cpp (original) +++ lldb/trunk/source/Expression/IRForTarget.cpp Thu Jan 13 15:23:32 2011 @@ -816,6 +816,8 @@ IRForTarget::RewritePersistentAlloc (llvm::Instruction *persistent_alloc, llvm::Module &llvm_module) { + lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + AllocaInst *alloc = dyn_cast(persistent_alloc); MDNode *alloc_md = alloc->getMetadata("clang.decl.ptr"); @@ -842,8 +844,8 @@ if (!m_decl_map->AddPersistentVariable(decl, persistent_variable_name, result_decl_type, false, false)) return false; - GlobalVariable *persistent_global = new GlobalVariable(llvm_module, - alloc->getType()->getElementType(), + GlobalVariable *persistent_global = new GlobalVariable(llvm_module, + alloc->getType(), false, /* not constant */ GlobalValue::ExternalLinkage, NULL, /* no initializer */ @@ -861,7 +863,17 @@ MDNode *persistent_global_md = MDNode::get(llvm_module.getContext(), values, 2); named_metadata->addOperand(persistent_global_md); - alloc->replaceAllUsesWith(persistent_global); + // Now, since the variable is a pointer variable, we will drop in a load of that + // pointer variable. + + LoadInst *persistent_load = new LoadInst (persistent_global, "", alloc); + + if (log) + log->Printf("Replacing \"%s\" with \"%s\"", + PrintValue(alloc).c_str(), + PrintValue(persistent_load).c_str()); + + alloc->replaceAllUsesWith(persistent_load); alloc->eraseFromParent(); return true; @@ -1006,7 +1018,7 @@ clang::QualType qual_type; const Type *value_type; - if (!name.compare("$__lldb_expr_result")) + if (name[0] == '$') { // The $__lldb_expr_result name indicates the the return value has allocated as // a static variable. Per the comment at ASTResultSynthesizer::SynthesizeBodyResult, @@ -1015,6 +1027,8 @@ // // Consequently, when reporting the size of the type, we report a pointer type pointing // to the type of $__lldb_expr_result, not the type itself. + // + // We also do this for any user-declared persistent variables. qual_type = ast_context->getPointerType(clang::QualType::getFromOpaquePtr(opaque_type)); value_type = PointerType::get(global_variable->getType(), 0); @@ -1029,7 +1043,7 @@ off_t value_alignment = (ast_context->getTypeAlign(qual_type) + 7) / 8; if (log) - log->Printf("Type of \"%s\" is [clang \"%s\", lldb \"%s\"] [size %d, align %d]", + log->Printf("Type of \"%s\" is [clang \"%s\", llvm \"%s\"] [size %d, align %d]", name.c_str(), qual_type.getAsString().c_str(), PrintType(value_type).c_str(), From ctice at apple.com Thu Jan 13 18:29:17 2011 From: ctice at apple.com (Caroline Tice) Date: Fri, 14 Jan 2011 00:29:17 -0000 Subject: [Lldb-commits] [lldb] r123415 - in /lldb/trunk: include/lldb/Core/ include/lldb/Interpreter/ scripts/ source/ source/Core/ source/Interpreter/ Message-ID: <20110114002917.31F182A6C12C@llvm.org> Author: ctice Date: Thu Jan 13 18:29:16 2011 New Revision: 123415 URL: http://llvm.org/viewvc/llvm-project?rev=123415&view=rev Log: Split up the Python script interpreter code to allow multiple script interpreter objects to exist within the same process (one script interpreter object per debugger object). The python script interpreter objects are all using the same global Python script interpreter; they use separate dictionaries to keep their data separate, and mutex's to prevent any object attempting to use the global Python interpreter when another object is already using it. Modified: lldb/trunk/include/lldb/Core/Debugger.h lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h lldb/trunk/scripts/lldb.swig lldb/trunk/source/Core/Debugger.cpp lldb/trunk/source/Interpreter/CommandInterpreter.cpp lldb/trunk/source/Interpreter/CommandObjectScript.cpp lldb/trunk/source/Interpreter/CommandObjectScript.h lldb/trunk/source/Interpreter/ScriptInterpreter.cpp lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp lldb/trunk/source/Interpreter/embedded_interpreter.py lldb/trunk/source/lldb.cpp Modified: lldb/trunk/include/lldb/Core/Debugger.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/Debugger.h (original) +++ lldb/trunk/include/lldb/Core/Debugger.h Thu Jan 13 18:29:16 2011 @@ -166,7 +166,6 @@ m_auto_confirm_on = auto_confirm_on; } - protected: void @@ -375,6 +374,9 @@ void CleanUpInputReaders (); + static int + TestDebuggerRefCount (); + protected: static void Modified: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h (original) +++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h Thu Jan 13 18:29:16 2011 @@ -262,6 +262,7 @@ OptionArgMap m_alias_options; // Stores any options (with or without arguments) that go with any alias. std::vector m_command_history; std::string m_repeat_command; // Stores the command that will be executed for an empty command string. + std::auto_ptr m_script_interpreter_ap; }; Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h (original) +++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h Thu Jan 13 18:29:16 2011 @@ -90,16 +90,23 @@ int GetMasterFileDescriptor (); - CommandInterpreter * - GetCommandInterpreter (); + CommandInterpreter & + GetCommandInterpreter (); - static std::string - LanguageToString (lldb::ScriptLanguage); + static std::string + LanguageToString (lldb::ScriptLanguage language); + + static void + Initialize (); + + static void + Terminate (); + + virtual void + ResetOutputFileHandle (FILE *new_fh) { } //By default, do nothing. protected: CommandInterpreter &m_interpreter; - -private: lldb::ScriptLanguage m_script_lang; // Scripting languages may need to use stdin for their interactive loops; @@ -108,8 +115,11 @@ // embedded scripting loops. Therefore we need to set up a pseudoterminal and use that // as stdin for the script interpreter interactive loops/prompts. - lldb_utility::PseudoTerminal m_interpreter_pty; - std::string m_pty_slave_name; + lldb_utility::PseudoTerminal m_interpreter_pty; // m_session_pty + std::string m_pty_slave_name; //m_session_pty_slave_name + +private: + }; } // namespace lldb_private Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h (original) +++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h Thu Jan 13 18:29:16 2011 @@ -11,6 +11,12 @@ #ifndef liblldb_ScriptInterpreterPython_h_ #define liblldb_ScriptInterpreterPython_h_ +#if defined (__APPLE__) +#include +#else +#include +#endif + #include "lldb/lldb-private.h" #include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Core/InputReader.h" @@ -70,9 +76,26 @@ StringList ReadCommandInputFromUser (FILE *in_file); + virtual void + ResetOutputFileHandle (FILE *new_fh); + static lldb::thread_result_t RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton); + static void + Initialize (); + + static void + Terminate (); + +protected: + + void + EnterSession (); + + void + LeaveSession (); + private: static size_t @@ -81,12 +104,19 @@ lldb::InputReaderAction notification, const char *bytes, size_t bytes_len); - - void *m_compiled_module; - struct termios m_termios; - bool m_termios_valid; + + lldb_utility::PseudoTerminal m_embedded_python_pty; lldb::InputReaderSP m_embedded_thread_input_reader_sp; + FILE *m_dbg_stdout; + PyObject *m_new_sysout; + std::string m_dictionary_name; + struct termios m_termios; + bool m_termios_valid; + bool m_session_is_active; + bool m_pty_slave_is_open; + bool m_valid_session; + }; } // namespace lldb_private Modified: lldb/trunk/scripts/lldb.swig URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/lldb.swig?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/scripts/lldb.swig (original) +++ lldb/trunk/scripts/lldb.swig Thu Jan 13 18:29:16 2011 @@ -1,8 +1,6 @@ /* lldb.swig - Created by Caroline Tice 1/18/2010 - This is the input file for SWIG, to create the appropriate C++ wrappers and functions for various scripting languages, to enable them to call the liblldb Script Bridge functions. @@ -151,6 +149,7 @@ LLDBSWIGPythonBreakpointCallbackFunction ( const char *python_function_name, + const char *session_dictionary_name, lldb::SBFrame& sb_frame, lldb::SBBreakpointLocation& sb_bp_loc ) @@ -161,20 +160,70 @@ if (Frame_PyObj == NULL || Bp_Loc_PyObj == NULL) return stop_at_breakpoint; + + if (!python_function_name || !session_dictionary_name) + return stop_at_breakpoint; - PyObject *pmodule, *pdict, *pfunc; + PyObject *pmodule, *main_dict, *session_dict, *pfunc; PyObject *pargs, *pvalue; pmodule = PyImport_AddModule ("__main__"); if (pmodule != NULL) { - pdict = PyModule_GetDict (pmodule); - if (pdict != NULL) + main_dict = PyModule_GetDict (pmodule); + if (main_dict != NULL) { - pfunc = PyObject_GetAttrString (pmodule, python_function_name); + PyObject *key, *value; + Py_ssize_t pos = 0; + + // Find the current session's dictionary in the main module's dictionary. + + if (PyDict_Check (main_dict)) + + { + session_dict = NULL; + while (PyDict_Next (main_dict, &pos, &key, &value)) + { + // We have stolen references to the key and value objects in the dictionary; we need to increment + // them now so that Python's garbage collector doesn't collect them out from under us. + Py_INCREF (key); + Py_INCREF (value); + if (strcmp (PyString_AsString (key), session_dictionary_name) == 0) + { + session_dict = value; + break; + } + } + } + + if (!session_dict || !PyDict_Check (session_dict)) + return stop_at_breakpoint; + + // Find the function we need to call in the current session's dictionary. + + pos = 0; + pfunc = NULL; + while (PyDict_Next (session_dict, &pos, &key, &value)) + { + if (PyString_Check (key)) + { + // We have stolen references to the key and value objects in the dictionary; we need to increment + // them now so that Python's garbage collector doesn't collect them out from under us. + Py_INCREF (key); + Py_INCREF (value); + if (strcmp (PyString_AsString (key), python_function_name) == 0) + { + pfunc = value; + break; + } + } + } + + // Set up the arguments and call the function. + if (pfunc && PyCallable_Check (pfunc)) { - pargs = PyTuple_New (2); + pargs = PyTuple_New (3); if (pargs == NULL) { if (PyErr_Occurred()) @@ -184,6 +233,7 @@ PyTuple_SetItem (pargs, 0, Frame_PyObj); // This "steals" a reference to Frame_PyObj PyTuple_SetItem (pargs, 1, Bp_Loc_PyObj); // This "steals" a reference to Bp_Loc_PyObj + PyTuple_SetItem (pargs, 2, session_dict); // This "steals" a reference to session_dict pvalue = PyObject_CallObject (pfunc, pargs); Py_DECREF (pargs); @@ -195,7 +245,7 @@ { PyErr_Clear(); } - Py_DECREF (pfunc); + Py_INCREF (session_dict); } else if (PyErr_Occurred()) { Modified: lldb/trunk/source/Core/Debugger.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/Core/Debugger.cpp (original) +++ lldb/trunk/source/Core/Debugger.cpp Thu Jan 13 18:29:16 2011 @@ -59,6 +59,12 @@ return g_settings_controller; } +int +Debugger::TestDebuggerRefCount () +{ + return g_shared_debugger_refcount; +} + void Debugger::Initialize () { @@ -252,6 +258,8 @@ m_output_file.SetFileHandle (fh, tranfer_ownership); if (m_output_file.GetFileHandle() == NULL) m_output_file.SetFileHandle (stdin, false); + + GetCommandInterpreter().GetScriptInterpreter()->ResetOutputFileHandle (fh); } FILE * Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original) +++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Thu Jan 13 18:29:16 2011 @@ -50,6 +50,8 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreterNone.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" using namespace lldb; using namespace lldb_private; @@ -63,7 +65,8 @@ Broadcaster ("lldb.command-interpreter"), m_debugger (debugger), m_synchronous_execution (synchronous_execution), - m_skip_lldbinit_files (false) + m_skip_lldbinit_files (false), + m_script_interpreter_ap () { const char *dbg_name = debugger.GetInstanceName().AsCString(); std::string lang_name = ScriptInterpreter::LanguageToString (script_language); @@ -1460,15 +1463,23 @@ ScriptInterpreter * CommandInterpreter::GetScriptInterpreter () { - CommandObject::CommandMap::iterator pos; + if (m_script_interpreter_ap.get() != NULL) + return m_script_interpreter_ap.get(); - pos = m_command_dict.find ("script"); - if (pos != m_command_dict.end()) + lldb::ScriptLanguage script_lang = GetDebugger().GetScriptLanguage(); + switch (script_lang) { - CommandObject *script_cmd_obj = pos->second.get(); - return ((CommandObjectScript *) script_cmd_obj)->GetInterpreter (); - } - return NULL; + case eScriptLanguageNone: + m_script_interpreter_ap.reset (new ScriptInterpreterNone (*this)); + break; + case eScriptLanguagePython: + m_script_interpreter_ap.reset (new ScriptInterpreterPython (*this)); + break; + default: + break; + }; + + return m_script_interpreter_ap.get(); } Modified: lldb/trunk/source/Interpreter/CommandObjectScript.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandObjectScript.cpp?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/CommandObjectScript.cpp (original) +++ lldb/trunk/source/Interpreter/CommandObjectScript.cpp Thu Jan 13 18:29:16 2011 @@ -17,8 +17,7 @@ #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/ScriptInterpreter.h" -#include "lldb/Interpreter/ScriptInterpreterPython.h" -#include "lldb/Interpreter/ScriptInterpreterNone.h" +#include "lldb/Interpreter/CommandInterpreter.h" using namespace lldb; using namespace lldb_private; @@ -32,8 +31,7 @@ "script", "Pass an expression to the script interpreter for evaluation and return the results. Drop into the interactive interpreter if no expression is given.", "script []"), - m_script_lang (script_lang), - m_interpreter_ap () + m_script_lang (script_lang) { } @@ -48,7 +46,7 @@ CommandReturnObject &result ) { - ScriptInterpreter *script_interpreter = GetInterpreter (); + ScriptInterpreter *script_interpreter = m_interpreter.GetScriptInterpreter (); if (script_interpreter == NULL) { @@ -88,22 +86,3 @@ return false; } - -ScriptInterpreter * -CommandObjectScript::GetInterpreter () -{ - if (m_interpreter_ap.get() == NULL) - { - switch (m_script_lang) - { - case eScriptLanguagePython: - m_interpreter_ap.reset (new ScriptInterpreterPython (m_interpreter)); - break; - - case eScriptLanguageNone: - m_interpreter_ap.reset (new ScriptInterpreterNone (m_interpreter)); - break; - } - } - return m_interpreter_ap.get(); -} Modified: lldb/trunk/source/Interpreter/CommandObjectScript.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandObjectScript.h?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/CommandObjectScript.h (original) +++ lldb/trunk/source/Interpreter/CommandObjectScript.h Thu Jan 13 18:29:16 2011 @@ -42,12 +42,8 @@ Execute (Args& command, CommandReturnObject &result); - ScriptInterpreter * - GetInterpreter (); - private: lldb::ScriptLanguage m_script_lang; - std::auto_ptr m_interpreter_ap; }; } // namespace lldb_private Modified: lldb/trunk/source/Interpreter/ScriptInterpreter.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreter.cpp?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/ScriptInterpreter.cpp (original) +++ lldb/trunk/source/Interpreter/ScriptInterpreter.cpp Thu Jan 13 18:29:16 2011 @@ -17,15 +17,17 @@ #include "lldb/Core/Stream.h" #include "lldb/Core/StringList.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/Interpreter/ScriptInterpreterPython.h" #include "lldb/Utility/PseudoTerminal.h" using namespace lldb; using namespace lldb_private; -ScriptInterpreter::ScriptInterpreter (CommandInterpreter &interpreter, ScriptLanguage script_lang) : +ScriptInterpreter::ScriptInterpreter (CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang) : m_interpreter (interpreter), m_script_lang (script_lang), - m_interpreter_pty () + m_interpreter_pty (), + m_pty_slave_name () { if (m_interpreter_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, NULL, 0)) { @@ -40,6 +42,12 @@ m_interpreter_pty.CloseMasterFileDescriptor(); } +CommandInterpreter & +ScriptInterpreter::GetCommandInterpreter () +{ + return m_interpreter; +} + const char * ScriptInterpreter::GetScriptInterpreterPtyName () { @@ -81,3 +89,16 @@ return return_value; } + +void +ScriptInterpreter::Initialize () +{ + ScriptInterpreterPython::Initialize (); +} + +void +ScriptInterpreter::Terminate () +{ + ScriptInterpreterPython::Terminate (); +} + Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original) +++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Thu Jan 13 18:29:16 2011 @@ -52,6 +52,7 @@ LLDBSWIGPythonBreakpointCallbackFunction ( const char *python_function_name, + const char *session_dictionary_name, lldb::SBFrame& sb_frame, lldb::SBBreakpointLocation& sb_bp_loc ); @@ -146,10 +147,22 @@ if not more:\n\ break\n\ \n\ + def one_line (self, input):\n\ + line = self.process_input (input)\n\ + more = self.push(line)\n\ + if more:\n\ + self.write (\"Input not a complete line.\")\n\ + self.resetbuffer()\n\ + more = 0\n\ +\n\ def run_python_interpreter (dict):\n\ # Pass in the dictionary, for continuity from one session to the next.\n\ repl = SimpleREPL('>>> ', dict)\n\ - repl.interact()\n"; + repl.interact()\n\ +\n\ +def run_one_line (dict, input_string):\n\ + repl = SimpleREPL ('', dict)\n\ + repl.one_line (input_string)\n"; static int _check_and_flush (FILE *stream) @@ -158,146 +171,171 @@ return fflush (stream) || prev_fail ? EOF : 0; } +static Mutex & +GetPythonMutex () +{ + static Mutex g_python_mutex (Mutex::eMutexTypeRecursive); + return g_python_mutex; +} + ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) : ScriptInterpreter (interpreter, eScriptLanguagePython), - m_compiled_module (NULL), + m_embedded_python_pty (), + m_embedded_thread_input_reader_sp (), + m_dbg_stdout (interpreter.GetDebugger().GetOutputFileHandle()), + m_new_sysout (NULL), + m_dictionary_name (interpreter.GetDebugger().GetInstanceName().AsCString()), m_termios (), m_termios_valid (false), - m_embedded_python_pty (), - m_embedded_thread_input_reader_sp () + m_session_is_active (false), + m_pty_slave_is_open (false), + m_valid_session (true) { + Mutex::Locker locker (GetPythonMutex()); - Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + m_dictionary_name.append("_dict"); + StreamString run_string; + run_string.Printf ("%s = dict()", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + + run_string.Clear(); + run_string.Printf ("run_one_line (%s, 'import sys')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + + // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a + // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the + // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final + // call to Debugger::Terminate is made, the ref-count has the correct value. + // + // Bonus question: Why doesn't the ref-count always increase? Because sometimes lldb has already been imported, in + // which case the code inside it, including the call to SBDebugger::Initialize(), does not get executed. + + int old_count = Debugger::TestDebuggerRefCount(); - // Save terminal settings if we can - int input_fd; - FILE *input_fh = m_interpreter.GetDebugger().GetInputFileHandle(); - if (input_fh != NULL) - input_fd = ::fileno (input_fh); - else - input_fd = STDIN_FILENO; + run_string.Clear(); + run_string.Printf ("run_one_line (%s, 'import lldb')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + + int new_count = Debugger::TestDebuggerRefCount(); - m_termios_valid = ::tcgetattr (input_fd, &m_termios) == 0; - - // Find the module that owns this code and use that path we get to - // set the PYTHONPATH appropriately. + if (new_count > old_count) + Debugger::Terminate(); - FileSpec file_spec; - char python_dir_path[PATH_MAX]; - if (Host::GetLLDBPath (ePathTypePythonDir, file_spec)) + run_string.Clear(); + run_string.Printf ("run_one_line (%s, 'import copy')", m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + + run_string.Clear(); + run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %d')", m_dictionary_name.c_str(), + interpreter.GetDebugger().GetID()); + PyRun_SimpleString (run_string.GetData()); + + if (m_dbg_stdout != NULL) { - std::string python_path; - const char *curr_python_path = ::getenv ("PYTHONPATH"); - if (curr_python_path) - { - // We have a current value for PYTHONPATH, so lets append to it - python_path.append (curr_python_path); - } - - if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) - { - if (!python_path.empty()) - python_path.append (1, ':'); - python_path.append (python_dir_path); - } - - if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec)) - { - if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) - { - if (!python_path.empty()) - python_path.append (1, ':'); - python_path.append (python_dir_path); - } - } - const char *pathon_path_env_cstr = python_path.c_str(); - ::setenv ("PYTHONPATH", pathon_path_env_cstr, 1); + m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); } +} - Py_Initialize (); - - PyObject *compiled_module = Py_CompileString (embedded_interpreter_string, - "embedded_interpreter.py", - Py_file_input); +ScriptInterpreterPython::~ScriptInterpreterPython () +{ + Debugger &debugger = GetCommandInterpreter().GetDebugger(); - m_compiled_module = static_cast(compiled_module); + if (m_embedded_thread_input_reader_sp.get() != NULL) + { + m_embedded_thread_input_reader_sp->SetIsDone (true); + m_embedded_python_pty.CloseSlaveFileDescriptor(); + m_pty_slave_is_open = false; + const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp; + m_embedded_thread_input_reader_sp.reset(); + debugger.PopInputReader (reader_sp); + } + + if (m_new_sysout) + { + Mutex::Locker locker(GetPythonMutex()); + Py_DECREF (m_new_sysout); + } +} - // This function is in the C++ output file generated by SWIG after it is - // run on all of the headers in "lldb/API/SB*.h" - init_lldb (); +void +ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh) +{ + if (fh == NULL) + return; + + m_dbg_stdout = fh; + Mutex::Locker locker (GetPythonMutex()); - // Update the path python uses to search for modules to include the current directory. + EnterSession (); + m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush); + LeaveSession (); +} - int success = PyRun_SimpleString ("import sys"); - success = PyRun_SimpleString ("sys.path.append ('.')"); - if (success == 0) - { - // Import the Script Bridge module. - success = PyRun_SimpleString ("import lldb"); - } +void +ScriptInterpreterPython::LeaveSession () +{ + m_session_is_active = false; +} - const char *pty_slave_name = GetScriptInterpreterPtyName (); - FILE *out_fh = interpreter.GetDebugger().GetOutputFileHandle(); +void +ScriptInterpreterPython::EnterSession () +{ + // If we have already entered the session, without having officially 'left' it, then there is no need to + // 'enter' it again. - PyObject *pmod = PyImport_ExecCodeModule (const_cast ("embedded_interpreter"), - static_cast(m_compiled_module)); + if (m_session_is_active) + return; - if (pmod != NULL) - { - PyRun_SimpleString ("ConsoleDict = locals()"); - PyRun_SimpleString ("from embedded_interpreter import run_python_interpreter"); - PyRun_SimpleString ("import sys"); - PyRun_SimpleString ("from termios import *"); - - if (out_fh != NULL) - { - PyObject *new_sysout = PyFile_FromFile (out_fh, (char *) "", (char *) "w", - _check_and_flush); - PyObject *sysmod = PyImport_AddModule ("sys"); - PyObject *sysdict = PyModule_GetDict (sysmod); - - if ((new_sysout != NULL) - && (sysmod != NULL) - && (sysdict != NULL)) - { - PyDict_SetItemString (sysdict, "stdout", new_sysout); - } + m_session_is_active = true; - if (PyErr_Occurred()) - PyErr_Clear(); - } + Mutex::Locker locker (GetPythonMutex()); - StreamString run_string; - run_string.Printf ("new_stdin = open('%s', 'r')", pty_slave_name); + PyObject *sysmod = PyImport_AddModule ("sys"); + PyObject *sysdict = PyModule_GetDict (sysmod); + + if ((m_new_sysout != NULL) + && (sysmod != NULL) + && (sysdict != NULL)) + PyDict_SetItemString (sysdict, "stdout", m_new_sysout); + + if (PyErr_Occurred()) + PyErr_Clear (); + + StreamString run_string; + if (!m_pty_slave_is_open) + { + run_string.Printf ("run_one_line (%s, \"new_stdin = open('%s', 'r')\")", m_dictionary_name.c_str(), + m_pty_slave_name.c_str()); PyRun_SimpleString (run_string.GetData()); - PyRun_SimpleString ("sys.stdin = new_stdin"); - + m_pty_slave_is_open = true; + run_string.Clear(); - run_string.Printf ("lldb.debugger_unique_id = %d", interpreter.GetDebugger().GetID()); + run_string.Printf ("run_one_line (%s, 'sys.stdin = new_stdin')", m_dictionary_name.c_str()); PyRun_SimpleString (run_string.GetData()); } +} - // Restore terminal settings if they were validly saved - if (m_termios_valid) - { - ::tcsetattr (input_fd, TCSANOW, &m_termios); - } -} - -ScriptInterpreterPython::~ScriptInterpreterPython () -{ - Py_Finalize (); -} - bool ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result) { + if (!m_valid_session) + return false; + + EnterSession (); + + Mutex::Locker locker (GetPythonMutex()); + if (command) { int success; - success = PyRun_SimpleString (command); + StreamString sstr; + sstr.Printf ("run_one_line (%s, '%s')", m_dictionary_name.c_str(), command); + success = PyRun_SimpleString (sstr.GetData()); + + LeaveSession (); + if (success == 0) return true; @@ -307,6 +345,7 @@ return false; } + LeaveSession (); if (result) result->AppendError ("empty command passed to python\n"); return false; @@ -329,12 +368,16 @@ if (baton == NULL) return 0; - + + ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + + if (script_interpreter->m_script_lang != eScriptLanguagePython) + return 0; + FILE *out_fh = reader.GetDebugger().GetOutputFileHandle (); if (out_fh == NULL) out_fh = stdout; - ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; switch (notification) { case eInputReaderActivate: @@ -384,14 +427,17 @@ log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty "); reader.SetIsDone (true); } + script_interpreter->EnterSession (); } break; case eInputReaderDeactivate: + script_interpreter->LeaveSession (); break; case eInputReaderReactivate: + script_interpreter->EnterSession (); break; case eInputReaderInterrupt: @@ -429,10 +475,8 @@ break; case eInputReaderDone: - // Send a control D to the script interpreter - //::write (interpreter->GetMasterFileDescriptor(), "\nquit()\n", strlen("\nquit()\n")); - // Write a newline out to the reader output - //::fwrite ("\n", 1, 1, out_fh); + script_interpreter->LeaveSession (); + // Restore terminal settings if they were validly saved if (log) log->Printf ("ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader."); @@ -460,7 +504,7 @@ { Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); - Debugger &debugger = m_interpreter.GetDebugger(); + Debugger &debugger = GetCommandInterpreter().GetDebugger(); // At the moment, the only time the debugger does not have an input file handle is when this is called // directly from Python, in which case it is both dangerous and unnecessary (not to mention confusing) to @@ -493,14 +537,54 @@ ScriptInterpreter::ReturnType return_type, void *ret_value) { + EnterSession (); + + Mutex::Locker locker (GetPythonMutex()); + PyObject *py_return = NULL; PyObject *mainmod = PyImport_AddModule ("__main__"); PyObject *globals = PyModule_GetDict (mainmod); - PyObject *locals = globals; + PyObject *locals = NULL; PyObject *py_error = NULL; bool ret_success; + bool should_decrement_locals = false; int success; + + if (PyDict_Check (globals)) + { + PyObject *key, *value; + Py_ssize_t pos = 0; + + int i = 0; + while (PyDict_Next (globals, &pos, &key, &value)) + { + // We have stolen references to the key and value objects in the dictionary; we need to increment them now + // so that Python's garbage collector doesn't collect them out from under us. + Py_INCREF (key); + Py_INCREF (value); + char *c_str = PyString_AsString (key); + if (strcmp (c_str, m_dictionary_name.c_str()) == 0) + locals = value; + ++i; + } + } + if (locals == NULL) + { + locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); + should_decrement_locals = true; + } + + if (locals == NULL) + { + locals = globals; + should_decrement_locals = false; + } + + py_error = PyErr_Occurred(); + if (py_error != NULL) + PyErr_Clear(); + if (in_string != NULL) { py_return = PyRun_String (in_string, Py_eval_input, globals, locals); @@ -513,6 +597,10 @@ py_return = PyRun_String (in_string, Py_single_input, globals, locals); } + if (locals != NULL + && should_decrement_locals) + Py_DECREF (locals); + if (py_return != NULL) { switch (return_type) @@ -614,6 +702,8 @@ PyErr_Clear(); ret_success = false; } + + LeaveSession (); return ret_success; } @@ -621,13 +711,50 @@ bool ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string) { + EnterSession (); + + Mutex::Locker locker (GetPythonMutex()); + bool success = false; PyObject *py_return = NULL; PyObject *mainmod = PyImport_AddModule ("__main__"); PyObject *globals = PyModule_GetDict (mainmod); - PyObject *locals = globals; + PyObject *locals = NULL; PyObject *py_error = NULL; + bool should_decrement_locals = false; + if (PyDict_Check (globals)) + { + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next (globals, &pos, &key, &value)) + { + // We have stolen references to the key and value objects in the dictionary; we need to increment them now + // so that Python's garbage collector doesn't collect them out from under us. + Py_INCREF (key); + Py_INCREF (value); + if (strcmp (PyString_AsString (key), m_dictionary_name.c_str()) == 0) + locals = value; + } + } + + if (locals == NULL) + { + locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str()); + should_decrement_locals = true; + } + + if (locals == NULL) + { + locals = globals; + should_decrement_locals = false; + } + + py_error = PyErr_Occurred(); + if (py_error != NULL) + PyErr_Clear(); + if (in_string != NULL) { struct _node *compiled_node = PyParser_SimpleParseString (in_string, Py_file_input); @@ -642,6 +769,8 @@ success = true; Py_DECREF (py_return); } + if (locals && should_decrement_locals) + Py_DECREF (locals); } } } @@ -655,6 +784,8 @@ success = false; } + LeaveSession (); + return success; } @@ -764,7 +895,8 @@ ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, CommandReturnObject &result) { - Debugger &debugger = m_interpreter.GetDebugger(); + Debugger &debugger = GetCommandInterpreter().GetDebugger(); + InputReaderSP reader_sp (new InputReader (debugger)); if (reader_sp) @@ -861,8 +993,16 @@ // Create the function name & definition string. - sstr.Printf ("def %s (frame, bp_loc):", auto_generated_function_name.c_str()); + sstr.Printf ("def %s (frame, bp_loc, dict):", auto_generated_function_name.c_str()); auto_generated_function.AppendString (sstr.GetData()); + + // Pre-pend code for setting up the session dictionary. + + auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary + auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict + auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict + auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the + // global dictionary. // Wrap everything up inside the function, increasing the indentation. @@ -873,6 +1013,14 @@ auto_generated_function.AppendString (sstr.GetData()); } + // Append code to clean up the global dictionary and update the session dictionary (all updates in the function + // got written to the values in the global dictionary, not the session dictionary). + + auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict + auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values + auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict + auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict + // Verify that the results are valid Python. if (!ExportFunctionDefinitionToInterpreter (auto_generated_function)) @@ -897,6 +1045,21 @@ { BreakpointOptions::CommandData *bp_option_data = (BreakpointOptions::CommandData *) baton; const char *python_function_name = bp_option_data->script_source.GetStringAtIndex (0); + + if (!context) + return true; + + Target *target = context->exe_ctx.target; + + if (!target) + return true; + + Debugger &debugger = target->GetDebugger(); + ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter(); + ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter; + + if (!script_interpreter) + return true; if (python_function_name != NULL && python_function_name[0] != '\0') @@ -911,7 +1074,15 @@ SBBreakpointLocation sb_bp_loc (bp_loc_sp); if (sb_bp_loc.IsValid() || sb_frame.IsValid()) - return LLDBSWIGPythonBreakpointCallbackFunction (python_function_name, sb_frame, sb_bp_loc); + { + python_interpreter->EnterSession (); + Mutex::Locker locker (GetPythonMutex()); + bool ret_val = LLDBSWIGPythonBreakpointCallbackFunction(python_function_name, + python_interpreter->m_dictionary_name.c_str(), + sb_frame, sb_bp_loc); + python_interpreter->LeaveSession (); + return ret_val; + } } // We currently always true so we stop in case anything goes wrong when // trying to call the script function @@ -923,6 +1094,8 @@ { ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton; + script_interpreter->EnterSession (); + LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT)); if (log) @@ -932,39 +1105,172 @@ const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str)); if (pty_slave_name != NULL) { + Mutex::Locker locker (GetPythonMutex()); + StreamString run_string; - PyRun_SimpleString ("save_stderr = sys.stderr"); - PyRun_SimpleString ("sys.stderr = sys.stdout"); - PyRun_SimpleString ("save_stdin = sys.stdin"); - run_string.Printf ("sys.stdin = open ('%s', 'r')", pty_slave_name); + + run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str()); PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(), + pty_slave_name); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + // The following call drops into the embedded interpreter loop and stays there until the // user chooses to exit from the Python interpreter. - script_interpreter->ExecuteOneLine ("run_python_interpreter(ConsoleDict)", NULL); + + run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear (); + + run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); - PyRun_SimpleString ("sys.stdin = save_stdin"); - PyRun_SimpleString ("sys.stderr = save_stderr"); + run_string.Printf ("run_one_line (%s, 'sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str()); + PyRun_SimpleString (run_string.GetData()); + run_string.Clear(); } if (script_interpreter->m_embedded_thread_input_reader_sp) script_interpreter->m_embedded_thread_input_reader_sp->SetIsDone (true); script_interpreter->m_embedded_python_pty.CloseSlaveFileDescriptor(); + + script_interpreter->m_pty_slave_is_open = false; log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT); if (log) log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread exiting...", baton); - // Clean up the input reader and make the debugger pop it off the stack. - Debugger &debugger = script_interpreter->m_interpreter.GetDebugger(); + // Clean up the input reader and make the debugger pop it off the stack. + Debugger &debugger = script_interpreter->GetCommandInterpreter().GetDebugger(); const InputReaderSP reader_sp = script_interpreter->m_embedded_thread_input_reader_sp; script_interpreter->m_embedded_thread_input_reader_sp.reset(); debugger.PopInputReader (reader_sp); + + script_interpreter->LeaveSession (); return NULL; } +void +ScriptInterpreterPython::Initialize () +{ + + Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); + + int input_fd = STDIN_FILENO; + + struct termios stdin_termios; + bool valid_termios = ::tcgetattr (input_fd, &stdin_termios) == 0; + + // Find the module that owns this code and use that path we get to + // set the PYTHONPATH appropriately. + FileSpec file_spec; + char python_dir_path[PATH_MAX]; + if (Host::GetLLDBPath (ePathTypePythonDir, file_spec)) + { + std::string python_path; + const char *curr_python_path = ::getenv ("PYTHONPATH"); + if (curr_python_path) + { + // We have a current value for PYTHONPATH, so lets append to it + python_path.append (curr_python_path); + } + + if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) + { + if (!python_path.empty()) + python_path.append (1, ':'); + python_path.append (python_dir_path); + } + + if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec)) + { + if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path))) + { + if (!python_path.empty()) + python_path.append (1, ':'); + python_path.append (python_dir_path); + } + } + const char *pathon_path_env_cstr = python_path.c_str(); + ::setenv ("PYTHONPATH", pathon_path_env_cstr, 1); + } + + Py_Initialize (); + + PyObject *compiled_module = Py_CompileString (embedded_interpreter_string, + "embedded_interpreter.py", + Py_file_input); + + PyObject *py_error = PyErr_Occurred (); + if (py_error != NULL) + { + PyErr_Print(); + PyErr_Clear(); + } + + + // This function is in the C++ output file generated by SWIG after it is + // run on all of the headers in "lldb/API/SB*.h" + init_lldb (); + + // Update the path python uses to search for modules to include the current directory. + + int success = PyRun_SimpleString ("import sys"); + success = PyRun_SimpleString ("sys.path.append ('.')"); + + PyObject *pmod = NULL; + + if (compiled_module) + { + pmod = PyImport_ExecCodeModule (const_cast ("embedded_interpreter"), + compiled_module); + Py_DECREF (compiled_module); + } + + if (pmod != NULL) + { + PyRun_SimpleString ("from embedded_interpreter import run_python_interpreter"); + PyRun_SimpleString ("from embedded_interpreter import run_one_line"); + PyRun_SimpleString ("import sys"); + PyRun_SimpleString ("from termios import *"); + Py_DECREF (pmod); + } + + if (valid_termios) + ::tcsetattr (input_fd, TCSANOW, &stdin_termios); +} + +void +ScriptInterpreterPython::Terminate () +{ + // We are intentionally NOT calling Py_Finalize here (this would be the logical place to call it). Calling + // Py_Finalize here causes test suite runs to seg fault: The test suite runs in Python. It registers + // SBDebugger::Terminate to be called 'at_exit'. When the test suite Python harness finishes up, it calls + // Py_Finalize, which calls all the 'at_exit' registered functions. SBDebugger::Terminate calls Debugger::Terminate, + // which calls lldb::Terminate, which calls ScriptInterpreter::Terminate, which calls + // ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we end up with Py_Finalize being called from + // within Py_Finalize, which results in a seg fault. + // + // Since this function only gets called when lldb is shutting down and going away anyway, the fact that we don't + // actually call Py_Finalize should not cause any problems (everything should shut down/go away anyway when the + // process exits). + // +// Py_Finalize (); +} Modified: lldb/trunk/source/Interpreter/embedded_interpreter.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/embedded_interpreter.py?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/embedded_interpreter.py (original) +++ lldb/trunk/source/Interpreter/embedded_interpreter.py Thu Jan 13 18:29:16 2011 @@ -84,7 +84,20 @@ if not more: break + def one_line (self, input): + line = self.process_input (input) + more = self.push(line) + if more: + self.write ("Input not a complete line.") + self.resetbuffer() + more = 0 + def run_python_interpreter (dict): # Pass in the dictionary, for continuity from one session to the next. repl = SimpleREPL('>>> ', dict) repl.interact() + +def run_one_line (dict, input_string): + repl = SimpleREPL ('', dict) + repl.one_line (input_string) + Modified: lldb/trunk/source/lldb.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=123415&r1=123414&r2=123415&view=diff ============================================================================== --- lldb/trunk/source/lldb.cpp (original) +++ lldb/trunk/source/lldb.cpp Thu Jan 13 18:29:16 2011 @@ -14,6 +14,7 @@ #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Host/Mutex.h" +#include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" @@ -53,7 +54,7 @@ lldb_private::Initialize () { // Make sure we inialize only once - static Mutex g_inited_mutex(Mutex::eMutexTypeNormal); + static Mutex g_inited_mutex(Mutex::eMutexTypeRecursive); static bool g_inited = false; Mutex::Locker locker(g_inited_mutex); @@ -75,6 +76,7 @@ UnwindAssemblyProfiler_x86::Initialize(); ArchDefaultUnwindPlan_x86::Initialize(); ArchVolatileRegs_x86::Initialize(); + ScriptInterpreter::Initialize (); #ifdef __APPLE__ ABIMacOSX_i386::Initialize(); @@ -114,6 +116,7 @@ UnwindAssemblyProfiler_x86::Terminate(); ArchDefaultUnwindPlan_x86::Terminate(); ArchVolatileRegs_x86::Terminate(); + ScriptInterpreter::Terminate (); #ifdef __APPLE__ DynamicLoaderMacOSXDYLD::Terminate(); From gclayton at apple.com Thu Jan 13 22:54:56 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 04:54:56 -0000 Subject: [Lldb-commits] [lldb] r123428 - in /lldb/trunk: include/lldb/Core/Error.h include/lldb/Symbol/ClangASTContext.h scripts/lldb.swig source/Core/Error.cpp source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp source/Symbol/ClangASTContext.cpp test/foundation/main.m Message-ID: <20110114045456.B85B12A6C12C@llvm.org> Author: gclayton Date: Thu Jan 13 22:54:56 2011 New Revision: 123428 URL: http://llvm.org/viewvc/llvm-project?rev=123428&view=rev Log: Fixed an error in the type map for "char **" that was a bad memory smasher. Anytime we had a valid python list that was trying to go from Python down into our C++ API, it was allocating too little memory and it ended up smashing whatever was next to the allocated memory. Added typemap conversions for "void *, size_t" so we can get SBProcess::ReadMemory() working. Also added a typemap for "const void *, size_t" so we can get SBProcess::WriteMemory() to work. Fixed an issue in the DWARF parser where we weren't correctly calculating the DeclContext for all types and classes. We now should be a lot more accurate. Fixes include: enums should now be setting their parent decl context correctly. We saw a lot of examples where enums in classes were not being properly namespace scoped. Also, classes within classes now get properly scoped. Fixed the objective C runtime pointer checkers to let "nil" pointers through since these are accepted by compiled code. We also now don't call "abort()" when a pointer doesn't validate correctly since this was wreaking havoc on the process due to the way abort() works. We now just dereference memory which should give us an exception from which we can easily and reliably recover. Modified: lldb/trunk/include/lldb/Core/Error.h lldb/trunk/include/lldb/Symbol/ClangASTContext.h lldb/trunk/scripts/lldb.swig lldb/trunk/source/Core/Error.cpp lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp lldb/trunk/source/Symbol/ClangASTContext.cpp lldb/trunk/test/foundation/main.m Modified: lldb/trunk/include/lldb/Core/Error.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Error.h?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/Error.h (original) +++ lldb/trunk/include/lldb/Core/Error.h Thu Jan 13 22:54:56 2011 @@ -64,9 +64,12 @@ /// @param[in] type /// The type for \a err. //------------------------------------------------------------------ + Error (); + explicit - Error (ValueType err = 0, lldb::ErrorType type = lldb::eErrorTypeGeneric); + Error (ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric); + Error (const Error &rhs); //------------------------------------------------------------------ /// Assignment operator. /// Modified: lldb/trunk/include/lldb/Symbol/ClangASTContext.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangASTContext.h?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/ClangASTContext.h (original) +++ lldb/trunk/include/lldb/Symbol/ClangASTContext.h Thu Jan 13 22:54:56 2011 @@ -506,7 +506,10 @@ // Enumeration Types //------------------------------------------------------------------ lldb::clang_type_t - CreateEnumerationType (const Declaration &decl, const char *name, lldb::clang_type_t integer_qual_type); + CreateEnumerationType (const char *name, + clang::DeclContext *decl_ctx, + const Declaration &decl, + lldb::clang_type_t integer_qual_type); static lldb::clang_type_t GetEnumerationIntegerType (lldb::clang_type_t enum_clang_type); Modified: lldb/trunk/scripts/lldb.swig URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/lldb.swig?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/scripts/lldb.swig (original) +++ lldb/trunk/scripts/lldb.swig Thu Jan 13 22:54:56 2011 @@ -18,11 +18,11 @@ if (PyList_Check($input)) { int size = PyList_Size($input); int i = 0; - $1 = (char **) malloc((size+1) * sizeof(char)); + $1 = (char **) malloc((size+1) * sizeof(char*)); for (i = 0; i < size; i++) { PyObject *o = PyList_GetItem($input,i); if (PyString_Check(o)) - $1[i] = PyString_AsString(PyList_GetItem($input,i)); + $1[i] = PyString_AsString(o); else { PyErr_SetString(PyExc_TypeError,"list must contain strings"); free($1); @@ -54,6 +54,43 @@ } + +// typemap for an outgoing buffer +%typemap(in) (const void *wbuffer, size_t len) { + if (!PyString_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting a string"); + return NULL; + } + $1 = (void *) PyString_AsString($input); + $2 = PyString_Size($input); +} + +// typemap for an incoming buffer +%typemap(in) (void *rbuffer, size_t len) { + if (!PyInt_Check($input)) { + PyErr_SetString(PyExc_ValueError, "Expecting an integer"); + return NULL; + } + $2 = PyInt_AsLong($input); + if ($2 < 0) { + PyErr_SetString(PyExc_ValueError, "Positive integer expected"); + return NULL; + } + $1 = (void *) malloc($2); +} + +// Return the buffer. Discarding any previous return result +%typemap(argout) (void *rbuffer, size_t len) { + Py_XDECREF($result); /* Blow away any previous result */ + if (result < 0) { /* Check for I/O error */ + free($1); + PyErr_SetFromErrno(PyExc_IOError); + return NULL; + } + $result = PyString_FromStringAndSize($1,result); + free($1); +} + /* The liblldb header files to be included. */ %{ Modified: lldb/trunk/source/Core/Error.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Error.cpp?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/source/Core/Error.cpp (original) +++ lldb/trunk/source/Core/Error.cpp Thu Jan 13 22:54:56 2011 @@ -27,6 +27,13 @@ using namespace lldb; using namespace lldb_private; +Error::Error (): + m_code (0), + m_type (eErrorTypeInvalid), + m_string () +{ +} + //---------------------------------------------------------------------- // Default constructor //---------------------------------------------------------------------- @@ -36,6 +43,14 @@ m_string () { } + +Error::Error (const Error &rhs) : + m_code (rhs.m_code), + m_type (rhs.m_type), + m_string (rhs.m_string) +{ +} + //---------------------------------------------------------------------- // Assignment operator //---------------------------------------------------------------------- Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original) +++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Thu Jan 13 22:54:56 2011 @@ -124,40 +124,45 @@ } } -struct BufStruct { - char contents[1024]; -}; - ClangUtilityFunction * AppleObjCRuntimeV2::CreateObjectChecker(const char *name) { - std::auto_ptr buf(new BufStruct); + char check_function_code[1024]; + int len = 0; if (m_has_object_getClass) { - assert(snprintf(&buf->contents[0], sizeof(buf->contents), - "extern \"C\" void *gdb_object_getClass(void *); \n" - "extern \"C\" void \n" - "%s(void *$__lldb_arg_obj) \n" - "{ \n" - " if (!gdb_object_getClass($__lldb_arg_obj)) \n" - " abort(); \n" - "} \n", - name) < sizeof(buf->contents)); + len = ::snprintf (check_function_code, + sizeof(check_function_code), + "extern \"C\" void *gdb_object_getClass(void *); \n" + "extern \"C\" void \n" + "%s(void *$__lldb_arg_obj) \n" + "{ \n" + " if ($__lldb_arg_obj == (void *)0) \n" + " return; // nil is ok \n" + " if (!gdb_object_getClass($__lldb_arg_obj)) \n" + " *((volatile int *)0) = 'ocgc'; \n" + "} \n", + name); } else { - assert(snprintf(&buf->contents[0], sizeof(buf->contents), - "extern \"C\" void *gdb_class_getClass(void *); \n" - "extern \"C\" void \n" - "%s(void *$__lldb_arg_obj) \n" - "{ \n" - " void **$isa_ptr = (void **)$__lldb_arg_obj; \n" - " if (!$isa_ptr || !gdb_class_getClass(*$isa_ptr)) \n" - " abort(); \n" - "} \n", - name) < sizeof(buf->contents)); + len = ::snprintf (check_function_code, + sizeof(check_function_code), + "extern \"C\" void *gdb_class_getClass(void *); \n" + "extern \"C\" void \n" + "%s(void *$__lldb_arg_obj) \n" + "{ \n" + " if ($__lldb_arg_obj == (void *)0) \n" + " return; // nil is ok \n" + " void **$isa_ptr = (void **)$__lldb_arg_obj; \n" + " if (!gdb_class_getClass(*$isa_ptr)) \n" + " *((volatile int *)0) = 'ocgc'; \n" + "} \n", + name); } - return new ClangUtilityFunction(buf->contents, name); + assert (len < sizeof(check_function_code)); + + return new ClangUtilityFunction(check_function_code, name); } Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (original) +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp Thu Jan 13 22:54:56 2011 @@ -1300,7 +1300,21 @@ DWARFCompileUnitSP cu_sp; const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, &cu_sp); if (type_die != NULL) + { + // We might be coming in in the middle of a type tree (a class + // withing a class, an enum within a class), so parse any needed + // parent DIEs before we get to this one... + const DWARFDebugInfoEntry* parent_die = type_die->GetParent(); + switch (parent_die->Tag()) + { + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + ResolveType(cu_sp.get(), parent_die); + break; + } return ResolveType (cu_sp.get(), type_die); + } } return NULL; } @@ -2651,7 +2665,9 @@ Type *type_ptr = m_die_to_type.lookup (die); if (type_ptr == NULL) { - SymbolContext sc(GetCompUnitForDWARFCompUnit(curr_cu)); + CompileUnit* lldb_cu = GetCompUnitForDWARFCompUnit(curr_cu); + assert (lldb_cu); + SymbolContext sc(lldb_cu); type_sp = ParseType(sc, curr_cu, die, NULL); } else if (type_ptr != DIE_IS_BEING_PARSED) @@ -2698,45 +2714,89 @@ clang::DeclContext * SymbolFileDWARF::GetClangDeclContextForDIE (DWARFCompileUnit *curr_cu, const DWARFDebugInfoEntry *die) { - DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die); - if (pos != m_die_to_decl_ctx.end()) - return pos->second; + if (m_clang_tu_decl == NULL) + m_clang_tu_decl = GetClangASTContext().getASTContext()->getTranslationUnitDecl(); + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x )\n", die->GetOffset()); + const DWARFDebugInfoEntry * const decl_die = die; while (die != NULL) { - switch (die->Tag()) + // If this is the original DIE that we are searching for a declaration + // for, then don't look in the cache as we don't want our own decl + // context to be our decl context... + if (decl_die != die) { - case DW_TAG_namespace: + DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die); + if (pos != m_die_to_decl_ctx.end()) { - const char *namespace_name = die->GetAttributeValueAsString(this, curr_cu, DW_AT_name, NULL); - if (namespace_name) + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) => 0x%8.8x\n", decl_die->GetOffset(), die->GetOffset()); + return pos->second; + } + + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) checking parent 0x%8.8x\n", decl_die->GetOffset(), die->GetOffset()); + + switch (die->Tag()) + { + case DW_TAG_namespace: { - Declaration decl; // TODO: fill in the decl object - clang::NamespaceDecl *namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, decl, GetClangDeclContextForDIE (curr_cu, die->GetParent())); - if (namespace_decl) - m_die_to_decl_ctx[die] = (clang::DeclContext*)namespace_decl; - return namespace_decl; + const char *namespace_name = die->GetAttributeValueAsString(this, curr_cu, DW_AT_name, NULL); + if (namespace_name) + { + Declaration decl; // TODO: fill in the decl object + clang::NamespaceDecl *namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, decl, GetClangDeclContextForDIE (curr_cu, die->GetParent())); + if (namespace_decl) + { + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) => 0x%8.8x\n", decl_die->GetOffset(), die->GetOffset()); + m_die_to_decl_ctx[die] = (clang::DeclContext*)namespace_decl; + } + return namespace_decl; + } } - } - break; + break; - default: - break; + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_class_type: + { + ResolveType (curr_cu, die); + pos = m_die_to_decl_ctx.find(die); + assert (pos != m_die_to_decl_ctx.end()); + if (pos != m_die_to_decl_ctx.end()) + { + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) => 0x%8.8x\n", decl_die->GetOffset(), die->GetOffset()); + return pos->second; + } + } + break; + + default: + break; + } } + clang::DeclContext *decl_ctx; - decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, curr_cu, DW_AT_specification, DW_INVALID_OFFSET)); - if (decl_ctx) - return decl_ctx; - - decl_ctx = GetClangDeclContextForDIEOffset (die->GetAttributeValueAsUnsigned(this, curr_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET)); - if (decl_ctx) - return decl_ctx; + dw_offset_t die_offset = die->GetAttributeValueAsUnsigned(this, curr_cu, DW_AT_specification, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) check DW_AT_specification 0x%8.8x\n", decl_die->GetOffset(), die_offset); + decl_ctx = GetClangDeclContextForDIEOffset (die_offset); + if (decl_ctx != m_clang_tu_decl) + return decl_ctx; + } + + die_offset = die->GetAttributeValueAsUnsigned(this, curr_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET); + if (die_offset != DW_INVALID_OFFSET) + { + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) check DW_AT_abstract_origin 0x%8.8x\n", decl_die->GetOffset(), die_offset); + decl_ctx = GetClangDeclContextForDIEOffset (die_offset); + if (decl_ctx != m_clang_tu_decl) + return decl_ctx; + } die = die->GetParent(); } // Right now we have only one translation unit per module... - if (m_clang_tu_decl == NULL) - m_clang_tu_decl = GetClangASTContext().getASTContext()->getTranslationUnitDecl(); + //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) => 0x%8.8x\n", decl_die->GetOffset(), curr_cu->GetFirstDIEOffset()); return m_clang_tu_decl; } @@ -3051,7 +3111,7 @@ } - if (is_forward_declaration) + if (is_forward_declaration && die->HasChildren() == false) { // We have a forward declaration to a type and we need // to try and find a full declaration. We look in the @@ -3183,8 +3243,9 @@ enumerator_clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL, DW_ATE_signed, byte_size * 8); - clang_type = ast.CreateEnumerationType (decl, - type_name_cstr, + clang_type = ast.CreateEnumerationType (type_name_cstr, + GetClangDeclContextForDIE (dwarf_cu, die->GetParent()), + decl, enumerator_clang_type); } else Modified: lldb/trunk/source/Symbol/ClangASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTContext.cpp?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp (original) +++ lldb/trunk/source/Symbol/ClangASTContext.cpp Thu Jan 13 22:54:56 2011 @@ -3487,7 +3487,13 @@ #pragma mark Enumeration Types clang_type_t -ClangASTContext::CreateEnumerationType (const Declaration &decl, const char *name, clang_type_t integer_qual_type) +ClangASTContext::CreateEnumerationType +( + const char *name, + DeclContext *decl_ctx, + const Declaration &decl, + clang_type_t integer_qual_type +) { // TODO: Do something intelligent with the Declaration object passed in // like maybe filling in the SourceLocation with it... @@ -3499,7 +3505,7 @@ // const bool IsFixed = false; EnumDecl *enum_decl = EnumDecl::Create (*ast_context, - ast_context->getTranslationUnitDecl(), + decl_ctx, SourceLocation(), name && name[0] ? &ast_context->Idents.get(name) : NULL, SourceLocation(), Modified: lldb/trunk/test/foundation/main.m URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/foundation/main.m?rev=123428&r1=123427&r2=123428&view=diff ============================================================================== --- lldb/trunk/test/foundation/main.m (original) +++ lldb/trunk/test/foundation/main.m Thu Jan 13 22:54:56 2011 @@ -98,6 +98,7 @@ int Test_NSArray () { + NSMutableArray *nil_mutable_array = nil; NSArray *array1 = [NSArray arrayWithObjects: @"array1 object1", @"array1 object2", @"array1 object3", nil]; NSArray *array2 = [NSArray arrayWithObjects: array1, @"array2 object2", @"array2 object3", nil]; // Expressions to test here for NSArray: @@ -105,6 +106,7 @@ // expression array1.count // expression [array2 count] // expression array2.count + // expression [nil_mutable_array count] id obj; // After each object at index call, use expression and validate object obj = [array1 objectAtIndex: 0]; @@ -114,7 +116,7 @@ obj = [array2 objectAtIndex: 0]; obj = [array2 objectAtIndex: 1]; obj = [array2 objectAtIndex: 2]; - + NSUInteger count = [nil_mutable_array count]; return 0; } From johnny.chen at apple.com Fri Jan 14 12:19:53 2011 From: johnny.chen at apple.com (Johnny Chen) Date: Fri, 14 Jan 2011 18:19:53 -0000 Subject: [Lldb-commits] [lldb] r123451 - /lldb/trunk/test/make/Makefile.rules Message-ID: <20110114181953.37B7B2A6C12C@llvm.org> Author: johnny Date: Fri Jan 14 12:19:53 2011 New Revision: 123451 URL: http://llvm.org/viewvc/llvm-project?rev=123451&view=rev Log: The cxx_compiler function should not blindly return clang++ as the C++ compiler if $(CC) contains "clang". Instead, it should perform a textual replacement of $(CC) from "clang" to "clang++". The same is true for "llvm-gcc" to "llvm-g++" and for "gcc" to "g++". This way, we keep the path component of the $(CC) passed in from the user and do not end up with a mixed toolchains with different paths. Ditto for a newly added function called cxx_linker. Modified: lldb/trunk/test/make/Makefile.rules Modified: lldb/trunk/test/make/Makefile.rules URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/make/Makefile.rules?rev=123451&r1=123450&r2=123451&view=diff ============================================================================== --- lldb/trunk/test/make/Makefile.rules (original) +++ lldb/trunk/test/make/Makefile.rules Fri Jan 14 12:19:53 2011 @@ -31,8 +31,11 @@ EXE = a.out DSYM = $(EXE).dSYM -# Function that returns the counterpart C++ compiler. -cxx_compiler = $(if $(findstring clang,$(1)), clang++, $(if $(findstring llvm-gcc,$(1)), llvm-g++, g++)) +# Function that returns the counterpart C++ compiler, given $(CC) as arg. +cxx_compiler = $(if $(findstring clang,$(1)), $(subst clang,clang++,$(1)), $(if $(findstring llvm-gcc,$(1)), $(subst llvm-gcc,llvm-g++,$(1)), $(subst gcc,g++,$(1)))) + +# Function that returns the C++ linker, given $(CC) as arg. +cxx_linker = $(if $(findstring clang,$(1)), $(subst clang,g++,$(1)), $(if $(findstring llvm-gcc,$(1)), $(subst llvm-gcc,g++,$(1)), $(subst gcc,g++,$(1)))) #---------------------------------------------------------------------- # dylib settings @@ -55,7 +58,7 @@ ifneq "$(strip $(CXX_SOURCES))" "" OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o)) CXX = $(call cxx_compiler,$(CC)) - LD = g++ + LD = $(call cxx_linker,$(CC)) endif #---------------------------------------------------------------------- @@ -72,7 +75,7 @@ ifneq "$(strip $(OBJCXX_SOURCES))" "" OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o)) CXX = $(call cxx_compiler,$(CC)) - LD = g++ + LD = $(call cxx_linker,$(CC)) ifeq $(findstring lobjc,$(LDFLAGS)) "" LDFLAGS +=-lobjc endif From johnny.chen at apple.com Fri Jan 14 13:19:30 2011 From: johnny.chen at apple.com (Johnny Chen) Date: Fri, 14 Jan 2011 19:19:30 -0000 Subject: [Lldb-commits] [lldb] r123454 - in /lldb/trunk/test/foundation: TestObjCMethods2.py main.m Message-ID: <20110114191930.BB3C92A6C12C@llvm.org> Author: johnny Date: Fri Jan 14 13:19:30 2011 New Revision: 123454 URL: http://llvm.org/viewvc/llvm-project?rev=123454&view=rev Log: Add an expression command: expression (int)[nil_mutable_array count] within NSArray_expr() function and expect a return of 0. Modified: lldb/trunk/test/foundation/TestObjCMethods2.py lldb/trunk/test/foundation/main.m Modified: lldb/trunk/test/foundation/TestObjCMethods2.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/foundation/TestObjCMethods2.py?rev=123454&r1=123453&r2=123454&view=diff ============================================================================== --- lldb/trunk/test/foundation/TestObjCMethods2.py (original) +++ lldb/trunk/test/foundation/TestObjCMethods2.py Fri Jan 14 13:19:30 2011 @@ -106,6 +106,8 @@ # Test_NSArray: self.runCmd("thread backtrace") + self.expect("expression (int)[nil_mutable_array count]", + patterns = ["\(int\) \$.* = 0"]) self.expect("expression (int)[array1 count]", patterns = ["\(int\) \$.* = 3"]) self.expect("expression (int)[array2 count]", Modified: lldb/trunk/test/foundation/main.m URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/foundation/main.m?rev=123454&r1=123453&r2=123454&view=diff ============================================================================== --- lldb/trunk/test/foundation/main.m (original) +++ lldb/trunk/test/foundation/main.m Fri Jan 14 13:19:30 2011 @@ -102,11 +102,11 @@ NSArray *array1 = [NSArray arrayWithObjects: @"array1 object1", @"array1 object2", @"array1 object3", nil]; NSArray *array2 = [NSArray arrayWithObjects: array1, @"array2 object2", @"array2 object3", nil]; // Expressions to test here for NSArray: + // expression [nil_mutable_array count] // expression [array1 count] // expression array1.count // expression [array2 count] // expression array2.count - // expression [nil_mutable_array count] id obj; // After each object at index call, use expression and validate object obj = [array1 objectAtIndex: 0]; From gclayton at apple.com Fri Jan 14 13:21:25 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 19:21:25 -0000 Subject: [Lldb-commits] [lldb] r123455 - /lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp Message-ID: <20110114192125.9DB252A6C12C@llvm.org> Author: gclayton Date: Fri Jan 14 13:21:25 2011 New Revision: 123455 URL: http://llvm.org/viewvc/llvm-project?rev=123455&view=rev Log: Removed printf statements in code. Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp?rev=123455&r1=123454&r2=123455&view=diff ============================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp (original) +++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCTrampolineHandler.cpp Fri Jan 14 13:21:25 2011 @@ -788,12 +788,12 @@ if (sc.symbol != NULL) impl_code_address = sc.symbol->GetValue(); - lldb::addr_t addr = impl_code_address.GetLoadAddress (exe_ctx.target); - printf ("Getting address for our_utility_function: 0x%llx.\n", addr); + //lldb::addr_t addr = impl_code_address.GetLoadAddress (exe_ctx.target); + //printf ("Getting address for our_utility_function: 0x%llx.\n", addr); } else { - printf ("Could not find implementation function address.\n"); + //printf ("Could not find implementation function address.\n"); return ret_plan_sp; } } From johnny.chen at apple.com Fri Jan 14 14:46:49 2011 From: johnny.chen at apple.com (Johnny Chen) Date: Fri, 14 Jan 2011 20:46:49 -0000 Subject: [Lldb-commits] [lldb] r123461 - /lldb/trunk/test/make/Makefile.rules Message-ID: <20110114204649.ACA762A6C12C@llvm.org> Author: johnny Date: Fri Jan 14 14:46:49 2011 New Revision: 123461 URL: http://llvm.org/viewvc/llvm-project?rev=123461&view=rev Log: Make CC defaults to gcc. The cxx_compiler and cxx_linker functions rely on substituting "g++" for "gcc". Modified: lldb/trunk/test/make/Makefile.rules Modified: lldb/trunk/test/make/Makefile.rules URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/make/Makefile.rules?rev=123461&r1=123460&r2=123461&view=diff ============================================================================== --- lldb/trunk/test/make/Makefile.rules (original) +++ lldb/trunk/test/make/Makefile.rules Fri Jan 14 14:46:49 2011 @@ -18,11 +18,18 @@ endif #---------------------------------------------------------------------- +# CC defaults to gcc. +#---------------------------------------------------------------------- +CC ?= gcc +ifeq "$(CC)" "cc" + CC = gcc +endif + +#---------------------------------------------------------------------- # Change any build/tool options needed #---------------------------------------------------------------------- DS := /usr/bin/dsymutil DSFLAGS = -CC ?= gcc CFLAGS ?=-arch $(ARCH) -gdwarf-2 -O0 CXXFLAGS +=$(CFLAGS) LD = $(CC) From wilsons at start.ca Fri Jan 14 14:56:31 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 15:56:31 -0500 Subject: [Lldb-commits] [PATCH 0/3] trivial lldb fixes Message-ID: <1295038594-9585-1-git-send-email-wilsons@start.ca> This patch series contains two trivial fixes. Also, an extension to the ObjectFile interface is provided as discussed here: http://lists.cs.uiuc.edu/pipermail/lldb-dev/2011-January/000325.html The fixes pave the way for a second patch series I will be sending shortly containing various fixes/improvements to the ObjectFileELF and ProcessLinux plugins. From wilsons at start.ca Fri Jan 14 14:56:32 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 15:56:32 -0500 Subject: [Lldb-commits] [PATCH 1/3] Do not prefix log messages with ProcessMacOSX from the context of Process. In-Reply-To: <1295038594-9585-1-git-send-email-wilsons@start.ca> References: <1295038594-9585-1-git-send-email-wilsons@start.ca> Message-ID: <1295038594-9585-2-git-send-email-wilsons@start.ca> --- source/Target/Process.cpp | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index 2a83829..fdfa3a6 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -1099,7 +1099,7 @@ Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site) addr_t bp_addr = bp_site->GetLoadAddress(); lldb::user_id_t breakID = bp_site->GetID(); if (log) - log->Printf ("ProcessMacOSX::DisableBreakpoint (breakID = %d) addr = 0x%llx", breakID, (uint64_t)bp_addr); + log->Printf ("Process::DisableBreakpoint (breakID = %d) addr = 0x%llx", breakID, (uint64_t)bp_addr); if (bp_site->IsHardware()) { -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 14:56:33 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 15:56:33 -0500 Subject: [Lldb-commits] [PATCH 2/3] Do not prematurely invalidate thread handle. In-Reply-To: <1295038594-9585-1-git-send-email-wilsons@start.ca> References: <1295038594-9585-1-git-send-email-wilsons@start.ca> Message-ID: <1295038594-9585-3-git-send-email-wilsons@start.ca> Setting m_private_state_thread to an invalid value when the child thread exits results in a race condition between calls to ThreadCancel and ThreadJoin. --- source/Target/Process.cpp | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp index fdfa3a6..5834b8d 100644 --- a/source/Target/Process.cpp +++ b/source/Target/Process.cpp @@ -2173,7 +2173,6 @@ Process::RunPrivateStateThread () if (log) log->Printf ("Process::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, this, GetID()); - m_private_state_thread = LLDB_INVALID_HOST_THREAD; return NULL; } -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 14:56:34 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 15:56:34 -0500 Subject: [Lldb-commits] [PATCH 3/3] Extend the ObjectFile interface to support dynamic loading on ELF platforms. In-Reply-To: <1295038594-9585-1-git-send-email-wilsons@start.ca> References: <1295038594-9585-1-git-send-email-wilsons@start.ca> Message-ID: <1295038594-9585-4-git-send-email-wilsons@start.ca> Debuggers on ELF platforms hook into the runtime linker by monitoring a special "rendezvous" embedded in the address space of the inferior process. The exact location of this structure is filled in by the runtime linker and can be resolved by locating the DT_DEBUG entry in the processes .dynamic section. The new GetImageInfo() method (morally equivalent to Process::GetImageInfo) provides the mechanism to locate this information. GetEntryPoint() simply returns the address of the start symbol in the executable if present. It is useful to the dynamic loader plugin for ELF systems as this is the earliest point where LLDB can break and probe the inferiors .dynamic section and rendezvous structure. Also, this address can be used in the computation of the virtual base address for position independent executables. --- include/lldb/Symbol/ObjectFile.h | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-) diff --git a/include/lldb/Symbol/ObjectFile.h b/include/lldb/Symbol/ObjectFile.h index 184e80c..8e51571 100644 --- a/include/lldb/Symbol/ObjectFile.h +++ b/include/lldb/Symbol/ObjectFile.h @@ -173,6 +173,17 @@ public: //------------------------------------------------------------------ virtual bool IsExecutable () const = 0; + + //------------------------------------------------------------------ + /// Returns the virtual address of the entry point for this object + /// file. + /// + /// @return + /// The virtual address of the entry point or an invalid address + /// if an entry point is not defined. + //------------------------------------------------------------------ + virtual lldb_private::Address + GetEntryPoint () const { return Address(); } //------------------------------------------------------------------ /// Returns the offset into a file at which this object resides. @@ -311,6 +322,22 @@ public: virtual lldb_private::UnwindTable& GetUnwindTable () { return m_unwind_table; } + //------------------------------------------------------------------ + /// Similar to Process::GetImageInfoAddress(). + /// + /// Some platforms embed auxiliary structures useful to debuggers in the + /// address space of the inferior process. This method returns the address + /// of such a structure if the information can be resolved via entries in + /// the object file. ELF, for example, provides a means to hook into the + /// runtime linker so that a debugger may monitor the loading and unloading + /// of shared libraries. + /// + /// @return + /// The address of any auxiliary tables, or an invalid address if this + /// object file format does not support or contain such information. + virtual lldb_private::Address + GetImageInfoAddress () { return Address(); } + protected: //------------------------------------------------------------------ // Member variables. -- 1.7.3.5 From johnny.chen at apple.com Fri Jan 14 14:55:13 2011 From: johnny.chen at apple.com (Johnny Chen) Date: Fri, 14 Jan 2011 20:55:13 -0000 Subject: [Lldb-commits] [lldb] r123463 - /lldb/trunk/test/make/Makefile.rules Message-ID: <20110114205513.D268A2A6C12C@llvm.org> Author: johnny Date: Fri Jan 14 14:55:13 2011 New Revision: 123463 URL: http://llvm.org/viewvc/llvm-project?rev=123463&view=rev Log: Added comments. Modified: lldb/trunk/test/make/Makefile.rules Modified: lldb/trunk/test/make/Makefile.rules URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/make/Makefile.rules?rev=123463&r1=123462&r2=123463&view=diff ============================================================================== --- lldb/trunk/test/make/Makefile.rules (original) +++ lldb/trunk/test/make/Makefile.rules Fri Jan 14 14:55:13 2011 @@ -19,6 +19,9 @@ #---------------------------------------------------------------------- # CC defaults to gcc. +# See also these functions: +# o cxx_compiler +# o cxx_linker #---------------------------------------------------------------------- CC ?= gcc ifeq "$(CC)" "cc" From gclayton at apple.com Fri Jan 14 15:03:17 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 13:03:17 -0800 Subject: [Lldb-commits] [PATCH 0/3] trivial lldb fixes In-Reply-To: <1295038594-9585-1-git-send-email-wilsons@start.ca> References: <1295038594-9585-1-git-send-email-wilsons@start.ca> Message-ID: <496726F5-12E2-4456-A9E4-DE205AF36565@apple.com> These look good. Commit them at will. On Jan 14, 2011, at 12:56 PM, Stephen Wilson wrote: > This patch series contains two trivial fixes. Also, an extension to the > ObjectFile interface is provided as discussed here: > > http://lists.cs.uiuc.edu/pipermail/lldb-dev/2011-January/000325.html > > The fixes pave the way for a second patch series I will be sending shortly > containing various fixes/improvements to the ObjectFileELF and ProcessLinux > plugins. > > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From wilsons at start.ca Fri Jan 14 15:07:07 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 21:07:07 -0000 Subject: [Lldb-commits] [lldb] r123464 - /lldb/trunk/source/Target/Process.cpp Message-ID: <20110114210708.011202A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 15:07:07 2011 New Revision: 123464 URL: http://llvm.org/viewvc/llvm-project?rev=123464&view=rev Log: Do not prefix log messages with ProcessMacOSX from the context of Process. Modified: lldb/trunk/source/Target/Process.cpp Modified: lldb/trunk/source/Target/Process.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=123464&r1=123463&r2=123464&view=diff ============================================================================== --- lldb/trunk/source/Target/Process.cpp (original) +++ lldb/trunk/source/Target/Process.cpp Fri Jan 14 15:07:07 2011 @@ -1099,7 +1099,7 @@ addr_t bp_addr = bp_site->GetLoadAddress(); lldb::user_id_t breakID = bp_site->GetID(); if (log) - log->Printf ("ProcessMacOSX::DisableBreakpoint (breakID = %d) addr = 0x%llx", breakID, (uint64_t)bp_addr); + log->Printf ("Process::DisableBreakpoint (breakID = %d) addr = 0x%llx", breakID, (uint64_t)bp_addr); if (bp_site->IsHardware()) { From wilsons at start.ca Fri Jan 14 15:07:56 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 21:07:56 -0000 Subject: [Lldb-commits] [lldb] r123465 - /lldb/trunk/source/Target/Process.cpp Message-ID: <20110114210756.90D1D2A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 15:07:56 2011 New Revision: 123465 URL: http://llvm.org/viewvc/llvm-project?rev=123465&view=rev Log: Do not prematurely invalidate thread handle. Setting m_private_state_thread to an invalid value when the child thread exits results in a race condition between calls to ThreadCancel and ThreadJoin. Modified: lldb/trunk/source/Target/Process.cpp Modified: lldb/trunk/source/Target/Process.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=123465&r1=123464&r2=123465&view=diff ============================================================================== --- lldb/trunk/source/Target/Process.cpp (original) +++ lldb/trunk/source/Target/Process.cpp Fri Jan 14 15:07:56 2011 @@ -2173,7 +2173,6 @@ if (log) log->Printf ("Process::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, this, GetID()); - m_private_state_thread = LLDB_INVALID_HOST_THREAD; return NULL; } From wilsons at start.ca Fri Jan 14 15:08:59 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 21:08:59 -0000 Subject: [Lldb-commits] [lldb] r123466 - /lldb/trunk/include/lldb/Symbol/ObjectFile.h Message-ID: <20110114210859.CF7752A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 15:08:59 2011 New Revision: 123466 URL: http://llvm.org/viewvc/llvm-project?rev=123466&view=rev Log: Extend the ObjectFile interface to support dynamic loading on ELF platforms. Debuggers on ELF platforms hook into the runtime linker by monitoring a special "rendezvous" embedded in the address space of the inferior process. The exact location of this structure is filled in by the runtime linker and can be resolved by locating the DT_DEBUG entry in the processes .dynamic section. The new GetImageInfoAddress() method (morally equivalent to Process::GetImageInfoAddress) provides the mechanism to locate this information. GetEntryPoint() simply returns the address of the start symbol in the executable if present. It is useful to the dynamic loader plugin for ELF systems as this is the earliest point where LLDB can break and probe the inferiors .dynamic section and rendezvous structure. Also, this address can be used in the computation of the virtual base address for position independent executables. Modified: lldb/trunk/include/lldb/Symbol/ObjectFile.h Modified: lldb/trunk/include/lldb/Symbol/ObjectFile.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ObjectFile.h?rev=123466&r1=123465&r2=123466&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/ObjectFile.h (original) +++ lldb/trunk/include/lldb/Symbol/ObjectFile.h Fri Jan 14 15:08:59 2011 @@ -173,6 +173,17 @@ //------------------------------------------------------------------ virtual bool IsExecutable () const = 0; + + //------------------------------------------------------------------ + /// Returns the virtual address of the entry point for this object + /// file. + /// + /// @return + /// The virtual address of the entry point or an invalid address + /// if an entry point is not defined. + //------------------------------------------------------------------ + virtual lldb_private::Address + GetEntryPoint () const { return Address(); } //------------------------------------------------------------------ /// Returns the offset into a file at which this object resides. @@ -311,6 +322,22 @@ virtual lldb_private::UnwindTable& GetUnwindTable () { return m_unwind_table; } + //------------------------------------------------------------------ + /// Similar to Process::GetImageInfoAddress(). + /// + /// Some platforms embed auxiliary structures useful to debuggers in the + /// address space of the inferior process. This method returns the address + /// of such a structure if the information can be resolved via entries in + /// the object file. ELF, for example, provides a means to hook into the + /// runtime linker so that a debugger may monitor the loading and unloading + /// of shared libraries. + /// + /// @return + /// The address of any auxiliary tables, or an invalid address if this + /// object file format does not support or contain such information. + virtual lldb_private::Address + GetImageInfoAddress () { return Address(); } + protected: //------------------------------------------------------------------ // Member variables. From ctice at apple.com Fri Jan 14 15:09:29 2011 From: ctice at apple.com (Caroline Tice) Date: Fri, 14 Jan 2011 21:09:29 -0000 Subject: [Lldb-commits] [lldb] r123467 - in /lldb/trunk/source: Commands/CommandObjectSettings.cpp Interpreter/ScriptInterpreterPython.cpp Message-ID: <20110114210929.4D6BA2A6C12C@llvm.org> Author: ctice Date: Fri Jan 14 15:09:29 2011 New Revision: 123467 URL: http://llvm.org/viewvc/llvm-project?rev=123467&view=rev Log: Recent modifications to the Python script interpreter caused some problems when handling one-liner commands that contain escaped characters. In order to deal with the new namespace/dictionary stuff, the command was being embedded within a second string, which messed up the escaping. This fixes the problem by handling one-liners in a different manner, so they no longer need to be embedded within another string, and can still be processed in the proper namespace/dictionary context. Modified: lldb/trunk/source/Commands/CommandObjectSettings.cpp lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Modified: lldb/trunk/source/Commands/CommandObjectSettings.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectSettings.cpp?rev=123467&r1=123466&r2=123467&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectSettings.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectSettings.cpp Fri Jan 14 15:09:29 2011 @@ -355,10 +355,10 @@ } else { + StreamString tmp_str; char *type_name = (char *) ""; if (var_type != eSetVarTypeNone) { - StreamString tmp_str; tmp_str.Printf (" (%s)", UserSettingsController::GetTypeString (var_type)); type_name = (char *) tmp_str.GetData(); } Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=123467&r1=123466&r2=123467&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original) +++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Fri Jan 14 15:09:29 2011 @@ -326,17 +326,98 @@ Mutex::Locker locker (GetPythonMutex()); + // We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through + // PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside + // another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated + // method to pass the command string directly down to Python. + + + bool success = false; + if (command) { - int success; + // Find the correct script interpreter dictionary in the main module. + PyObject *main_mod = PyImport_AddModule ("__main__"); + PyObject *script_interpreter_dict = NULL; + if (main_mod != NULL) + { + PyObject *main_dict = PyModule_GetDict (main_mod); + if ((main_dict != NULL) + && PyDict_Check (main_dict)) + { + // Go through the main dictionary looking for the correct python script interpreter dictionary + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next (main_dict, &pos, &key, &value)) + { + // We have stolen references to the key and value objects in the dictionary; we need to increment + // them now so that Python's garbage collector doesn't collect them out from under us. + Py_INCREF (key); + Py_INCREF (value); + if (strcmp (PyString_AsString (key), m_dictionary_name.c_str()) == 0) + { + script_interpreter_dict = value; + break; + } + } + } + + if (script_interpreter_dict != NULL) + { + PyObject *pfunc = NULL; + PyObject *pmod = PyImport_AddModule ("embedded_interpreter"); + if (pmod != NULL) + { + PyObject *pmod_dict = PyModule_GetDict (pmod); + if ((pmod_dict != NULL) + && PyDict_Check (pmod_dict)) + { + PyObject *key, *value; + Py_ssize_t pos = 0; + + while (PyDict_Next (pmod_dict, &pos, &key, &value)) + { + Py_INCREF (key); + Py_INCREF (value); + if (strcmp (PyString_AsString (key), "run_one_line") == 0) + { + pfunc = value; + break; + } + } + + PyObject *string_arg = PyString_FromString (command); + if (pfunc && string_arg && PyCallable_Check (pfunc)) + { + PyObject *pargs = PyTuple_New (2); + if (pargs != NULL) + { + PyTuple_SetItem (pargs, 0, script_interpreter_dict); + PyTuple_SetItem (pargs, 1, string_arg); + PyObject *pvalue = PyObject_CallObject (pfunc, pargs); + Py_DECREF (pargs); + if (pvalue != NULL) + { + Py_DECREF (pvalue); + success = true; + } + else if (PyErr_Occurred ()) + { + PyErr_Print(); + PyErr_Clear(); + } + } + } + } + } + Py_INCREF (script_interpreter_dict); + } + } - StreamString sstr; - sstr.Printf ("run_one_line (%s, '%s')", m_dictionary_name.c_str(), command); - success = PyRun_SimpleString (sstr.GetData()); - LeaveSession (); - if (success == 0) + if (success) return true; // The one-liner failed. Append the error message. From wilsons at start.ca Fri Jan 14 15:12:14 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:14 -0500 Subject: [Lldb-commits] [PATCH 0/8] linux: process and object file plugin updates Message-ID: <1295039542-9640-1-git-send-email-wilsons@start.ca> This patch series provides some relatively straightforward updates and fixes to the ProcessLinux and ObjectFileELF plugins. Most notably the new ObjectFile methods GetImageInfoAddress and GetEntryPoint are implemented for ELF's, as well as Process::GetImageInfoAddress. This patch series paves the way for the addition of a new DynamicLoader plugin for Linux that I will be sending out shortly. From wilsons at start.ca Fri Jan 14 15:12:15 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:15 -0500 Subject: [Lldb-commits] [PATCH 1/8] Have LinuxThread cache it's current StopInfo object. In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-2-git-send-email-wilsons@start.ca> --- source/Plugins/Process/Linux/LinuxThread.cpp | 47 ++++++++++++++++---------- source/Plugins/Process/Linux/LinuxThread.h | 4 ++ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/source/Plugins/Process/Linux/LinuxThread.cpp b/source/Plugins/Process/Linux/LinuxThread.cpp index e189064..4ceb051 100644 --- a/source/Plugins/Process/Linux/LinuxThread.cpp +++ b/source/Plugins/Process/Linux/LinuxThread.cpp @@ -40,6 +40,7 @@ LinuxThread::GetMonitor() void LinuxThread::RefreshStateAfterStop() { + RefreshPrivateStopReason(); } const char * @@ -101,24 +102,9 @@ LinuxThread::CreateRegisterContextForFrame (lldb_private::StackFrame *frame) lldb::StopInfoSP LinuxThread::GetPrivateStopReason() { - lldb::StopInfoSP stop_info; - - switch (m_note) - { - default: - break; - - case eBreak: - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( - *this, m_breakpoint->GetID()); - break; - - case eTrace: - stop_info = StopInfo::CreateStopReasonToTrace(*this); - break; - } - - return stop_info; + if (!m_stop_info || !m_stop_info->IsValid()) + RefreshPrivateStopReason(); + return m_stop_info; } Unwind * @@ -196,3 +182,28 @@ LinuxThread::ExitNotify() { m_note = eExit; } + +void +LinuxThread::RefreshPrivateStopReason() +{ + switch (m_note) { + + default: + case eNone: + m_stop_info.reset(); + break; + + case eBreak: + m_stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( + *this, m_breakpoint->GetID()); + break; + + case eTrace: + m_stop_info = StopInfo::CreateStopReasonToTrace(*this); + break; + + case eExit: + m_stop_info = StopInfo::CreateStopReasonWithSignal(*this, SIGCHLD); + break; + } +} diff --git a/source/Plugins/Process/Linux/LinuxThread.h b/source/Plugins/Process/Linux/LinuxThread.h index 4dcdbb3..ee69cf7 100644 --- a/source/Plugins/Process/Linux/LinuxThread.h +++ b/source/Plugins/Process/Linux/LinuxThread.h @@ -72,6 +72,7 @@ private: std::auto_ptr m_frame_ap; lldb::BreakpointSiteSP m_breakpoint; + lldb::StopInfoSP m_stop_info; enum Notification { eNone, @@ -87,6 +88,9 @@ private: lldb::StopInfoSP GetPrivateStopReason(); + void + RefreshPrivateStopReason(); + lldb_private::Unwind * GetUnwinder(); }; -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 15:12:16 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:16 -0500 Subject: [Lldb-commits] [PATCH 2/8] Implement GetEntryPoint, GetImageInfoAddress and GetArchitecture for ObjectFileELF. In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-3-git-send-email-wilsons@start.ca> --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 78 ++++++++++++++++++++++- source/Plugins/ObjectFile/ELF/ObjectFileELF.h | 9 +++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 3f6dd20..5b99d01 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -12,6 +12,7 @@ #include #include +#include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Error.h" #include "lldb/Core/FileSpecList.h" @@ -70,9 +71,10 @@ ObjectFileELF::CreateInstance(Module *module, unsigned address_size = ELFHeader::AddressSizeInBytes(magic); if (address_size == 4 || address_size == 8) { - std::auto_ptr objfile_ap( + std::auto_ptr objfile_ap( new ObjectFileELF(module, data_sp, file, offset, length)); - if (objfile_ap->ParseHeader()) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec.IsValid() && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } } @@ -80,6 +82,15 @@ ObjectFileELF::CreateInstance(Module *module, return NULL; } +ArchSpec +ObjectFileELF::GetArchitecture() +{ + if (!ParseHeader()) + return ArchSpec(); + + return ArchSpec(eArchTypeELF, m_header.e_machine, m_header.e_flags); +} + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -151,6 +162,15 @@ ObjectFileELF::IsExecutable() const return m_header.e_type == ET_EXEC; } +Address +ObjectFileELF::GetEntryPoint() const +{ + if (m_header.e_entry) + return Address(NULL, m_header.e_entry); + else + return Address(); +} + ByteOrder ObjectFileELF::GetByteOrder() const { @@ -208,6 +228,60 @@ ObjectFileELF::GetDependentModules(FileSpecList &files) return num_specs; } +Address +ObjectFileELF::GetImageInfoAddress() +{ + if (!ParseSectionHeaders()) + return Address(); + + user_id_t dynsym_id = 0; + for (SectionHeaderCollIter sh_pos = m_section_headers.begin(); + sh_pos != m_section_headers.end(); ++sh_pos) + { + if (sh_pos->sh_type == SHT_DYNAMIC) + { + dynsym_id = SectionIndex(sh_pos); + break; + } + } + + if (!dynsym_id) + return Address(); + + SectionList *section_list = GetSectionList(); + if (!section_list) + return Address(); + + // Resolve the dynamic table entries. + Section *dynsym = section_list->FindSectionByID(dynsym_id).get(); + if (!dynsym) + return Address(); + + DataExtractor dynsym_data; + if (dynsym->ReadSectionDataFromObjectFile(this, dynsym_data)) + { + ELFDynamic symbol; + const unsigned section_size = dynsym_data.GetByteSize(); + unsigned offset = 0; + unsigned cursor = 0; + + // Look for a DT_DEBUG entry. + while (cursor < section_size) + { + offset = cursor; + if (!symbol.Parse(dynsym_data, &cursor)) + break; + + if (symbol.d_tag != DT_DEBUG) + continue; + + return Address(dynsym, offset + sizeof(symbol.d_tag)); + } + } + + return Address(); +} + //---------------------------------------------------------------------- // ParseDependentModules //---------------------------------------------------------------------- diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index e91fabb..69a9a68 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -89,6 +89,9 @@ public: virtual bool IsExecutable () const; + virtual lldb_private::Address + GetEntryPoint() const; + virtual size_t GetAddressByteSize() const; @@ -110,6 +113,12 @@ public: virtual uint32_t GetDependentModules(lldb_private::FileSpecList& files); + virtual lldb_private::Address + GetImageInfoAddress(); + + lldb_private::ArchSpec + GetArchitecture(); + private: ObjectFileELF(lldb_private::Module* module, lldb::DataBufferSP& dataSP, -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 15:12:17 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:17 -0500 Subject: [Lldb-commits] [PATCH 3/8] Test if an ELF object is executable by checking if an entry point is defined. In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-4-git-send-email-wilsons@start.ca> The previous check on header type ET_EXEC is not general enough. Position independent executables have type ET_DYN. --- source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 5b99d01..f58c779 100644 --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -159,7 +159,7 @@ ObjectFileELF::~ObjectFileELF() bool ObjectFileELF::IsExecutable() const { - return m_header.e_type == ET_EXEC; + return m_header.e_entry != 0; } Address -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 15:12:18 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:18 -0500 Subject: [Lldb-commits] [PATCH 4/8] Implement ProcessLinux::GetImageInfoAddress(). In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-5-git-send-email-wilsons@start.ca> --- source/Plugins/Process/Linux/ProcessLinux.cpp | 13 +++++++++++++ source/Plugins/Process/Linux/ProcessLinux.h | 3 +++ 2 files changed, 16 insertions(+), 0 deletions(-) diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp index 5e9a19d..6e9c0fb 100644 --- a/source/Plugins/Process/Linux/ProcessLinux.cpp +++ b/source/Plugins/Process/Linux/ProcessLinux.cpp @@ -149,6 +149,19 @@ ProcessLinux::DoResume() return Error(); } +addr_t +ProcessLinux::GetImageInfoAddress() +{ + Target *target = &GetTarget(); + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(); + + if (addr.IsValid()) + return addr.GetLoadAddress(target); + else + return LLDB_INVALID_ADDRESS; +} + Error ProcessLinux::DoHalt(bool &caused_stop) { diff --git a/source/Plugins/Process/Linux/ProcessLinux.h b/source/Plugins/Process/Linux/ProcessLinux.h index 16c2bec..3e23a7a 100644 --- a/source/Plugins/Process/Linux/ProcessLinux.h +++ b/source/Plugins/Process/Linux/ProcessLinux.h @@ -128,6 +128,9 @@ public: virtual lldb::ByteOrder GetByteOrder() const; + virtual lldb::addr_t + GetImageInfoAddress(); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 15:12:20 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:20 -0500 Subject: [Lldb-commits] [PATCH 6/8] Miscellaneous cleanups in ProcessMonitor. In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-7-git-send-email-wilsons@start.ca> Propagate the environment if one is not provided. Also, do not allocate the monitor threads launch arguments on the stack (let the monitor thread assume ownership). --- source/Plugins/Process/Linux/ProcessMonitor.cpp | 29 +++++++++++++++-------- 1 files changed, 19 insertions(+), 10 deletions(-) diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp index 1522263..8dd9804 100644 --- a/source/Plugins/Process/Linux/ProcessMonitor.cpp +++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -463,7 +463,7 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, m_client_fd(-1), m_server_fd(-1) { - LaunchArgs args(this, module, argv, envp, + LaunchArgs *args = new LaunchArgs(this, module, argv, envp, stdin_path, stdout_path, stderr_path); // Server/client descriptors. @@ -473,13 +473,13 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, error.SetErrorString("Monitor failed to initialize."); } - StartOperationThread(&args, error); + StartOperationThread(args, error); if (!error.Success()) return; WAIT_AGAIN: // Wait for the operation thread to initialize. - if (sem_wait(&args.m_semaphore)) + if (sem_wait(&args->m_semaphore)) { if (errno == EINTR) goto WAIT_AGAIN; @@ -491,16 +491,17 @@ WAIT_AGAIN: } // Check that the launch was a success. - if (!args.m_error.Success()) + if (!args->m_error.Success()) { StopOperationThread(); - error = args.m_error; + error = args->m_error; return; } // Finally, start monitoring the child process for change in state. - if (!(m_monitor_thread = Host::StartMonitoringChildProcess( - ProcessMonitor::MonitorCallback, this, GetPID(), true))) + m_monitor_thread = Host::StartMonitoringChildProcess( + ProcessMonitor::MonitorCallback, this, GetPID(), true); + if (m_monitor_thread == LLDB_INVALID_HOST_THREAD) { error.SetErrorToGenericError(); error.SetErrorString("Process launch failed."); @@ -524,12 +525,16 @@ void ProcessMonitor::StartOperationThread(LaunchArgs *args, Error &error) { static const char *g_thread_name = "lldb.process.linux.operation"; + std::auto_ptr args_ap(args); if (m_operation_thread != LLDB_INVALID_HOST_THREAD) return; m_operation_thread = Host::ThreadCreate(g_thread_name, OperationThread, args, &error); + + if (error.Success()) + args_ap.release(); } void @@ -547,12 +552,12 @@ ProcessMonitor::StopOperationThread() void * ProcessMonitor::OperationThread(void *arg) { - LaunchArgs *args = static_cast(arg); + std::auto_ptr args_ap(static_cast(arg)); - if (!Launch(args)) + if (!Launch(args_ap.get())) return NULL; - ServeOperation(args->m_monitor); + ServeOperation(args_ap->m_monitor); return NULL; } @@ -574,6 +579,10 @@ ProcessMonitor::Launch(LaunchArgs *args) lldb::ThreadSP inferior; + // Propagate the environment if one is not supplied. + if (envp == NULL || envp[0] == NULL) + envp = const_cast(environ); + // Pseudo terminal setup. if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len)) { -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 15:12:21 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:21 -0500 Subject: [Lldb-commits] [PATCH 7/8] Set the ID of a ProcessLinux instance to the PID of the inferior on launch. In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-8-git-send-email-wilsons@start.ca> --- source/Plugins/Process/Linux/ProcessLinux.cpp | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp index 6e9c0fb..00bdda5 100644 --- a/source/Plugins/Process/Linux/ProcessLinux.cpp +++ b/source/Plugins/Process/Linux/ProcessLinux.cpp @@ -124,6 +124,7 @@ ProcessLinux::DoLaunch(Module *module, if (!error.Success()) return error; + SetID(m_monitor->GetPID()); return error; } -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 15:12:19 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:19 -0500 Subject: [Lldb-commits] [PATCH 5/8] Use the correct type for thread handle. In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-6-git-send-email-wilsons@start.ca> --- source/Plugins/Process/Linux/ProcessMonitor.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/source/Plugins/Process/Linux/ProcessMonitor.h b/source/Plugins/Process/Linux/ProcessMonitor.h index 7c3ae74..431fab7 100644 --- a/source/Plugins/Process/Linux/ProcessMonitor.h +++ b/source/Plugins/Process/Linux/ProcessMonitor.h @@ -140,7 +140,7 @@ private: lldb::pid_t m_pid; int m_terminal_fd; - uint32_t m_monitor_thread; + lldb::thread_t m_monitor_thread; lldb_private::Mutex m_server_mutex; int m_client_fd; -- 1.7.3.5 From wilsons at start.ca Fri Jan 14 15:12:22 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 16:12:22 -0500 Subject: [Lldb-commits] [PATCH 8/8] Add empty implementation of pure virtual RegisterContext::InvalidateAllRegisters. In-Reply-To: <1295039542-9640-1-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> Message-ID: <1295039542-9640-9-git-send-email-wilsons@start.ca> --- .../Process/Linux/RegisterContextLinux_x86_64.cpp | 5 +++++ .../Process/Linux/RegisterContextLinux_x86_64.h | 3 +++ 2 files changed, 8 insertions(+), 0 deletions(-) diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp index da6ea8d..27cd6c6 100644 --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp @@ -423,6 +423,11 @@ RegisterContextLinux_x86_64::Invalidate() { } +void +RegisterContextLinux_x86_64::InvalidateAllRegisters() +{ +} + size_t RegisterContextLinux_x86_64::GetRegisterCount() { diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h index dc421ec..876d685 100644 --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h @@ -26,6 +26,9 @@ public: void Invalidate(); + void + InvalidateAllRegisters(); + size_t GetRegisterCount(); -- 1.7.3.5 From johnny.chen at apple.com Fri Jan 14 15:18:12 2011 From: johnny.chen at apple.com (Johnny Chen) Date: Fri, 14 Jan 2011 21:18:12 -0000 Subject: [Lldb-commits] [lldb] r123469 - /lldb/trunk/test/make/Makefile.rules Message-ID: <20110114211812.453682A6C12C@llvm.org> Author: johnny Date: Fri Jan 14 15:18:12 2011 New Revision: 123469 URL: http://llvm.org/viewvc/llvm-project?rev=123469&view=rev Log: Add makefile debugging rule for printing out the value of a variable. >From http://blog.melski.net/tag/debugging-makefiles/. Example: [13:14:59] johnny:/Volumes/data/lldb/svn/trunk/test/class_static $ make print-CC CC=gcc origin = file flavor = recursive value = gcc [13:15:09] johnny:/Volumes/data/lldb/svn/trunk/test/class_static $ make print-LD LD= g++ origin = file flavor = recursive value = $(call cxx_linker,$(CC)) [13:15:21] johnny:/Volumes/data/lldb/svn/trunk/test/class_static $ make print-CXX CXX= g++ origin = file flavor = recursive value = $(call cxx_compiler,$(CC)) [13:15:29] johnny:/Volumes/data/lldb/svn/trunk/test/class_static $ Modified: lldb/trunk/test/make/Makefile.rules Modified: lldb/trunk/test/make/Makefile.rules URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/make/Makefile.rules?rev=123469&r1=123468&r2=123469&view=diff ============================================================================== --- lldb/trunk/test/make/Makefile.rules (original) +++ lldb/trunk/test/make/Makefile.rules Fri Jan 14 15:18:12 2011 @@ -175,3 +175,14 @@ else rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS) $(DYLIB_OBJECTS) $(DYLIB_NAME) $(DYLIB_NAME).dSYM endif + +#---------------------------------------------------------------------- +# From http://blog.melski.net/tag/debugging-makefiles/ +# +# Usage: make print-CC print-CXX print-LD +#---------------------------------------------------------------------- +print-%: + @echo '$*=$($*)' + @echo ' origin = $(origin $*)' + @echo ' flavor = $(flavor $*)' + @echo ' value = $(value $*)' From gclayton at apple.com Fri Jan 14 15:34:58 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 13:34:58 -0800 Subject: [Lldb-commits] [PATCH 3/8] Test if an ELF object is executable by checking if an entry point is defined. In-Reply-To: <1295039542-9640-4-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-4-git-send-email-wilsons@start.ca> Message-ID: <7A4E6B48-9A78-4414-B6E2-BD36D07B65F6@apple.com> Could a bootloader ELF file have an entry point of zero? Should this be: bool ObjectFileELF::IsExecutable() const { return m_header.e_entry != LLDB_INVALID_ADDRESS; } And then you would need to make sure that m_header.e_entry always gets initialized to LLDB_INVALID_ADDRESS? On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > The previous check on header type ET_EXEC is not general enough. Position > independent executables have type ET_DYN. > --- > source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp > index 5b99d01..f58c779 100644 > --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp > +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp > @@ -159,7 +159,7 @@ ObjectFileELF::~ObjectFileELF() > bool > ObjectFileELF::IsExecutable() const > { > - return m_header.e_type == ET_EXEC; > + return m_header.e_entry != 0; > } > > Address > -- > 1.7.3.5 > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From gclayton at apple.com Fri Jan 14 15:35:25 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 13:35:25 -0800 Subject: [Lldb-commits] [PATCH 4/8] Implement ProcessLinux::GetImageInfoAddress(). In-Reply-To: <1295039542-9640-5-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-5-git-send-email-wilsons@start.ca> Message-ID: <79C732C6-62F6-49F9-82C4-183B6BE03B7D@apple.com> Looks good. On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > --- > source/Plugins/Process/Linux/ProcessLinux.cpp | 13 +++++++++++++ > source/Plugins/Process/Linux/ProcessLinux.h | 3 +++ > 2 files changed, 16 insertions(+), 0 deletions(-) > > diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp > index 5e9a19d..6e9c0fb 100644 > --- a/source/Plugins/Process/Linux/ProcessLinux.cpp > +++ b/source/Plugins/Process/Linux/ProcessLinux.cpp > @@ -149,6 +149,19 @@ ProcessLinux::DoResume() > return Error(); > } > > +addr_t > +ProcessLinux::GetImageInfoAddress() > +{ > + Target *target = &GetTarget(); > + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); > + Address addr = obj_file->GetImageInfoAddress(); > + > + if (addr.IsValid()) > + return addr.GetLoadAddress(target); > + else > + return LLDB_INVALID_ADDRESS; > +} > + > Error > ProcessLinux::DoHalt(bool &caused_stop) > { > diff --git a/source/Plugins/Process/Linux/ProcessLinux.h b/source/Plugins/Process/Linux/ProcessLinux.h > index 16c2bec..3e23a7a 100644 > --- a/source/Plugins/Process/Linux/ProcessLinux.h > +++ b/source/Plugins/Process/Linux/ProcessLinux.h > @@ -128,6 +128,9 @@ public: > virtual lldb::ByteOrder > GetByteOrder() const; > > + virtual lldb::addr_t > + GetImageInfoAddress(); > + > //------------------------------------------------------------------ > // PluginInterface protocol > //------------------------------------------------------------------ > -- > 1.7.3.5 > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From gclayton at apple.com Fri Jan 14 15:41:59 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 13:41:59 -0800 Subject: [Lldb-commits] [PATCH 6/8] Miscellaneous cleanups in ProcessMonitor. In-Reply-To: <1295039542-9640-7-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-7-git-send-email-wilsons@start.ca> Message-ID: <7962DEC7-6AA6-4021-B30B-AB8A8EA070F3@apple.com> The lifetime of args seems possibly racy? What if "StartOperationThread()" spawns a thread which gets an error and exits super quickly, could the thread put "args" into its auto_ptr and delete "args" before the code that launches that thread is done with "args"? I can't see all the code here, so I am just curious. Other than that check, it looks good. On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > Propagate the environment if one is not provided. Also, do not allocate the > monitor threads launch arguments on the stack (let the monitor thread assume > ownership). > --- > source/Plugins/Process/Linux/ProcessMonitor.cpp | 29 +++++++++++++++-------- > 1 files changed, 19 insertions(+), 10 deletions(-) > > diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp > index 1522263..8dd9804 100644 > --- a/source/Plugins/Process/Linux/ProcessMonitor.cpp > +++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp > @@ -463,7 +463,7 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, > m_client_fd(-1), > m_server_fd(-1) > { > - LaunchArgs args(this, module, argv, envp, > + LaunchArgs *args = new LaunchArgs(this, module, argv, envp, > stdin_path, stdout_path, stderr_path); > > // Server/client descriptors. > @@ -473,13 +473,13 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, > error.SetErrorString("Monitor failed to initialize."); > } > > - StartOperationThread(&args, error); > + StartOperationThread(args, error); > if (!error.Success()) > return; > > WAIT_AGAIN: > // Wait for the operation thread to initialize. > - if (sem_wait(&args.m_semaphore)) > + if (sem_wait(&args->m_semaphore)) > { > if (errno == EINTR) > goto WAIT_AGAIN; > @@ -491,16 +491,17 @@ WAIT_AGAIN: > } > > // Check that the launch was a success. > - if (!args.m_error.Success()) > + if (!args->m_error.Success()) > { > StopOperationThread(); > - error = args.m_error; > + error = args->m_error; > return; > } > > // Finally, start monitoring the child process for change in state. > - if (!(m_monitor_thread = Host::StartMonitoringChildProcess( > - ProcessMonitor::MonitorCallback, this, GetPID(), true))) > + m_monitor_thread = Host::StartMonitoringChildProcess( > + ProcessMonitor::MonitorCallback, this, GetPID(), true); > + if (m_monitor_thread == LLDB_INVALID_HOST_THREAD) > { > error.SetErrorToGenericError(); > error.SetErrorString("Process launch failed."); > @@ -524,12 +525,16 @@ void > ProcessMonitor::StartOperationThread(LaunchArgs *args, Error &error) > { > static const char *g_thread_name = "lldb.process.linux.operation"; > + std::auto_ptr args_ap(args); > > if (m_operation_thread != LLDB_INVALID_HOST_THREAD) > return; > > m_operation_thread = > Host::ThreadCreate(g_thread_name, OperationThread, args, &error); > + > + if (error.Success()) > + args_ap.release(); > } > > void > @@ -547,12 +552,12 @@ ProcessMonitor::StopOperationThread() > void * > ProcessMonitor::OperationThread(void *arg) > { > - LaunchArgs *args = static_cast(arg); > + std::auto_ptr args_ap(static_cast(arg)); > > - if (!Launch(args)) > + if (!Launch(args_ap.get())) > return NULL; > > - ServeOperation(args->m_monitor); > + ServeOperation(args_ap->m_monitor); > return NULL; > } > > @@ -574,6 +579,10 @@ ProcessMonitor::Launch(LaunchArgs *args) > > lldb::ThreadSP inferior; > > + // Propagate the environment if one is not supplied. > + if (envp == NULL || envp[0] == NULL) > + envp = const_cast(environ); > + > // Pseudo terminal setup. > if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len)) > { > -- > 1.7.3.5 > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From gclayton at apple.com Fri Jan 14 15:46:24 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 13:46:24 -0800 Subject: [Lldb-commits] [PATCH 7/8] Set the ID of a ProcessLinux instance to the PID of the inferior on launch. In-Reply-To: <1295039542-9640-8-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-8-git-send-email-wilsons@start.ca> Message-ID: <30785D6F-3C39-410B-91EA-4E220938894F@apple.com> Good. On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > --- > source/Plugins/Process/Linux/ProcessLinux.cpp | 1 + > 1 files changed, 1 insertions(+), 0 deletions(-) > > diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp > index 6e9c0fb..00bdda5 100644 > --- a/source/Plugins/Process/Linux/ProcessLinux.cpp > +++ b/source/Plugins/Process/Linux/ProcessLinux.cpp > @@ -124,6 +124,7 @@ ProcessLinux::DoLaunch(Module *module, > if (!error.Success()) > return error; > > + SetID(m_monitor->GetPID()); > return error; > } > > -- > 1.7.3.5 > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From gclayton at apple.com Fri Jan 14 15:47:34 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 13:47:34 -0800 Subject: [Lldb-commits] [PATCH 5/8] Use the correct type for thread handle. In-Reply-To: <1295039542-9640-6-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-6-git-send-email-wilsons@start.ca> Message-ID: <10154A14-11B6-4F0B-8776-18A79C2EB15A@apple.com> Good. On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > --- > source/Plugins/Process/Linux/ProcessMonitor.h | 2 +- > 1 files changed, 1 insertions(+), 1 deletions(-) > > diff --git a/source/Plugins/Process/Linux/ProcessMonitor.h b/source/Plugins/Process/Linux/ProcessMonitor.h > index 7c3ae74..431fab7 100644 > --- a/source/Plugins/Process/Linux/ProcessMonitor.h > +++ b/source/Plugins/Process/Linux/ProcessMonitor.h > @@ -140,7 +140,7 @@ private: > lldb::pid_t m_pid; > int m_terminal_fd; > > - uint32_t m_monitor_thread; > + lldb::thread_t m_monitor_thread; > > lldb_private::Mutex m_server_mutex; > int m_client_fd; > -- > 1.7.3.5 > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From gclayton at apple.com Fri Jan 14 15:50:42 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 13:50:42 -0800 Subject: [Lldb-commits] [PATCH 8/8] Add empty implementation of pure virtual RegisterContext::InvalidateAllRegisters. In-Reply-To: <1295039542-9640-9-git-send-email-wilsons@start.ca> References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-9-git-send-email-wilsons@start.ca> Message-ID: Here is where you will want to track if you have read your regiters from what ever you read registers from on Linux. You might to just want to copy the "lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp" and "lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h" files and modify the structures to match linux. This has all of the invalidating code done on a per/register group basis (gpr, fpu and exc registers). On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > --- > .../Process/Linux/RegisterContextLinux_x86_64.cpp | 5 +++++ > .../Process/Linux/RegisterContextLinux_x86_64.h | 3 +++ > 2 files changed, 8 insertions(+), 0 deletions(-) > > diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp > index da6ea8d..27cd6c6 100644 > --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp > +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp > @@ -423,6 +423,11 @@ RegisterContextLinux_x86_64::Invalidate() > { > } > > +void > +RegisterContextLinux_x86_64::InvalidateAllRegisters() > +{ > +} > + > size_t > RegisterContextLinux_x86_64::GetRegisterCount() > { > diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h > index dc421ec..876d685 100644 > --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h > +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h > @@ -26,6 +26,9 @@ public: > void > Invalidate(); > > + void > + InvalidateAllRegisters(); > + > size_t > GetRegisterCount(); > > -- > 1.7.3.5 > > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From johnny.chen at apple.com Fri Jan 14 15:55:29 2011 From: johnny.chen at apple.com (Johnny Chen) Date: Fri, 14 Jan 2011 21:55:29 -0000 Subject: [Lldb-commits] [lldb] r123471 - /lldb/trunk/test/objc/Makefile Message-ID: <20110114215529.E1B792A6C12C@llvm.org> Author: johnny Date: Fri Jan 14 15:55:29 2011 New Revision: 123471 URL: http://llvm.org/viewvc/llvm-project?rev=123471&view=rev Log: Converted to use Makefile.rules. Modified: lldb/trunk/test/objc/Makefile Modified: lldb/trunk/test/objc/Makefile URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/objc/Makefile?rev=123471&r1=123470&r2=123471&view=diff ============================================================================== --- lldb/trunk/test/objc/Makefile (original) +++ lldb/trunk/test/objc/Makefile Fri Jan 14 15:55:29 2011 @@ -1,125 +1,6 @@ -#---------------------------------------------------------------------- -# Fill in the source files to build -#---------------------------------------------------------------------- -C_SOURCES := -CXX_SOURCES := -OBJC_SOURCES :=main.m -OBJCXX_SOURCES := +LEVEL = ../make -# Uncomment line below for debugging shell commands -# SHELL = /bin/sh -x - -#---------------------------------------------------------------------- -# Change any build/tool options needed -#---------------------------------------------------------------------- -DS := /usr/bin/dsymutil -DSFLAGS = -CFLAGS ?=-arch x86_64 -g -O0 -CPLUSPLUSFLAGS +=$(CFLAGS) -CPPFLAGS +=$(CFLAGS) -LD = gcc +OBJC_SOURCES := main.m LDFLAGS = $(CFLAGS) -lobjc -framework Foundation -OBJECTS = -EXE=a.out -DSYM=$(EXE).dSYM - -#---------------------------------------------------------------------- -# Check if we have any C source files -#---------------------------------------------------------------------- -ifneq "$(strip $(C_SOURCES))" "" - OBJECTS +=$(strip $(C_SOURCES:.c=.o)) -endif - -#---------------------------------------------------------------------- -# Check if we have any C++ source files -#---------------------------------------------------------------------- -ifneq "$(strip $(CXX_SOURCES))" "" - OBJECTS +=$(strip $(CXX_SOURCES:.cpp=.o)) - LD = g++ -endif - -#---------------------------------------------------------------------- -# Check if we have any ObjC source files -#---------------------------------------------------------------------- -ifneq "$(strip $(OBJC_SOURCES))" "" - OBJECTS +=$(strip $(OBJC_SOURCES:.m=.o)) - LDFLAGS +=-lobjc -endif - -#---------------------------------------------------------------------- -# Check if we have any ObjC++ source files -#---------------------------------------------------------------------- -ifneq "$(strip $(OBJCXX_SOURCES))" "" - OBJECTS +=$(strip $(OBJCXX_SOURCES:.mm=.o)) - LD = g++ - ifeq $(findstring lobjc,$(LDFLAGS)) "" - LDFLAGS +=-lobjc - endif -endif - - -#---------------------------------------------------------------------- -# Make the dSYM file from the executable -#---------------------------------------------------------------------- -$(DSYM) : $(EXE) - $(DS) $(DSFLAGS) -o "$(DSYM)" "$(EXE)" - -#---------------------------------------------------------------------- -# Compile the executable from all the objects (default rule) with no -# dsym file. -#---------------------------------------------------------------------- -$(EXE) : $(OBJECTS) - $(LD) $(LDFLAGS) $(OBJECTS) -o "$(EXE)" - - -#---------------------------------------------------------------------- -# Automatic variables based on items already entered. Below we create -# an objects lists from the list of sources by replacing all entries -# that end with .c with .o, and we also create a list of prerequisite -# files by replacing all .c files with .d. -#---------------------------------------------------------------------- -PREREQS := $(OBJECTS:.o=.d) - -#---------------------------------------------------------------------- -# Rule for Generating Prerequisites Automatically using .d files and -# the compiler -MM option. The -M option will list all system headers, -# and the -MM option will list all non-system dependencies. -#---------------------------------------------------------------------- -%.d: %.c - @set -e; rm -f $@; \ - $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ - sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ - rm -f $@.$$$$ - -%.d: %.cpp - @set -e; rm -f $@; \ - $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ - sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ - rm -f $@.$$$$ - -%.d: %.m - @set -e; rm -f $@; \ - $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ - sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ - rm -f $@.$$$$ - -%.d: %.mm - @set -e; rm -f $@; \ - $(CC) -M $(CPPFLAGS) $< > $@.$$$$; \ - sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ - rm -f $@.$$$$ - -#---------------------------------------------------------------------- -# Include all of the makefiles for each source file so we don't have -# to manually track all of the prerequisites for each source file. -#---------------------------------------------------------------------- -sinclude $(PREREQS) - -.PHONY: clean -dsym: $(DSYM) -all: $(EXE) $(DSYM) -clean: - rm -rf "$(EXE)" "$(DSYM)" $(OBJECTS) $(PREREQS) - - +include $(LEVEL)/Makefile.rules From wilsons at start.ca Fri Jan 14 16:19:38 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 17:19:38 -0500 Subject: [Lldb-commits] [PATCH 3/8] Test if an ELF object is executable by checking if an entry point is defined. In-Reply-To: <7A4E6B48-9A78-4414-B6E2-BD36D07B65F6@apple.com> (Greg Clayton's message of "Fri, 14 Jan 2011 13:34:58 -0800") References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-4-git-send-email-wilsons@start.ca> <7A4E6B48-9A78-4414-B6E2-BD36D07B65F6@apple.com> Message-ID: Greg Clayton writes: > Could a bootloader ELF file have an entry point of zero? Should this be: Interesting question. I have never seen one myself (but that does not mean they do not exist). However the spec specifically says that if an ELF does not have an entry point then this field must be zero. For that reason I think this should be a relatively safe test. > bool > ObjectFileELF::IsExecutable() const > { > return m_header.e_entry != LLDB_INVALID_ADDRESS; > } > > And then you would need to make sure that m_header.e_entry always gets initialized to LLDB_INVALID_ADDRESS? > > > On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > >> The previous check on header type ET_EXEC is not general enough. Position >> independent executables have type ET_DYN. >> --- >> source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 2 +- >> 1 files changed, 1 insertions(+), 1 deletions(-) >> >> diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp >> index 5b99d01..f58c779 100644 >> --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp >> +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp >> @@ -159,7 +159,7 @@ ObjectFileELF::~ObjectFileELF() >> bool >> ObjectFileELF::IsExecutable() const >> { >> - return m_header.e_type == ET_EXEC; >> + return m_header.e_entry != 0; >> } >> >> Address >> -- >> 1.7.3.5 >> >> _______________________________________________ >> lldb-commits mailing list >> lldb-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits > -- steve From wilsons at start.ca Fri Jan 14 16:57:48 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 17:57:48 -0500 Subject: [Lldb-commits] [PATCH 6/8] Miscellaneous cleanups in ProcessMonitor. In-Reply-To: <7962DEC7-6AA6-4021-B30B-AB8A8EA070F3@apple.com> (Greg Clayton's message of "Fri, 14 Jan 2011 13:41:59 -0800") References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-7-git-send-email-wilsons@start.ca> <7962DEC7-6AA6-4021-B30B-AB8A8EA070F3@apple.com> Message-ID: Greg Clayton writes: > The lifetime of args seems possibly racy? What if > "StartOperationThread()" spawns a thread which gets an error and exits > super quickly, could the thread put "args" into its auto_ptr and > delete "args" before the code that launches that thread is done with > "args"? I can't see all the code here, so I am just curious. I took another look over the code. You are right, there is a race if the monitor thread encounters an error when launching the inferior. This corrected patch uses the previous approach of having the parent thread maintain ownership. Holding onto the launch args in an auto_ptr should be safe here since we synchronize with the child thread via a semaphore, and the child does not reference the launch args beyond that point. Thanks for the review! Miscellaneous cleanups in ProcessMonitor. Propagate the environment if one is not provided. Also, do not allocate the monitor threads launch arguments on the stack. diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp index 1522263..f21cb00 100644 --- a/source/Plugins/Process/Linux/ProcessMonitor.cpp +++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -463,8 +463,10 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, m_client_fd(-1), m_server_fd(-1) { - LaunchArgs args(this, module, argv, envp, - stdin_path, stdout_path, stderr_path); + std::auto_ptr args; + + args.reset(new LaunchArgs(this, module, argv, envp, + stdin_path, stdout_path, stderr_path)); // Server/client descriptors. if (!EnableIPC()) @@ -473,13 +475,13 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, error.SetErrorString("Monitor failed to initialize."); } - StartOperationThread(&args, error); + StartOperationThread(args.get(), error); if (!error.Success()) return; WAIT_AGAIN: // Wait for the operation thread to initialize. - if (sem_wait(&args.m_semaphore)) + if (sem_wait(&args->m_semaphore)) { if (errno == EINTR) goto WAIT_AGAIN; @@ -491,16 +493,17 @@ WAIT_AGAIN: } // Check that the launch was a success. - if (!args.m_error.Success()) + if (!args->m_error.Success()) { StopOperationThread(); - error = args.m_error; + error = args->m_error; return; } // Finally, start monitoring the child process for change in state. - if (!(m_monitor_thread = Host::StartMonitoringChildProcess( - ProcessMonitor::MonitorCallback, this, GetPID(), true))) + m_monitor_thread = Host::StartMonitoringChildProcess( + ProcessMonitor::MonitorCallback, this, GetPID(), true); + if (m_monitor_thread == LLDB_INVALID_HOST_THREAD) { error.SetErrorToGenericError(); error.SetErrorString("Process launch failed."); @@ -574,6 +577,10 @@ ProcessMonitor::Launch(LaunchArgs *args) lldb::ThreadSP inferior; + // Propagate the environment if one is not supplied. + if (envp == NULL || envp[0] == NULL) + envp = const_cast(environ); + // Pseudo terminal setup. if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len)) { From wilsons at start.ca Fri Jan 14 17:01:29 2011 From: wilsons at start.ca (Stephen Wilson) Date: Fri, 14 Jan 2011 18:01:29 -0500 Subject: [Lldb-commits] [PATCH 8/8] Add empty implementation of pure virtual RegisterContext::InvalidateAllRegisters. In-Reply-To: (Greg Clayton's message of "Fri, 14 Jan 2011 13:50:42 -0800") References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-9-git-send-email-wilsons@start.ca> Message-ID: Greg Clayton writes: > Here is where you will want to track if you have read your regiters > from what ever you read registers from on Linux. OK. > You might to just want to copy the > "lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp" > and > "lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h" > files and modify the structures to match linux. This has all of the > invalidating code done on a per/register group basis (gpr, fpu and exc > registers). Absolutely. Is it OK for this patch to go in as is? Since the method is pure virtual this empty implementation simply allows the tree to build. I will certainly look into implementing the method properly in the near future. > > On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: > >> --- >> .../Process/Linux/RegisterContextLinux_x86_64.cpp | 5 +++++ >> .../Process/Linux/RegisterContextLinux_x86_64.h | 3 +++ >> 2 files changed, 8 insertions(+), 0 deletions(-) >> >> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp >> index da6ea8d..27cd6c6 100644 >> --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp >> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp >> @@ -423,6 +423,11 @@ RegisterContextLinux_x86_64::Invalidate() >> { >> } >> >> +void >> +RegisterContextLinux_x86_64::InvalidateAllRegisters() >> +{ >> +} >> + >> size_t >> RegisterContextLinux_x86_64::GetRegisterCount() >> { >> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h >> index dc421ec..876d685 100644 >> --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h >> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h >> @@ -26,6 +26,9 @@ public: >> void >> Invalidate(); >> >> + void >> + InvalidateAllRegisters(); >> + >> size_t >> GetRegisterCount(); >> >> -- >> 1.7.3.5 >> >> _______________________________________________ >> lldb-commits mailing list >> lldb-commits at cs.uiuc.edu >> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits > -- steve From gclayton at apple.com Fri Jan 14 17:37:51 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 23:37:51 -0000 Subject: [Lldb-commits] [lldb] r123492 - /lldb/trunk/include/lldb/Host/Predicate.h Message-ID: <20110114233751.B3EC02A6C12C@llvm.org> Author: gclayton Date: Fri Jan 14 17:37:51 2011 New Revision: 123492 URL: http://llvm.org/viewvc/llvm-project?rev=123492&view=rev Log: Added the ability to wait for a predicate value, and set it to a new value all in a thread safe fashion. Modified: lldb/trunk/include/lldb/Host/Predicate.h Modified: lldb/trunk/include/lldb/Host/Predicate.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Predicate.h?rev=123492&r1=123491&r2=123492&view=diff ============================================================================== --- lldb/trunk/include/lldb/Host/Predicate.h (original) +++ lldb/trunk/include/lldb/Host/Predicate.h Fri Jan 14 17:37:51 2011 @@ -320,6 +320,38 @@ return m_value == value; } + bool + WaitForValueEqualToAndSetValueTo (T wait_value, T new_value, const TimeValue *abstime = NULL, bool *timed_out = NULL) + { + int err = 0; + // pthread_cond_timedwait() or pthread_cond_wait() will atomically + // unlock the mutex and wait for the condition to be set. When either + // function returns, they will re-lock the mutex. We use an auto lock/unlock + // class (Mutex::Locker) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + Mutex::Locker locker(m_mutex); + +#ifdef DB_PTHREAD_LOG_EVENTS + printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x", __FUNCTION__, value, abstime, m_value); +#endif + if (timed_out) + *timed_out = false; + + while (err == 0 && m_value != wait_value) + { + err = m_condition.Wait (m_mutex.GetMutex(), abstime, timed_out); + } + + if (m_value == wait_value) + { + m_value = new_value; + return true; + } + + return false; + } + + //------------------------------------------------------------------ /// Wait for \a m_value to not be equal to \a value. /// From gclayton at apple.com Fri Jan 14 17:43:29 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 15:43:29 -0800 Subject: [Lldb-commits] [PATCH 3/8] Test if an ELF object is executable by checking if an entry point is defined. In-Reply-To: References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-4-git-send-email-wilsons@start.ca> <7A4E6B48-9A78-4414-B6E2-BD36D07B65F6@apple.com> Message-ID: <5F0711E4-09C6-4D6F-9D02-CFD98758B17F@apple.com> Sounds good, just checking. On Jan 14, 2011, at 2:19 PM, Stephen Wilson wrote: > Greg Clayton writes: > >> Could a bootloader ELF file have an entry point of zero? Should this be: > > Interesting question. I have never seen one myself (but that does not > mean they do not exist). > > However the spec specifically says that if an ELF does not have an entry > point then this field must be zero. For that reason I think this should > be a relatively safe test. > > >> bool >> ObjectFileELF::IsExecutable() const >> { >> return m_header.e_entry != LLDB_INVALID_ADDRESS; >> } >> >> And then you would need to make sure that m_header.e_entry always gets initialized to LLDB_INVALID_ADDRESS? >> >> >> On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: >> >>> The previous check on header type ET_EXEC is not general enough. Position >>> independent executables have type ET_DYN. >>> --- >>> source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 2 +- >>> 1 files changed, 1 insertions(+), 1 deletions(-) >>> >>> diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp >>> index 5b99d01..f58c779 100644 >>> --- a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp >>> +++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp >>> @@ -159,7 +159,7 @@ ObjectFileELF::~ObjectFileELF() >>> bool >>> ObjectFileELF::IsExecutable() const >>> { >>> - return m_header.e_type == ET_EXEC; >>> + return m_header.e_entry != 0; >>> } >>> >>> Address >>> -- >>> 1.7.3.5 >>> >>> _______________________________________________ >>> lldb-commits mailing list >>> lldb-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits >> > > > > -- > steve From gclayton at apple.com Fri Jan 14 17:49:08 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 15:49:08 -0800 Subject: [Lldb-commits] [PATCH 6/8] Miscellaneous cleanups in ProcessMonitor. In-Reply-To: References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-7-git-send-email-wilsons@start.ca> <7962DEC7-6AA6-4021-B30B-AB8A8EA070F3@apple.com> Message-ID: <5553927F-5974-41E7-A196-0D907609BB22@apple.com> Yep, just make sure if the parent of the thread goes away, that it is sure to make the thread terminate otherwise the parent will delete the value in the auto_ptr and the still running thread might crash? Most of our code has a parent class object that might spawn a thread, then the parent object will pass itself (the "this" pointer to the thread), and the parent object ensures that the thread is shut down properly when it "void Clear()" is called on the object. The destructor of the parent object then calls Clear() to make sure the thread shuts down. Then you can call accessors on the parent class object to get the LaunchArgs data. Feel free to take your own approch, but I just wanted to tell you what other code is commonly doing withing LLDB. Greg Clayton On Jan 14, 2011, at 2:57 PM, Stephen Wilson wrote: > Greg Clayton writes: > >> The lifetime of args seems possibly racy? What if >> "StartOperationThread()" spawns a thread which gets an error and exits >> super quickly, could the thread put "args" into its auto_ptr and >> delete "args" before the code that launches that thread is done with >> "args"? I can't see all the code here, so I am just curious. > > I took another look over the code. You are right, there is a race if > the monitor thread encounters an error when launching the inferior. > > This corrected patch uses the previous approach of having the parent > thread maintain ownership. Holding onto the launch args in an auto_ptr > should be safe here since we synchronize with the child thread via a > semaphore, and the child does not reference the launch args beyond that > point. > > Thanks for the review! > > > > > Miscellaneous cleanups in ProcessMonitor. > > Propagate the environment if one is not provided. Also, do not allocate the > monitor threads launch arguments on the stack. > > diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp > index 1522263..f21cb00 100644 > --- a/source/Plugins/Process/Linux/ProcessMonitor.cpp > +++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp > @@ -463,8 +463,10 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, > m_client_fd(-1), > m_server_fd(-1) > { > - LaunchArgs args(this, module, argv, envp, > - stdin_path, stdout_path, stderr_path); > + std::auto_ptr args; > + > + args.reset(new LaunchArgs(this, module, argv, envp, > + stdin_path, stdout_path, stderr_path)); > > // Server/client descriptors. > if (!EnableIPC()) > @@ -473,13 +475,13 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process, > error.SetErrorString("Monitor failed to initialize."); > } > > - StartOperationThread(&args, error); > + StartOperationThread(args.get(), error); > if (!error.Success()) > return; > > WAIT_AGAIN: > // Wait for the operation thread to initialize. > - if (sem_wait(&args.m_semaphore)) > + if (sem_wait(&args->m_semaphore)) > { > if (errno == EINTR) > goto WAIT_AGAIN; > @@ -491,16 +493,17 @@ WAIT_AGAIN: > } > > // Check that the launch was a success. > - if (!args.m_error.Success()) > + if (!args->m_error.Success()) > { > StopOperationThread(); > - error = args.m_error; > + error = args->m_error; > return; > } > > // Finally, start monitoring the child process for change in state. > - if (!(m_monitor_thread = Host::StartMonitoringChildProcess( > - ProcessMonitor::MonitorCallback, this, GetPID(), true))) > + m_monitor_thread = Host::StartMonitoringChildProcess( > + ProcessMonitor::MonitorCallback, this, GetPID(), true); > + if (m_monitor_thread == LLDB_INVALID_HOST_THREAD) > { > error.SetErrorToGenericError(); > error.SetErrorString("Process launch failed."); > @@ -574,6 +577,10 @@ ProcessMonitor::Launch(LaunchArgs *args) > > lldb::ThreadSP inferior; > > + // Propagate the environment if one is not supplied. > + if (envp == NULL || envp[0] == NULL) > + envp = const_cast(environ); > + > // Pseudo terminal setup. > if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len)) > { > From gclayton at apple.com Fri Jan 14 17:49:40 2011 From: gclayton at apple.com (Greg Clayton) Date: Fri, 14 Jan 2011 15:49:40 -0800 Subject: [Lldb-commits] [PATCH 8/8] Add empty implementation of pure virtual RegisterContext::InvalidateAllRegisters. In-Reply-To: References: <1295039542-9640-1-git-send-email-wilsons@start.ca> <1295039542-9640-9-git-send-email-wilsons@start.ca> Message-ID: Good to go. On Jan 14, 2011, at 3:01 PM, Stephen Wilson wrote: > Greg Clayton writes: > >> Here is where you will want to track if you have read your regiters >> from what ever you read registers from on Linux. > > OK. > >> You might to just want to copy the >> "lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.cpp" >> and >> "lldb/source/Plugins/Process/MacOSX-User/source/RegisterContextMach_x86_64.h" >> files and modify the structures to match linux. This has all of the >> invalidating code done on a per/register group basis (gpr, fpu and exc >> registers). > > Absolutely. Is it OK for this patch to go in as is? Since the method > is pure virtual this empty implementation simply allows the tree to > build. I will certainly look into implementing the method properly in > the near future. > > >> >> On Jan 14, 2011, at 1:12 PM, Stephen Wilson wrote: >> >>> --- >>> .../Process/Linux/RegisterContextLinux_x86_64.cpp | 5 +++++ >>> .../Process/Linux/RegisterContextLinux_x86_64.h | 3 +++ >>> 2 files changed, 8 insertions(+), 0 deletions(-) >>> >>> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp >>> index da6ea8d..27cd6c6 100644 >>> --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp >>> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp >>> @@ -423,6 +423,11 @@ RegisterContextLinux_x86_64::Invalidate() >>> { >>> } >>> >>> +void >>> +RegisterContextLinux_x86_64::InvalidateAllRegisters() >>> +{ >>> +} >>> + >>> size_t >>> RegisterContextLinux_x86_64::GetRegisterCount() >>> { >>> diff --git a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h >>> index dc421ec..876d685 100644 >>> --- a/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h >>> +++ b/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h >>> @@ -26,6 +26,9 @@ public: >>> void >>> Invalidate(); >>> >>> + void >>> + InvalidateAllRegisters(); >>> + >>> size_t >>> GetRegisterCount(); >>> >>> -- >>> 1.7.3.5 >>> >>> _______________________________________________ >>> lldb-commits mailing list >>> lldb-commits at cs.uiuc.edu >>> http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits >> > > > > -- > steve From wilsons at start.ca Fri Jan 14 18:07:36 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:07:36 -0000 Subject: [Lldb-commits] [lldb] r123495 - in /lldb/trunk/source/Plugins/Process/Linux: LinuxThread.cpp LinuxThread.h Message-ID: <20110115000736.CBC042A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 18:07:36 2011 New Revision: 123495 URL: http://llvm.org/viewvc/llvm-project?rev=123495&view=rev Log: Have LinuxThread cache it's current StopInfo object. Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp?rev=123495&r1=123494&r2=123495&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp Fri Jan 14 18:07:36 2011 @@ -26,6 +26,7 @@ LinuxThread::LinuxThread(Process &process, lldb::tid_t tid) : Thread(process, tid), m_frame_ap(0), + m_stop_info_id(0), m_note(eNone) { } @@ -40,6 +41,7 @@ void LinuxThread::RefreshStateAfterStop() { + RefreshPrivateStopReason(); } const char * @@ -101,24 +103,11 @@ lldb::StopInfoSP LinuxThread::GetPrivateStopReason() { - lldb::StopInfoSP stop_info; + const uint32_t process_stop_id = GetProcess().GetStopID(); - switch (m_note) - { - default: - break; - - case eBreak: - stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( - *this, m_breakpoint->GetID()); - break; - - case eTrace: - stop_info = StopInfo::CreateStopReasonToTrace(*this); - break; - } - - return stop_info; + if (m_stop_info_id != process_stop_id || !m_stop_info || !m_stop_info->IsValid()) + RefreshPrivateStopReason(); + return m_stop_info; } Unwind * @@ -196,3 +185,30 @@ { m_note = eExit; } + +void +LinuxThread::RefreshPrivateStopReason() +{ + m_stop_info_id = GetProcess().GetStopID(); + + switch (m_note) { + + default: + case eNone: + m_stop_info.reset(); + break; + + case eBreak: + m_stop_info = StopInfo::CreateStopReasonWithBreakpointSiteID( + *this, m_breakpoint->GetID()); + break; + + case eTrace: + m_stop_info = StopInfo::CreateStopReasonToTrace(*this); + break; + + case eExit: + m_stop_info = StopInfo::CreateStopReasonWithSignal(*this, SIGCHLD); + break; + } +} Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h?rev=123495&r1=123494&r2=123495&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h (original) +++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h Fri Jan 14 18:07:36 2011 @@ -72,6 +72,11 @@ std::auto_ptr m_frame_ap; lldb::BreakpointSiteSP m_breakpoint; + lldb::StopInfoSP m_stop_info; + + // Cached process stop id. Used to ensure we do not recalculate stop + // information/state needlessly. + uint32_t m_stop_info_id; enum Notification { eNone, @@ -87,6 +92,9 @@ lldb::StopInfoSP GetPrivateStopReason(); + void + RefreshPrivateStopReason(); + lldb_private::Unwind * GetUnwinder(); }; From wilsons at start.ca Fri Jan 14 18:08:44 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:08:44 -0000 Subject: [Lldb-commits] [lldb] r123496 - in /lldb/trunk/source/Plugins/ObjectFile/ELF: ObjectFileELF.cpp ObjectFileELF.h Message-ID: <20110115000844.A032C2A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 18:08:44 2011 New Revision: 123496 URL: http://llvm.org/viewvc/llvm-project?rev=123496&view=rev Log: Implement GetEntryPoint, GetImageInfoAddress and GetArchitecture for ObjectFileELF. Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp?rev=123496&r1=123495&r2=123496&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Fri Jan 14 18:08:44 2011 @@ -12,6 +12,7 @@ #include #include +#include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Error.h" #include "lldb/Core/FileSpecList.h" @@ -70,9 +71,10 @@ unsigned address_size = ELFHeader::AddressSizeInBytes(magic); if (address_size == 4 || address_size == 8) { - std::auto_ptr objfile_ap( + std::auto_ptr objfile_ap( new ObjectFileELF(module, data_sp, file, offset, length)); - if (objfile_ap->ParseHeader()) + ArchSpec spec = objfile_ap->GetArchitecture(); + if (spec.IsValid() && objfile_ap->SetModulesArchitecture(spec)) return objfile_ap.release(); } } @@ -80,6 +82,15 @@ return NULL; } +ArchSpec +ObjectFileELF::GetArchitecture() +{ + if (!ParseHeader()) + return ArchSpec(); + + return ArchSpec(eArchTypeELF, m_header.e_machine, m_header.e_flags); +} + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -151,6 +162,15 @@ return m_header.e_type == ET_EXEC; } +Address +ObjectFileELF::GetEntryPoint() const +{ + if (m_header.e_entry) + return Address(NULL, m_header.e_entry); + else + return Address(); +} + ByteOrder ObjectFileELF::GetByteOrder() const { @@ -208,6 +228,60 @@ return num_specs; } +Address +ObjectFileELF::GetImageInfoAddress() +{ + if (!ParseSectionHeaders()) + return Address(); + + user_id_t dynsym_id = 0; + for (SectionHeaderCollIter sh_pos = m_section_headers.begin(); + sh_pos != m_section_headers.end(); ++sh_pos) + { + if (sh_pos->sh_type == SHT_DYNAMIC) + { + dynsym_id = SectionIndex(sh_pos); + break; + } + } + + if (!dynsym_id) + return Address(); + + SectionList *section_list = GetSectionList(); + if (!section_list) + return Address(); + + // Resolve the dynamic table entries. + Section *dynsym = section_list->FindSectionByID(dynsym_id).get(); + if (!dynsym) + return Address(); + + DataExtractor dynsym_data; + if (dynsym->ReadSectionDataFromObjectFile(this, dynsym_data)) + { + ELFDynamic symbol; + const unsigned section_size = dynsym_data.GetByteSize(); + unsigned offset = 0; + unsigned cursor = 0; + + // Look for a DT_DEBUG entry. + while (cursor < section_size) + { + offset = cursor; + if (!symbol.Parse(dynsym_data, &cursor)) + break; + + if (symbol.d_tag != DT_DEBUG) + continue; + + return Address(dynsym, offset + sizeof(symbol.d_tag)); + } + } + + return Address(); +} + //---------------------------------------------------------------------- // ParseDependentModules //---------------------------------------------------------------------- Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h?rev=123496&r1=123495&r2=123496&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.h Fri Jan 14 18:08:44 2011 @@ -89,6 +89,9 @@ virtual bool IsExecutable () const; + virtual lldb_private::Address + GetEntryPoint() const; + virtual size_t GetAddressByteSize() const; @@ -110,6 +113,12 @@ virtual uint32_t GetDependentModules(lldb_private::FileSpecList& files); + virtual lldb_private::Address + GetImageInfoAddress(); + + lldb_private::ArchSpec + GetArchitecture(); + private: ObjectFileELF(lldb_private::Module* module, lldb::DataBufferSP& dataSP, From wilsons at start.ca Fri Jan 14 18:09:50 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:09:50 -0000 Subject: [Lldb-commits] [lldb] r123498 - /lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Message-ID: <20110115000950.F14A82A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 18:09:50 2011 New Revision: 123498 URL: http://llvm.org/viewvc/llvm-project?rev=123498&view=rev Log: Test if an ELF object is executable by checking if an entry point is defined. The previous check on header type ET_EXEC is not general enough. Position independent executables have type ET_DYN. Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Modified: lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp?rev=123498&r1=123497&r2=123498&view=diff ============================================================================== --- lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (original) +++ lldb/trunk/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp Fri Jan 14 18:09:50 2011 @@ -159,7 +159,7 @@ bool ObjectFileELF::IsExecutable() const { - return m_header.e_type == ET_EXEC; + return m_header.e_entry != 0; } Address From wilsons at start.ca Fri Jan 14 18:10:37 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:10:37 -0000 Subject: [Lldb-commits] [lldb] r123499 - in /lldb/trunk/source/Plugins/Process/Linux: ProcessLinux.cpp ProcessLinux.h Message-ID: <20110115001037.BC9C32A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 18:10:37 2011 New Revision: 123499 URL: http://llvm.org/viewvc/llvm-project?rev=123499&view=rev Log: Implement ProcessLinux::GetImageInfoAddress(). Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp?rev=123499&r1=123498&r2=123499&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp Fri Jan 14 18:10:37 2011 @@ -149,6 +149,19 @@ return Error(); } +addr_t +ProcessLinux::GetImageInfoAddress() +{ + Target *target = &GetTarget(); + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(); + + if (addr.IsValid()) + return addr.GetLoadAddress(target); + else + return LLDB_INVALID_ADDRESS; +} + Error ProcessLinux::DoHalt(bool &caused_stop) { Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h?rev=123499&r1=123498&r2=123499&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h (original) +++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h Fri Jan 14 18:10:37 2011 @@ -128,6 +128,9 @@ virtual lldb::ByteOrder GetByteOrder() const; + virtual lldb::addr_t + GetImageInfoAddress(); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ From wilsons at start.ca Fri Jan 14 18:11:28 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:11:28 -0000 Subject: [Lldb-commits] [lldb] r123500 - /lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Message-ID: <20110115001128.E5BBA2A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 18:11:28 2011 New Revision: 123500 URL: http://llvm.org/viewvc/llvm-project?rev=123500&view=rev Log: Use the correct type for thread handle. Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h?rev=123500&r1=123499&r2=123500&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h (original) +++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Fri Jan 14 18:11:28 2011 @@ -140,7 +140,7 @@ lldb::pid_t m_pid; int m_terminal_fd; - uint32_t m_monitor_thread; + lldb::thread_t m_monitor_thread; lldb_private::Mutex m_server_mutex; int m_client_fd; From wilsons at start.ca Fri Jan 14 18:12:41 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:12:41 -0000 Subject: [Lldb-commits] [lldb] r123502 - /lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Message-ID: <20110115001241.C13C42A6C12D@llvm.org> Author: wilsons Date: Fri Jan 14 18:12:41 2011 New Revision: 123502 URL: http://llvm.org/viewvc/llvm-project?rev=123502&view=rev Log: Miscellaneous cleanups in ProcessMonitor. Propagate the environment if one is not provided. Also, do not allocate the monitor threads launch arguments on the stack. Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=123502&r1=123501&r2=123502&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Fri Jan 14 18:12:41 2011 @@ -463,8 +463,10 @@ m_client_fd(-1), m_server_fd(-1) { - LaunchArgs args(this, module, argv, envp, - stdin_path, stdout_path, stderr_path); + std::auto_ptr args; + + args.reset(new LaunchArgs(this, module, argv, envp, + stdin_path, stdout_path, stderr_path)); // Server/client descriptors. if (!EnableIPC()) @@ -473,13 +475,13 @@ error.SetErrorString("Monitor failed to initialize."); } - StartOperationThread(&args, error); + StartOperationThread(args.get(), error); if (!error.Success()) return; WAIT_AGAIN: // Wait for the operation thread to initialize. - if (sem_wait(&args.m_semaphore)) + if (sem_wait(&args->m_semaphore)) { if (errno == EINTR) goto WAIT_AGAIN; @@ -491,16 +493,17 @@ } // Check that the launch was a success. - if (!args.m_error.Success()) + if (!args->m_error.Success()) { StopOperationThread(); - error = args.m_error; + error = args->m_error; return; } // Finally, start monitoring the child process for change in state. - if (!(m_monitor_thread = Host::StartMonitoringChildProcess( - ProcessMonitor::MonitorCallback, this, GetPID(), true))) + m_monitor_thread = Host::StartMonitoringChildProcess( + ProcessMonitor::MonitorCallback, this, GetPID(), true); + if (m_monitor_thread == LLDB_INVALID_HOST_THREAD) { error.SetErrorToGenericError(); error.SetErrorString("Process launch failed."); @@ -574,6 +577,10 @@ lldb::ThreadSP inferior; + // Propagate the environment if one is not supplied. + if (envp == NULL || envp[0] == NULL) + envp = const_cast(environ); + // Pseudo terminal setup. if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len)) { From wilsons at start.ca Fri Jan 14 18:13:27 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:13:27 -0000 Subject: [Lldb-commits] [lldb] r123503 - /lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp Message-ID: <20110115001327.DCD592A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 18:13:27 2011 New Revision: 123503 URL: http://llvm.org/viewvc/llvm-project?rev=123503&view=rev Log: Set the ID of a ProcessLinux instance to the PID of the inferior on launch. Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp?rev=123503&r1=123502&r2=123503&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp Fri Jan 14 18:13:27 2011 @@ -124,6 +124,7 @@ if (!error.Success()) return error; + SetID(m_monitor->GetPID()); return error; } From wilsons at start.ca Fri Jan 14 18:15:12 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 00:15:12 -0000 Subject: [Lldb-commits] [lldb] r123504 - in /lldb/trunk/source/Plugins/Process/Linux: RegisterContextLinux_x86_64.cpp RegisterContextLinux_x86_64.h Message-ID: <20110115001513.02CF92A6C12C@llvm.org> Author: wilsons Date: Fri Jan 14 18:15:12 2011 New Revision: 123504 URL: http://llvm.org/viewvc/llvm-project?rev=123504&view=rev Log: Add empty implementation of pure virtual RegisterContext::InvalidateAllRegisters. This patch simply allows the tree to build. A proper implementation still needs to be provided. Modified: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h Modified: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp?rev=123504&r1=123503&r2=123504&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.cpp Fri Jan 14 18:15:12 2011 @@ -423,6 +423,11 @@ { } +void +RegisterContextLinux_x86_64::InvalidateAllRegisters() +{ +} + size_t RegisterContextLinux_x86_64::GetRegisterCount() { Modified: lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h?rev=123504&r1=123503&r2=123504&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h (original) +++ lldb/trunk/source/Plugins/Process/Linux/RegisterContextLinux_x86_64.h Fri Jan 14 18:15:12 2011 @@ -26,6 +26,9 @@ void Invalidate(); + void + InvalidateAllRegisters(); + size_t GetRegisterCount(); From gclayton at apple.com Fri Jan 14 19:32:14 2011 From: gclayton at apple.com (Greg Clayton) Date: Sat, 15 Jan 2011 01:32:14 -0000 Subject: [Lldb-commits] [lldb] r123507 - /lldb/trunk/source/Expression/ClangExpressionParser.cpp Message-ID: <20110115013214.446242A6C12C@llvm.org> Author: gclayton Date: Fri Jan 14 19:32:14 2011 New Revision: 123507 URL: http://llvm.org/viewvc/llvm-project?rev=123507&view=rev Log: Enabled ObjC 2 abilities for expressions. We will enable the fragile ivar stuff soon when we get a fix for looking up the "OBJC_IVAR_$_Class.ivar" style symbols into IRForTarget::ResolveExternals() next week. Modified: lldb/trunk/source/Expression/ClangExpressionParser.cpp Modified: lldb/trunk/source/Expression/ClangExpressionParser.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionParser.cpp?rev=123507&r1=123506&r2=123507&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangExpressionParser.cpp (original) +++ lldb/trunk/source/Expression/ClangExpressionParser.cpp Fri Jan 14 19:32:14 2011 @@ -207,7 +207,15 @@ // Parse expressions as Objective C++ regardless of context. // Our hook into Clang's lookup mechanism only works in C++. m_compiler->getLangOpts().CPlusPlus = true; + + // Setup objective C m_compiler->getLangOpts().ObjC1 = true; + m_compiler->getLangOpts().ObjC2 = true; + // We need to enable the fragile ABI for things target triples that + // support it. +// m_compiler->getLangOpts().ObjCNonFragileABI = true; // NOT i386 +// m_compiler->getLangOpts().ObjCNonFragileABI2 = true; // NOT i386 + m_compiler->getLangOpts().ThreadsafeStatics = false; m_compiler->getLangOpts().AccessControl = false; // Debuggers get universal access m_compiler->getLangOpts().DollarIdents = true; // $ indicates a persistent variable name From gclayton at apple.com Fri Jan 14 20:52:14 2011 From: gclayton at apple.com (Greg Clayton) Date: Sat, 15 Jan 2011 02:52:14 -0000 Subject: [Lldb-commits] [lldb] r123509 - in /lldb/trunk: include/lldb/lldb-enumerations.h source/Core/DataExtractor.cpp source/Symbol/ClangASTContext.cpp source/Symbol/ClangASTType.cpp Message-ID: <20110115025214.84D542A6C12C@llvm.org> Author: gclayton Date: Fri Jan 14 20:52:14 2011 New Revision: 123509 URL: http://llvm.org/viewvc/llvm-project?rev=123509&view=rev Log: Added complete complex support for displaying and parsing complex types. Modified: lldb/trunk/include/lldb/lldb-enumerations.h lldb/trunk/source/Core/DataExtractor.cpp lldb/trunk/source/Symbol/ClangASTContext.cpp lldb/trunk/source/Symbol/ClangASTType.cpp Modified: lldb/trunk/include/lldb/lldb-enumerations.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-enumerations.h?rev=123509&r1=123508&r2=123509&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-enumerations.h (original) +++ lldb/trunk/include/lldb/lldb-enumerations.h Fri Jan 14 20:52:14 2011 @@ -148,7 +148,8 @@ eFormatBytesWithASCII, eFormatChar, eFormatCharPrintable, // Only printable characters, space if not printable - eFormatComplex, + eFormatComplex, // Floating point complex type + eFormatComplexFloat = eFormatComplex, eFormatCString, // NULL terminated C strings eFormatDecimal, eFormatEnum, @@ -171,7 +172,8 @@ eFormatVectorOfUInt64, eFormatVectorOfFloat32, eFormatVectorOfFloat64, - eFormatVectorOfUInt128 + eFormatVectorOfUInt128, + eFormatComplexInteger, // Integer complex type } Format; Modified: lldb/trunk/source/Core/DataExtractor.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/DataExtractor.cpp?rev=123509&r1=123508&r2=123509&view=diff ============================================================================== --- lldb/trunk/source/Core/DataExtractor.cpp (original) +++ lldb/trunk/source/Core/DataExtractor.cpp Fri Jan 14 20:52:14 2011 @@ -1390,6 +1390,19 @@ s->Address(GetMaxU64Bitfield(&offset, item_byte_size, item_bit_size, item_bit_offset), sizeof (addr_t)); break; + + case eFormatComplexInteger: + { + uint32_t complex_int_byte_size = item_byte_size / 2; + + if (complex_int_byte_size <= 8) + { + s->Printf("%llu", GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0)); + s->Printf(" + %llui", GetMaxU64Bitfield(&offset, complex_int_byte_size, 0, 0)); + } + } + break; + case eFormatComplex: if (sizeof(float) * 2 == item_byte_size) { @@ -1414,9 +1427,12 @@ s->Printf ("%Lg + %Lgi", ld64_1, ld64_2); break; } - - // Fall through to hex for any other sizes - item_format = eFormatHex; + else + { + s->Printf ("unsupported complex float byte size %u", item_byte_size); + return start_offset; + } + break; default: case eFormatDefault: Modified: lldb/trunk/source/Symbol/ClangASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTContext.cpp?rev=123509&r1=123508&r2=123509&view=diff ============================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp (original) +++ lldb/trunk/source/Symbol/ClangASTContext.cpp Fri Jan 14 20:52:14 2011 @@ -548,13 +548,27 @@ return ast_context->UnsignedIntTy.getAsOpaquePtr(); break; + case DW_ATE_lo_user: + // This has been seen to mean DW_AT_complex_integer + if (strcmp(type_name, "complex") == 0) + { + clang_type_t complex_int_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("int", DW_ATE_signed, bit_size/2); + return ast_context->getComplexType (QualType::getFromOpaquePtr(complex_int_clang_type)).getAsOpaquePtr(); + } + break; + case DW_ATE_complex_float: if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatComplexTy)) return ast_context->FloatComplexTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleComplexTy)) + else if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleComplexTy)) return ast_context->DoubleComplexTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleComplexTy)) + else if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleComplexTy)) return ast_context->LongDoubleComplexTy.getAsOpaquePtr(); + else + { + clang_type_t complex_float_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("float", DW_ATE_float, bit_size/2); + return ast_context->getComplexType (QualType::getFromOpaquePtr(complex_float_clang_type)).getAsOpaquePtr(); + } break; case DW_ATE_float: @@ -1773,7 +1787,7 @@ *pointee_or_element_clang_type = qual_type->getPointeeType().getAsOpaquePtr(); return eTypeIsPointer | eTypeHasChildren | eTypeIsBlock; - case clang::Type::Complex: return eTypeHasChildren | eTypeIsBuiltIn | eTypeHasValue; + case clang::Type::Complex: return eTypeIsBuiltIn | eTypeHasValue; case clang::Type::ConstantArray: case clang::Type::DependentSizedArray: @@ -1902,8 +1916,7 @@ } break; - case clang::Type::Complex: - return 2; + case clang::Type::Complex: return 0; case clang::Type::Record: if (ClangASTType::IsDefined (clang_qual_type)) @@ -2090,7 +2103,7 @@ } break; - case clang::Type::Complex: return 2; + case clang::Type::Complex: return 1; case clang::Type::Pointer: return 1; case clang::Type::BlockPointer: return 0; // If block pointers don't have debug info, then no children for them case clang::Type::LValueReference: return 1; Modified: lldb/trunk/source/Symbol/ClangASTType.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTType.cpp?rev=123509&r1=123508&r2=123509&view=diff ============================================================================== --- lldb/trunk/source/Symbol/ClangASTType.cpp (original) +++ lldb/trunk/source/Symbol/ClangASTType.cpp Fri Jan 14 20:52:14 2011 @@ -177,10 +177,22 @@ case clang::Type::LValueReference: case clang::Type::RValueReference: case clang::Type::MemberPointer: return lldb::eEncodingUint; - // Complex numbers are made up of floats case clang::Type::Complex: - count = 2; - return lldb::eEncodingIEEE754; + { + lldb::Encoding encoding = lldb::eEncodingIEEE754; + if (qual_type->isComplexType()) + encoding = lldb::eEncodingIEEE754; + else + { + const clang::ComplexType *complex_type = qual_type->getAsComplexIntegerType(); + if (complex_type) + encoding = GetEncoding (complex_type->getElementType().getAsOpaquePtr(), count); + else + encoding = lldb::eEncodingSint; + } + count = 2; + return encoding; + } case clang::Type::ObjCInterface: break; case clang::Type::Record: break; @@ -270,7 +282,13 @@ case clang::Type::LValueReference: case clang::Type::RValueReference: return lldb::eFormatHex; case clang::Type::MemberPointer: break; - case clang::Type::Complex: return lldb::eFormatComplex; + case clang::Type::Complex: + { + if (qual_type->isComplexType()) + return lldb::eFormatComplex; + else + return lldb::eFormatComplexInteger; + } case clang::Type::ObjCInterface: break; case clang::Type::Record: break; case clang::Type::Enum: return lldb::eFormatEnum; From gclayton at apple.com Fri Jan 14 21:06:23 2011 From: gclayton at apple.com (Greg Clayton) Date: Sat, 15 Jan 2011 03:06:23 -0000 Subject: [Lldb-commits] [lldb] r123513 - in /lldb/trunk: lldb.xcodeproj/project.pbxproj resources/LLDB-Info.plist tools/debugserver/debugserver.xcodeproj/project.pbxproj Message-ID: <20110115030623.347452A6C12C@llvm.org> Author: gclayton Date: Fri Jan 14 21:06:23 2011 New Revision: 123513 URL: http://llvm.org/viewvc/llvm-project?rev=123513&view=rev Log: lldb-41 and debugserver-126 are set in the Xcode projects. Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj lldb/trunk/resources/LLDB-Info.plist lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=123513&r1=123512&r2=123513&view=diff ============================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original) +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Fri Jan 14 21:06:23 2011 @@ -2926,9 +2926,9 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 40; + DYLIB_CURRENT_VERSION = 41; EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -2978,11 +2978,11 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 40; + DYLIB_CURRENT_VERSION = 41; EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3052,7 +3052,7 @@ isa = XCBuildConfiguration; buildSettings = { COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3087,11 +3087,11 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 40; + DYLIB_CURRENT_VERSION = 41; EXPORTED_SYMBOLS_FILE = "resources/lldb-framework-exports"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -3140,7 +3140,7 @@ buildSettings = { CODE_SIGN_IDENTITY = lldb_codesign; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", @@ -3178,7 +3178,7 @@ ); CODE_SIGN_IDENTITY = lldb_codesign; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 40; + CURRENT_PROJECT_VERSION = 41; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", Modified: lldb/trunk/resources/LLDB-Info.plist URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/resources/LLDB-Info.plist?rev=123513&r1=123512&r2=123513&view=diff ============================================================================== --- lldb/trunk/resources/LLDB-Info.plist (original) +++ lldb/trunk/resources/LLDB-Info.plist Fri Jan 14 21:06:23 2011 @@ -17,7 +17,7 @@ CFBundleSignature ???? CFBundleVersion - 40 + 41 CFBundleName ${EXECUTABLE_NAME} Modified: lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj?rev=123513&r1=123512&r2=123513&view=diff ============================================================================== --- lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj (original) +++ lldb/trunk/tools/debugserver/debugserver.xcodeproj/project.pbxproj Fri Jan 14 21:06:23 2011 @@ -460,7 +460,7 @@ i386, ); COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; STRIP_INSTALLED_PRODUCT = NO; @@ -478,7 +478,7 @@ x86_64, i386, ); - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEAD_CODE_STRIPPING = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; @@ -498,7 +498,7 @@ x86_64, i386, ); - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEAD_CODE_STRIPPING = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; @@ -515,7 +515,7 @@ buildSettings = { "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist"; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( @@ -556,7 +556,7 @@ "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = lldb_codesign; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( "$(SDKROOT)/System/Library/PrivateFrameworks", @@ -597,7 +597,7 @@ "CODE_SIGN_ENTITLEMENTS[sdk=iphoneos*]" = "source/debugserver-entitlements.plist"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = lldb_codesign; COPY_PHASE_STRIP = YES; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 126; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = $SDKROOT/System/Library/PrivateFrameworks; "FRAMEWORK_SEARCH_PATHS[sdk=iphoneos*][arch=*]" = ( From wilsons at start.ca Sat Jan 15 13:31:28 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 14:31:28 -0500 Subject: [Lldb-commits] [PATCH] linux: Make a mandatory call to DestroyThread() in ~LinuxThread() Message-ID: diff --git a/source/Plugins/Process/Linux/LinuxThread.cpp b/source/Plugins/Process/Linux/LinuxThread.cpp index caed8e1..de1ca51 100644 --- a/source/Plugins/Process/Linux/LinuxThread.cpp +++ b/source/Plugins/Process/Linux/LinuxThread.cpp @@ -31,6 +31,11 @@ LinuxThread::LinuxThread(Process &process, lldb::tid_t tid) { } +LinuxThread::~LinuxThread() +{ + DestroyThread(); +} + ProcessMonitor & LinuxThread::GetMonitor() { diff --git a/source/Plugins/Process/Linux/LinuxThread.h b/source/Plugins/Process/Linux/LinuxThread.h index 7e30f0a..c7f29ca 100644 --- a/source/Plugins/Process/Linux/LinuxThread.h +++ b/source/Plugins/Process/Linux/LinuxThread.h @@ -29,6 +29,8 @@ class LinuxThread public: LinuxThread(lldb_private::Process &process, lldb::tid_t tid); + virtual ~LinuxThread(); + void RefreshStateAfterStop(); From wilsons at start.ca Sat Jan 15 13:40:42 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sat, 15 Jan 2011 14:40:42 -0500 Subject: [Lldb-commits] [PATCH][RFC] Linux DynamicLoader plugin. Message-ID: This patch is enough to have shared objects recognized by LLDB on Linux. We can handle position independent executables. We can handle dynamically loaded modules brought in via dlopen. The DYLDRendezvous class provides an interface to a structure present in the address space of ELF-based processes. This structure provides the location of a function which is called by the runtime linker each time a shared object is loaded and unloaded (thus a breakpoint at that address will let LLDB intercept such events), a list of entries describing the currently loaded shared objects, plus a few other things. On Linux, processes are brought up with an auxiliary vector on the stack. One element in this vector contains the (possibly dynamic) entry address of the process. One does not need to walk the stack to find this information as it is available under /proc//auxv. The new AuxVector class provides a convenient read-only view of this auxiliary information. We use the dynamic entry address and the address as specified in the object file to compute the actual load address of the inferior image. This strategy works for both normal executables and PIE's. As most of this code is new the following diff might not be the most readable. One can also browse the files online here: https://github.com/eightcien/lldb/tree/lldb-linux/source/Plugins/DynamicLoader/Linux-DYLD --- lib/Makefile | 3 +- .../Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp | 191 ++++++++++ .../Plugins/DynamicLoader/Linux-DYLD/AuxVector.h | 97 +++++ .../DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp | 315 +++++++++++++++++ .../DynamicLoader/Linux-DYLD/DYLDRendezvous.h | 227 ++++++++++++ .../Linux-DYLD/DynamicLoaderLinuxDYLD.cpp | 371 ++++++++++++++++++++ .../Linux-DYLD/DynamicLoaderLinuxDYLD.h | 165 +++++++++ source/Plugins/DynamicLoader/Linux-DYLD/Makefile | 14 + source/Plugins/Makefile | 2 +- source/Plugins/Process/Linux/ProcessLinux.cpp | 27 ++ source/Plugins/Process/Linux/ProcessLinux.h | 12 + source/lldb.cpp | 3 + 12 files changed, 1425 insertions(+), 2 deletions(-) create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/Makefile diff --git a/lib/Makefile b/lib/Makefile index 881b23c..abd9c1d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -67,7 +67,8 @@ ifeq ($(HOST_OS),Darwin) endif ifeq ($(HOST_OS),Linux) - USEDLIBS += lldbPluginProcessLinux.a + USEDLIBS += lldbPluginProcessLinux.a \ + lldbPluginDynamicLoaderLinux.a endif include $(LEVEL)/Makefile.common diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp new file mode 100644 index 0000000..6954e4c --- /dev/null +++ b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp @@ -0,0 +1,191 @@ +//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include +#include +#include + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" + +#include "AuxVector.h" + +using namespace lldb; +using namespace lldb_private; + +static bool +GetMaxU64(DataExtractor &data, + uint32_t *offset, uint64_t *value, unsigned int byte_size) +{ + uint32_t saved_offset = *offset; + *value = data.GetMaxU64(offset, byte_size); + return *offset != saved_offset; +} + +static bool +ParseAuxvEntry(DataExtractor &data, AuxVector::Entry &entry, + uint32_t *offset, unsigned int byte_size) +{ + if (!GetMaxU64(data, offset, &entry.type, byte_size)) + return false; + + if (!GetMaxU64(data, offset, &entry.value, byte_size)) + return false; + + return true; +} + +DataBufferSP +AuxVector::GetAuxvData() +{ + static const size_t path_size = 128; + static char path[path_size]; + DataBufferSP buf_sp; + int fd; + + // Ideally, we would simply create a FileSpec and call ReadFileContents. + // However, files in procfs have zero size (since they are, in general, + // dynamically generated by the kernel) which is incompatible with the + // current ReadFileContents implementation. Therefore we simply stream the + // data into a DataBuffer ourselves. + if (snprintf(path, path_size, "/proc/%d/auxv", m_process->GetID()) < 0) + return buf_sp; + + if ((fd = open(path, O_RDONLY, 0)) < 0) + return buf_sp; + + size_t bytes_read = 0; + std::auto_ptr buf_ap(new DataBufferHeap(1024, 0)); + for (;;) + { + size_t avail = buf_ap->GetByteSize() - bytes_read; + ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail); + + if (status < 0) + break; + + bytes_read += status; + + if (status == 0) + { + buf_ap->SetByteSize(bytes_read); + buf_sp.reset(buf_ap.release()); + break; + } + + if (avail - status == 0) + buf_ap->SetByteSize(2 * buf_ap->GetByteSize()); + } + + return buf_sp; +} + +void +AuxVector::ParseAuxv(DataExtractor &data) +{ + const unsigned int byte_size = m_process->GetAddressByteSize(); + uint32_t offset = 0; + + for (;;) + { + Entry entry; + + if (!ParseAuxvEntry(data, entry, &offset, byte_size)) + break; + + if (entry.type == AT_NULL) + break; + + if (entry.type == AT_IGNORE) + continue; + + m_auxv.push_back(entry); + } +} + +AuxVector::AuxVector(Process *process) + : m_process(process) +{ + DataExtractor data; + LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + data.SetData(GetAuxvData()); + data.SetByteOrder(m_process->GetByteOrder()); + data.SetAddressByteSize(m_process->GetAddressByteSize()); + + ParseAuxv(data); + + if (log) + DumpToLog(log); +} + +AuxVector::iterator +AuxVector::FindEntry(EntryType type) const +{ + for (iterator I = begin(); I != end(); ++I) + { + if (I->type == static_cast(type)) + return I; + } + + return end(); +} + +void +AuxVector::DumpToLog(LogSP log) const +{ + if (!log) + return; + + log->PutCString("AuxVector: "); + for (iterator I = begin(); I != end(); ++I) + { + log->Printf(" %s [%d]: %lx", GetEntryName(*I), I->type, I->value); + } +} + +const char * +AuxVector::GetEntryName(EntryType type) +{ + const char *name; + +#define ENTRY_NAME(_type) _type: name = #_type + switch (type) + { + default: + name = "unkown"; + break; + + case ENTRY_NAME(AT_NULL); break; + case ENTRY_NAME(AT_IGNORE); break; + case ENTRY_NAME(AT_EXECFD); break; + case ENTRY_NAME(AT_PHDR); break; + case ENTRY_NAME(AT_PHENT); break; + case ENTRY_NAME(AT_PHNUM); break; + case ENTRY_NAME(AT_PAGESZ); break; + case ENTRY_NAME(AT_BASE); break; + case ENTRY_NAME(AT_FLAGS); break; + case ENTRY_NAME(AT_ENTRY); break; + case ENTRY_NAME(AT_NOTELF); break; + case ENTRY_NAME(AT_UID); break; + case ENTRY_NAME(AT_EUID); break; + case ENTRY_NAME(AT_GID); break; + case ENTRY_NAME(AT_EGID); break; + case ENTRY_NAME(AT_CLKTCK); break; + } +#undef ENTRY_NAME + + return name; +} + diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h new file mode 100644 index 0000000..7a5b370 --- /dev/null +++ b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h @@ -0,0 +1,97 @@ +//===-- AuxVector.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AuxVector_H_ +#define liblldb_AuxVector_H_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +#include "lldb/lldb-forward-rtti.h" + +namespace lldb_private { +class DataExtractor; +} + +/// @class AuxVector +/// @brief Represents a processes auxiliary vector. +/// +/// When a process is loaded on Linux a vector of values is placed onto the +/// stack communicating operating system specific information. On construction +/// this class locates and parses this information and provides a simple +/// read-only interface to the entries found. +class AuxVector { + +public: + AuxVector(lldb_private::Process *process); + + struct Entry { + uint64_t type; + uint64_t value; + + Entry() : type(0), value(0) { } + }; + + /// Constants describing the type of entry. + enum EntryType { + AT_NULL = 0, ///< End of auxv. + AT_IGNORE = 1, ///< Ignore entry. + AT_EXECFD = 2, ///< File descriptor of program. + AT_PHDR = 3, ///< Program headers. + AT_PHENT = 4, ///< Size of program header. + AT_PHNUM = 5, ///< Number of program headers. + AT_PAGESZ = 6, ///< Page size. + AT_BASE = 7, ///< Interpreter base address. + AT_FLAGS = 8, ///< Flags. + AT_ENTRY = 9, ///< Program entry point. + AT_NOTELF = 10, ///< Set if program is not an ELF. + AT_UID = 11, ///< UID. + AT_EUID = 12, ///< Effective UID. + AT_GID = 13, ///< GID. + AT_EGID = 14, ///< Effective GID. + AT_CLKTCK = 17 ///< Clock frequency (e.g. times(2)). + }; + +private: + typedef std::vector EntryVector; + +public: + typedef EntryVector::const_iterator iterator; + + iterator begin() const { return m_auxv.begin(); } + iterator end() const { return m_auxv.end(); } + + iterator + FindEntry(EntryType type) const; + + static const char * + GetEntryName(const Entry &entry) { + return GetEntryName(static_cast(entry.type)); + } + + static const char * + GetEntryName(EntryType type); + + void + DumpToLog(lldb::LogSP log) const; + +private: + lldb_private::Process *m_process; + EntryVector m_auxv; + + lldb::DataBufferSP + GetAuxvData(); + + void + ParseAuxv(lldb_private::DataExtractor &data); +}; + +#endif diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp new file mode 100644 index 0000000..8b4795d --- /dev/null +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp @@ -0,0 +1,315 @@ +//===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "DYLDRendezvous.h" + +using namespace lldb; +using namespace lldb_private; + +/// Locates the address of the rendezvous structure. Returns the address on +/// success and LLDB_INVALID_ADDRESS on failure. +static addr_t +ResolveRendezvousAddress(Process *process) +{ + addr_t info_location; + addr_t info_addr; + Error error; + size_t size; + + info_location = process->GetImageInfoAddress(); + + if (info_location == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + info_addr = 0; + size = process->DoReadMemory(info_location, &info_addr, + process->GetAddressByteSize(), error); + if (size != process->GetAddressByteSize() || error.Fail()) + return LLDB_INVALID_ADDRESS; + + if (info_addr == 0) + return LLDB_INVALID_ADDRESS; + + return info_addr; +} + +DYLDRendezvous::DYLDRendezvous(Process *process) + : m_process(process), + m_rendezvous_addr(LLDB_INVALID_ADDRESS), + m_current(), + m_previous(), + m_soentries(), + m_added_soentries(), + m_removed_soentries() +{ +} + +bool +DYLDRendezvous::Resolve() +{ + const size_t word_size = 4; + Rendezvous info; + size_t address_size; + size_t padding; + addr_t info_addr; + addr_t cursor; + + address_size = m_process->GetAddressByteSize(); + padding = address_size - word_size; + + if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) + cursor = info_addr = ResolveRendezvousAddress(m_process); + else + cursor = info_addr = m_rendezvous_addr; + + if (cursor == LLDB_INVALID_ADDRESS) + return false; + + if (!(cursor = ReadMemory(cursor, &info.version, word_size))) + return false; + + if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size))) + return false; + + if (!(cursor = ReadMemory(cursor, &info.brk, address_size))) + return false; + + if (!(cursor = ReadMemory(cursor, &info.state, word_size))) + return false; + + if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size))) + return false; + + // The rendezvous was successfully read. Update our internal state. + m_rendezvous_addr = info_addr; + m_previous = m_current; + m_current = info; + + return UpdateSOEntries(); +} + +bool +DYLDRendezvous::IsValid() +{ + return m_rendezvous_addr != LLDB_INVALID_ADDRESS; +} + +bool +DYLDRendezvous::UpdateSOEntries() +{ + SOEntry entry; + + if (m_current.map_addr == 0) + return false; + + // If we are about to add or remove a shared object clear out the current + // state and take a snapshot of the currently loaded images. + if (m_current.state == eAdd || m_current.state == eDelete) + { + assert(m_previous.state == eConsistent); + m_soentries.clear(); + m_added_soentries.clear(); + m_removed_soentries.clear(); + return TakeSnapshot(m_soentries); + } + + // Otherwise check the previous state to determine what to expect and update + // accordingly. + if (m_previous.state == eAdd) + return UpdateSOEntriesForAddition(); + else if (m_previous.state == eDelete) + return UpdateSOEntriesForDeletion(); + + return false; +} + +bool +DYLDRendezvous::UpdateSOEntriesForAddition() +{ + SOEntry entry; + iterator pos; + + assert(m_previous.state == eAdd); + + if (m_current.map_addr == 0) + return false; + + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) + { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; + + if (entry.path.empty()) + continue; + + pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) + { + m_soentries.push_back(entry); + m_added_soentries.push_back(entry); + } + } + + return true; +} + +bool +DYLDRendezvous::UpdateSOEntriesForDeletion() +{ + SOEntryList entry_list; + iterator pos; + + assert(m_previous.state == eDelete); + + if (!TakeSnapshot(entry_list)) + return false; + + for (iterator I = begin(); I != end(); ++I) + { + pos = std::find(entry_list.begin(), entry_list.end(), *I); + if (pos == entry_list.end()) + m_removed_soentries.push_back(*I); + } + + m_soentries = entry_list; + return true; +} + +bool +DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) +{ + SOEntry entry; + + if (m_current.map_addr == 0) + return false; + + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) + { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; + + if (entry.path.empty()) + continue; + + entry_list.push_back(entry); + } + + return true; +} + +addr_t +DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size) +{ + size_t bytes_read; + Error error; + + bytes_read = m_process->DoReadMemory(addr, dst, size, error); + if (bytes_read != size || error.Fail()) + return 0; + + return addr + bytes_read; +} + +std::string +DYLDRendezvous::ReadStringFromMemory(addr_t addr) +{ + std::string str; + Error error; + size_t size; + char c; + + if (addr == LLDB_INVALID_ADDRESS) + return std::string(); + + for (;;) { + size = m_process->DoReadMemory(addr, &c, 1, error); + if (size != 1 || error.Fail()) + return std::string(); + if (c == 0) + break; + else { + str.push_back(c); + addr++; + } + } + + return str; +} + +bool +DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) +{ + size_t address_size = m_process->GetAddressByteSize(); + + entry.clear(); + + if (!(addr = ReadMemory(addr, &entry.base_addr, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.path_addr, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.next, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.prev, address_size))) + return false; + + entry.path = ReadStringFromMemory(entry.path_addr); + + return true; +} + +void +DYLDRendezvous::DumpToLog(LogSP log) const +{ + int state = GetState(); + + if (!log) + return; + + log->PutCString("DYLDRendezvous:"); + log->Printf(" Address: %lx", GetRendezvousAddress()); + log->Printf(" Version: %d", GetVersion()); + log->Printf(" Link : %lx", GetLinkMapAddress()); + log->Printf(" Break : %lx", GetBreakAddress()); + log->Printf(" LDBase : %lx", GetLDBase()); + log->Printf(" State : %s", + (state == eConsistent) ? "consistent" : + (state == eAdd) ? "add" : + (state == eDelete) ? "delete" : "unknown"); + + iterator I = begin(); + iterator E = end(); + + if (I != E) + log->PutCString("DYLDRendezvous SOEntries:"); + + for (int i = 1; I != E; ++I, ++i) + { + log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); + log->Printf(" Base : %lx", I->base_addr); + log->Printf(" Path : %lx", I->path_addr); + log->Printf(" Dyn : %lx", I->dyn_addr); + log->Printf(" Next : %lx", I->next); + log->Printf(" Prev : %lx", I->prev); + } +} diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h new file mode 100644 index 0000000..e8052ae --- /dev/null +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h @@ -0,0 +1,227 @@ +//===-- DYLDRendezvous.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Rendezvous_H_ +#define liblldb_Rendezvous_H_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { +class Process; +} + +/// @class DYLDRendezvous +/// @brief Interface to the runtime linker. +/// +/// A structure is present in a processes memory space which is updated by the +/// runtime liker each time a module is loaded or unloaded. This class provides +/// an interface to this structure and maintains a consistent snapshot of the +/// currently loaded modules. +class DYLDRendezvous { + + // This structure is used to hold the contents of the debug rendezvous + // information (struct r_debug) as found in the inferiors memory. Note that + // the layout of this struct is not binary compatible, it is simply large + // enough to hold the information on both 32 and 64 bit platforms. + struct Rendezvous { + uint64_t version; + lldb::addr_t map_addr; + lldb::addr_t brk; + uint64_t state; + lldb::addr_t ldbase; + + Rendezvous() + : version(0), map_addr(0), brk(0), state(0), ldbase(0) { } + }; + +public: + DYLDRendezvous(lldb_private::Process *process); + + /// Update the internal snapshot of runtime linker rendezvous and recompute + /// the currently loaded modules. + /// + /// This method should be called once one start up, then once each time the + /// runtime linker enters the function given by GetBreakAddress(). + /// + /// @returns true on success and false on failure. + /// + /// @see GetBreakAddress(). + bool + Resolve(); + + /// @returns true if this rendezvous has been located in the inferiors + /// address space and false otherwise. + bool + IsValid(); + + /// @returns the address of the rendezvous structure in the inferiors + /// address space. + lldb::addr_t + GetRendezvousAddress() const { return m_rendezvous_addr; } + + /// @returns the version of the rendezvous protocol being used. + int + GetVersion() const { return m_current.version; } + + /// @returns address in the inferiors address space containing the linked + /// list of shared object descriptors. + lldb::addr_t + GetLinkMapAddress() const { return m_current.map_addr; } + + /// A breakpoint should be set at this address and Resolve called on each + /// hit. + /// + /// @returns the address of a function called by the runtime linker each + /// time a module is loaded/unloaded, or about to be loaded/unloaded. + /// + /// @see Resolve() + lldb::addr_t + GetBreakAddress() const { return m_current.brk; } + + /// Returns the current state of the rendezvous structure. + int + GetState() const { return m_current.state; } + + /// @returns the base address of the runtime linker in the inferiors address + /// space. + lldb::addr_t + GetLDBase() const { return m_current.ldbase; } + + /// @returns true if modules have been loaded into the inferior since the + /// last call to Resolve(). + bool + ModulesDidLoad() const { return !m_added_soentries.empty(); } + + /// @returns true if modules have been unloaded from the inferior since the + /// last call to Resolve(). + bool + ModulesDidUnload() const { return !m_removed_soentries.empty(); } + + void + DumpToLog(lldb::LogSP log) const; + + /// @brief Constants describing the state of the rendezvous. + /// + /// @see GetState(). + enum RendezvousState { + eConsistent, + eAdd, + eDelete + }; + + /// @brief Structure representing the shared objects currently loaded into + /// the inferior process. + /// + /// This object is a rough analogue to the struct link_map object which + /// actually lives in the inferiors memory. + struct SOEntry { + lldb::addr_t base_addr; ///< Base address of the loaded object. + lldb::addr_t path_addr; ///< String naming the shared object. + lldb::addr_t dyn_addr; ///< Dynamic section of shared object. + lldb::addr_t next; ///< Address of next so_entry. + lldb::addr_t prev; ///< Address of previous so_entry. + std::string path; ///< File name of shared object. + + SOEntry() { clear(); } + + bool operator ==(const SOEntry &entry) { + return this->path == entry.path; + } + + void clear() { + base_addr = 0; + path_addr = 0; + dyn_addr = 0; + next = 0; + prev = 0; + path.clear(); + } + }; + +protected: + typedef std::list SOEntryList; + +public: + typedef SOEntryList::const_iterator iterator; + + /// Iterators over all currently loaded modules. + iterator begin() const { return m_soentries.begin(); } + iterator end() const { return m_soentries.end(); } + + /// Iterators over all modules loaded into the inferior since the last call + /// to Resolve(). + iterator loaded_begin() const { return m_added_soentries.begin(); } + iterator loaded_end() const { return m_added_soentries.end(); } + + /// Iterators over all modules unloaded from the inferior since the last + /// call to Resolve(). + iterator unloaded_begin() const { return m_removed_soentries.begin(); } + iterator unloaded_end() const { return m_removed_soentries.end(); } + +protected: + lldb_private::Process *m_process; + + /// Location of the r_debug structure in the inferiors address space. + lldb::addr_t m_rendezvous_addr; + + /// Current and previous snapshots of the rendezvous structure. + Rendezvous m_current; + Rendezvous m_previous; + + /// List of SOEntry objects corresponding to the current link map state. + SOEntryList m_soentries; + + /// List of SOEntry's added to the link map since the last call to Resolve(). + SOEntryList m_added_soentries; + + /// List of SOEntry's removed from the link map since the last call to + /// Resolve(). + SOEntryList m_removed_soentries; + + /// Reads @p size bytes from the inferiors address space starting at @p + /// addr. + /// + /// @returns addr + size if the read was successful and false otherwise. + lldb::addr_t + ReadMemory(lldb::addr_t addr, void *dst, size_t size); + + /// Reads a null-terminated C string from the memory location starting at @p + /// addr. + std::string + ReadStringFromMemory(lldb::addr_t addr); + + /// Reads an SOEntry starting at @p addr. + bool + ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); + + /// Updates the current set of SOEntries, the set of added entries, and the + /// set of removed entries. + bool + UpdateSOEntries(); + + bool + UpdateSOEntriesForAddition(); + + bool + UpdateSOEntriesForDeletion(); + + /// Reads the current list of shared objects according to the link map + /// supplied by the runtime linker. + bool + TakeSnapshot(SOEntryList &entry_list); +}; + +#endif diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp new file mode 100644 index 0000000..0802ff6 --- /dev/null +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp @@ -0,0 +1,371 @@ +//===-- DynamicLoaderLinux.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "AuxVector.h" +#include "DynamicLoaderLinuxDYLD.h" + +using namespace lldb; +using namespace lldb_private; + +void +DynamicLoaderLinuxDYLD::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +DynamicLoaderLinuxDYLD::Terminate() +{ +} + +const char * +DynamicLoaderLinuxDYLD::GetPluginName() +{ + return "DynamicLoaderLinuxDYLD"; +} + +const char * +DynamicLoaderLinuxDYLD::GetShortPluginName() +{ + return "linux-dyld"; +} + +const char * +DynamicLoaderLinuxDYLD::GetPluginNameStatic() +{ + return "dynamic-loader.linux-dyld"; +} + +const char * +DynamicLoaderLinuxDYLD::GetPluginDescriptionStatic() +{ + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in Linux processes."; +} + +void +DynamicLoaderLinuxDYLD::GetPluginCommandHelp(const char *command, Stream *strm) +{ +} + +uint32_t +DynamicLoaderLinuxDYLD::GetPluginVersion() +{ + return 1; +} + +DynamicLoader * +DynamicLoaderLinuxDYLD::CreateInstance(Process *process) +{ + return new DynamicLoaderLinuxDYLD(process); +} + +DynamicLoaderLinuxDYLD::DynamicLoaderLinuxDYLD(Process *process) + : DynamicLoader(process), + m_rendezvous(process), + m_load_offset(LLDB_INVALID_ADDRESS), + m_entry_point(LLDB_INVALID_ADDRESS), + m_auxv(NULL) +{ +} + +DynamicLoaderLinuxDYLD::~DynamicLoaderLinuxDYLD() +{ +} + +void +DynamicLoaderLinuxDYLD::DidAttach() +{ + ModuleSP executable; + addr_t load_offset; + + m_auxv.reset(new AuxVector(m_process)); + + executable = m_process->GetTarget().GetExecutableModule(); + load_offset = ComputeLoadOffset(); + + if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS) + { + ModuleList module_list; + module_list.Append(executable); + UpdateLoadedSections(executable, load_offset); + m_process->GetTarget().ModulesDidLoad(module_list); + } +} + +void +DynamicLoaderLinuxDYLD::DidLaunch() +{ + ModuleSP executable; + addr_t load_offset; + + m_auxv.reset(new AuxVector(m_process)); + + executable = m_process->GetTarget().GetExecutableModule(); + load_offset = ComputeLoadOffset(); + + if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS) + { + ModuleList module_list; + module_list.Append(executable); + UpdateLoadedSections(executable, load_offset); + ProbeEntry(); + m_process->GetTarget().ModulesDidLoad(module_list); + } +} + +Error +DynamicLoaderLinuxDYLD::ExecutePluginCommand(Args &command, Stream *strm) +{ + return Error(); +} + +Log * +DynamicLoaderLinuxDYLD::EnablePluginLogging(Stream *strm, Args &command) +{ + return NULL; +} + +Error +DynamicLoaderLinuxDYLD::CanLoadImage() +{ + return Error(); +} + +void +DynamicLoaderLinuxDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr) +{ + ObjectFile *obj_file = module->GetObjectFile(); + SectionList *sections = obj_file->GetSectionList(); + SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); + const size_t num_sections = sections->GetSize(); + + for (unsigned i = 0; i < num_sections; ++i) + { + Section *section = sections->GetSectionAtIndex(i).get(); + lldb::addr_t new_load_addr = section->GetFileAddress() + base_addr; + lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section); + + // If the file address of the section is zero then this is not an + // allocatable/loadable section (property of ELF sh_addr). Skip it. + if (new_load_addr == base_addr) + continue; + + if (old_load_addr == LLDB_INVALID_ADDRESS || + old_load_addr != new_load_addr) + load_list.SetSectionLoadAddress(section, new_load_addr); + } +} + +void +DynamicLoaderLinuxDYLD::ProbeEntry() +{ + Breakpoint *entry_break; + addr_t entry; + + if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) + return; + + entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get(); + entry_break->SetCallback(EntryBreakpointHit, this, true); +} + +// The runtime linker has run and initialized the rendezvous structure once the +// process has hit its entry point. When we hit the corresponding breakpoint we +// interrogate the rendezvous structure to get the load addresses of all +// dependent modules for the process. Similarly, we can discover the runtime +// linker function and setup a breakpoint to notify us of any dynamically loaded +// modules (via dlopen). +bool +DynamicLoaderLinuxDYLD::EntryBreakpointHit(void *baton, + StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id) +{ + DynamicLoaderLinuxDYLD* dyld_instance; + + dyld_instance = static_cast(baton); + dyld_instance->LoadAllCurrentModules(); + dyld_instance->SetRendezvousBreakpoint(); + return false; // Continue running. +} + +void +DynamicLoaderLinuxDYLD::SetRendezvousBreakpoint() +{ + Breakpoint *dyld_break; + addr_t break_addr; + + break_addr = m_rendezvous.GetBreakAddress(); + dyld_break = m_process->GetTarget().CreateBreakpoint(break_addr, true).get(); + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); +} + +bool +DynamicLoaderLinuxDYLD::RendezvousBreakpointHit(void *baton, + StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id) +{ + DynamicLoaderLinuxDYLD* dyld_instance; + + dyld_instance = static_cast(baton); + dyld_instance->RefreshModules(); + + // Return true to stop the target, false to just let the target run. + return dyld_instance->GetStopWhenImagesChange(); +} + +void +DynamicLoaderLinuxDYLD::RefreshModules() +{ + if (!m_rendezvous.Resolve()) + return; + + DYLDRendezvous::iterator I; + DYLDRendezvous::iterator E; + + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + if (m_rendezvous.ModulesDidLoad()) + { + ModuleList new_modules; + + E = m_rendezvous.loaded_end(); + for (I = m_rendezvous.loaded_begin(); I != E; ++I) + { + FileSpec file(I->path.c_str(), true); + ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); + if (!module_sp.empty()) + new_modules.Append(module_sp); + } + m_process->GetTarget().ModulesDidLoad(new_modules); + } + + if (m_rendezvous.ModulesDidUnload()) + { + ModuleList old_modules; + + E = m_rendezvous.unloaded_end(); + for (I = m_rendezvous.unloaded_begin(); I != E; ++I) + { + FileSpec file(I->path.c_str(), true); + ModuleSP module_sp = loaded_modules.FindFirstModuleForFileSpec(file); + if (!module_sp.empty()) + old_modules.Append(module_sp); + } + m_process->GetTarget().ModulesDidUnload(old_modules); + } +} + +ThreadPlanSP +DynamicLoaderLinuxDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop_others) +{ + LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + ThreadPlanSP thread_plan_sp; + + if (log) + log->PutCString("DynamicLoaderLinuxDYLD: " + "GetStepThroughTrampolinePlan not implemented\n"); + + return thread_plan_sp; +} + +void +DynamicLoaderLinuxDYLD::LoadAllCurrentModules() +{ + DYLDRendezvous::iterator I; + DYLDRendezvous::iterator E; + ModuleList module_list; + + if (!m_rendezvous.Resolve()) + return; + + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) + { + FileSpec file(I->path.c_str(), false); + ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); + if (!module_sp.empty()) + module_list.Append(module_sp); + } + + m_process->GetTarget().ModulesDidLoad(module_list); +} + +ModuleSP +DynamicLoaderLinuxDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr) +{ + Target &target = m_process->GetTarget(); + ModuleList &modules = target.GetImages(); + ModuleSP module_sp; + + if ((module_sp = modules.FindFirstModuleForFileSpec(file))) + { + UpdateLoadedSections(module_sp, base_addr); + } + else if ((module_sp = target.GetSharedModule(file, target.GetArchitecture()))) + { + UpdateLoadedSections(module_sp, base_addr); + modules.Append(module_sp); + } + + return module_sp; +} + +addr_t +DynamicLoaderLinuxDYLD::ComputeLoadOffset() +{ + addr_t virt_entry; + + if (m_load_offset != LLDB_INVALID_ADDRESS) + return m_load_offset; + + if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + ModuleSP module = m_process->GetTarget().GetExecutableModule(); + ObjectFile *exe = module->GetObjectFile(); + Address file_entry = exe->GetEntryPoint(); + + if (!file_entry.IsValid()) + return LLDB_INVALID_ADDRESS; + + m_load_offset = virt_entry - file_entry.GetFileAddress(); + return m_load_offset; +} + +addr_t +DynamicLoaderLinuxDYLD::GetEntryPoint() +{ + if (m_entry_point != LLDB_INVALID_ADDRESS) + return m_entry_point; + + if (m_auxv.get() == NULL) + return LLDB_INVALID_ADDRESS; + + AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY); + + if (I == m_auxv->end()) + return LLDB_INVALID_ADDRESS; + + m_entry_point = static_cast(I->value); + return m_entry_point; +} diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h new file mode 100644 index 0000000..bc537ce --- /dev/null +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h @@ -0,0 +1,165 @@ +//===-- DynamicLoaderLinux.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DynamicLoaderLinux_H_ +#define liblldb_DynamicLoaderLinux_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Target/DynamicLoader.h" + +#include "DYLDRendezvous.h" + +class AuxVector; + +class DynamicLoaderLinuxDYLD : public lldb_private::DynamicLoader +{ +public: + + static void + Initialize(); + + static void + Terminate(); + + static const char * + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process); + + DynamicLoaderLinuxDYLD(lldb_private::Process *process); + + virtual + ~DynamicLoaderLinuxDYLD(); + + //------------------------------------------------------------------ + // DynamicLoader protocol + //------------------------------------------------------------------ + + virtual void + DidAttach(); + + virtual void + DidLaunch(); + + virtual lldb::ThreadPlanSP + GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others); + + virtual lldb_private::Error + CanLoadImage(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual const char * + GetPluginName(); + + virtual const char * + GetShortPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + GetPluginCommandHelp(const char *command, lldb_private::Stream *strm); + + virtual lldb_private::Error + ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm); + + virtual lldb_private::Log * + EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command); + +protected: + /// Runtime linker rendezvous structure. + DYLDRendezvous m_rendezvous; + + /// Virtual load address of the inferior process. + lldb::addr_t m_load_offset; + + /// Virtual entry address of the inferior process. + lldb::addr_t m_entry_point; + + /// Auxiliary vector of the inferior process. + std::auto_ptr m_auxv; + + /// Enables a breakpoint on a function called by the runtime + /// linker each time a module is loaded or unloaded. + void + SetRendezvousBreakpoint(); + + /// Callback routine which updates the current list of loaded modules based + /// on the information supplied by the runtime linker. + static bool + RendezvousBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set + /// of loaded modules. + void + RefreshModules(); + + /// Updates the load address of every allocatable section in @p module. + /// + /// @param module The module to traverse. + /// + /// @param base_addr The virtual base address @p module is loaded at. + void + UpdateLoadedSections(lldb::ModuleSP module, + lldb::addr_t base_addr = 0); + + /// Locates or creates a module given by @p file and updates/loads the + /// resulting module at the virtual base address @p base_addr. + lldb::ModuleSP + LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t base_addr); + + /// Resolves the entry point for the current inferior process and sets a + /// breakpoint at that address. + void + ProbeEntry(); + + /// Callback routine invoked when we hit the breakpoint on process entry. + /// + /// This routine is responsible for resolving the load addresses of all + /// dependent modules required by the inferior and setting up the rendezvous + /// breakpoint. + static bool + EntryBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + /// Helper for the entry breakpoint callback. Resolves the load addresses + /// of all dependent modules. + void + LoadAllCurrentModules(); + + /// Computes a value for m_load_offset returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t + ComputeLoadOffset(); + + /// Computes a value for m_entry_point returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t + GetEntryPoint(); + +private: + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderLinuxDYLD); +}; + +#endif // liblldb_DynamicLoaderLinuxDYLD_H_ diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/Makefile b/source/Plugins/DynamicLoader/Linux-DYLD/Makefile new file mode 100644 index 0000000..94025dd --- /dev/null +++ b/source/Plugins/DynamicLoader/Linux-DYLD/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/DynamicLoader/Linux-DYLD/Makefile ----*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginDynamicLoaderLinux +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile diff --git a/source/Plugins/Makefile b/source/Plugins/Makefile index 14eed8a..a3d644f 100644 --- a/source/Plugins/Makefile +++ b/source/Plugins/Makefile @@ -23,7 +23,7 @@ DIRS += DynamicLoader/MacOSX-DYLD ObjectContainer/Universal-Mach-O \ endif ifeq ($(HOST_OS),Linux) -DIRS += Process/Linux +DIRS += Process/Linux DynamicLoader/Linux-DYLD endif include $(LLDB_LEVEL)/Makefile diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp index 00bdda5..d7fe1da 100644 --- a/source/Plugins/Process/Linux/ProcessLinux.cpp +++ b/source/Plugins/Process/Linux/ProcessLinux.cpp @@ -13,6 +13,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Target.h" #include "ProcessLinux.h" @@ -102,6 +103,19 @@ ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid) } Error +ProcessLinux::WillLaunch(Module* module) +{ + Error error; + + m_dyld_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.linux-dyld")); + if (m_dyld_ap.get() == NULL) + error.SetErrorString("unable to find the dynamic loader named " + "'dynamic-loader.linux-dyld'"); + + return error; +} + +Error ProcessLinux::DoLaunch(Module *module, char const *argv[], char const *envp[], @@ -128,6 +142,13 @@ ProcessLinux::DoLaunch(Module *module, return error; } +void +ProcessLinux::DidLaunch() +{ + if (m_dyld_ap.get() != NULL) + m_dyld_ap->DidLaunch(); +} + Error ProcessLinux::DoResume() { @@ -371,6 +392,12 @@ ProcessLinux::GetByteOrder() const return m_byte_order; } +DynamicLoader * +ProcessLinux::GetDynamicLoader() +{ + return m_dyld_ap.get(); +} + //------------------------------------------------------------------------------ // ProcessInterface protocol. diff --git a/source/Plugins/Process/Linux/ProcessLinux.h b/source/Plugins/Process/Linux/ProcessLinux.h index 3e23a7a..fbf14df 100644 --- a/source/Plugins/Process/Linux/ProcessLinux.h +++ b/source/Plugins/Process/Linux/ProcessLinux.h @@ -60,6 +60,9 @@ public: CanDebug(lldb_private::Target &target); virtual lldb_private::Error + WillLaunch(lldb_private::Module *module); + + virtual lldb_private::Error DoAttachToProcessWithID(lldb::pid_t pid); virtual lldb_private::Error @@ -71,6 +74,9 @@ public: const char *stdout_path, const char *stderr_path); + virtual void + DidLaunch(); + virtual lldb_private::Error DoResume(); @@ -131,6 +137,9 @@ public: virtual lldb::addr_t GetImageInfoAddress(); + virtual lldb_private::DynamicLoader * + GetDynamicLoader(); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -176,6 +185,9 @@ private: lldb_private::Mutex m_message_mutex; std::queue m_message_queue; + /// Dynamic loader plugin associated with this process. + std::auto_ptr m_dyld_ap; + /// Updates the loaded sections provided by the executable. /// /// FIXME: It would probably be better to delegate this task to the diff --git a/source/lldb.cpp b/source/lldb.cpp index 05c7f4b..ac281a2 100644 --- a/source/lldb.cpp +++ b/source/lldb.cpp @@ -44,6 +44,7 @@ #ifdef __linux__ #include "Plugins/Process/Linux/ProcessLinux.h" +#include "Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h" #endif using namespace lldb; @@ -94,6 +95,7 @@ lldb_private::Initialize () #endif #ifdef __linux__ ProcessLinux::Initialize(); + DynamicLoaderLinuxDYLD::Initialize(); #endif } } @@ -137,6 +139,7 @@ lldb_private::Terminate () #ifdef __linux__ ProcessLinux::Terminate(); + DynamicLoaderLinuxDYLD::Terminate(); #endif Log::Terminate(); -- 1.7.3.5 From gclayton at apple.com Sat Jan 15 17:48:37 2011 From: gclayton at apple.com (Greg Clayton) Date: Sat, 15 Jan 2011 15:48:37 -0800 Subject: [Lldb-commits] [PATCH][RFC] Linux DynamicLoader plugin. In-Reply-To: References: Message-ID: Looks good, and great news that linux now has a dynamic loader. The nice thing is if you want remote linux debugging, we can modify the ProcessGDBRemote plug-in, on linux by default, to use this dynamic loader plug-in since they are completely pluggable. We would need to just write a linux remote debug server. The current "debugserver" project really needs to be re-written from the ground up using the classes we have in LLDB (StringExtractor, GDBRemoteCommunication, StringExtractorGDBRemote). One might also be able to make slight modifications to the existing GDB gdbserver binary (from the current GDB sources) for linux, and use it as the remote stub to connect to with LLDB! Greg Clayton On Jan 15, 2011, at 11:40 AM, Stephen Wilson wrote: > > This patch is enough to have shared objects recognized by LLDB on Linux. > We can handle position independent executables. We can handle > dynamically loaded modules brought in via dlopen. > > The DYLDRendezvous class provides an interface to a structure present in > the address space of ELF-based processes. This structure provides the > location of a function which is called by the runtime linker each time a > shared object is loaded and unloaded (thus a breakpoint at that address > will let LLDB intercept such events), a list of entries describing the > currently loaded shared objects, plus a few other things. > > On Linux, processes are brought up with an auxiliary vector on the > stack. One element in this vector contains the (possibly dynamic) entry > address of the process. One does not need to walk the stack to find > this information as it is available under /proc//auxv. The new > AuxVector class provides a convenient read-only view of this auxiliary > information. We use the dynamic entry address and the address as > specified in the object file to compute the actual load address of the > inferior image. This strategy works for both normal executables and > PIE's. > > As most of this code is new the following diff might not be the most > readable. One can also browse the files online here: > > https://github.com/eightcien/lldb/tree/lldb-linux/source/Plugins/DynamicLoader/Linux-DYLD > > > --- > lib/Makefile | 3 +- > .../Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp | 191 ++++++++++ > .../Plugins/DynamicLoader/Linux-DYLD/AuxVector.h | 97 +++++ > .../DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp | 315 +++++++++++++++++ > .../DynamicLoader/Linux-DYLD/DYLDRendezvous.h | 227 ++++++++++++ > .../Linux-DYLD/DynamicLoaderLinuxDYLD.cpp | 371 ++++++++++++++++++++ > .../Linux-DYLD/DynamicLoaderLinuxDYLD.h | 165 +++++++++ > source/Plugins/DynamicLoader/Linux-DYLD/Makefile | 14 + > source/Plugins/Makefile | 2 +- > source/Plugins/Process/Linux/ProcessLinux.cpp | 27 ++ > source/Plugins/Process/Linux/ProcessLinux.h | 12 + > source/lldb.cpp | 3 + > 12 files changed, 1425 insertions(+), 2 deletions(-) > create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp > create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h > create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp > create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h > create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp > create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h > create mode 100644 source/Plugins/DynamicLoader/Linux-DYLD/Makefile > > diff --git a/lib/Makefile b/lib/Makefile > index 881b23c..abd9c1d 100644 > --- a/lib/Makefile > +++ b/lib/Makefile > @@ -67,7 +67,8 @@ ifeq ($(HOST_OS),Darwin) > endif > > ifeq ($(HOST_OS),Linux) > - USEDLIBS += lldbPluginProcessLinux.a > + USEDLIBS += lldbPluginProcessLinux.a \ > + lldbPluginDynamicLoaderLinux.a > endif > > include $(LEVEL)/Makefile.common > diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp > new file mode 100644 > index 0000000..6954e4c > --- /dev/null > +++ b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp > @@ -0,0 +1,191 @@ > +//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +// C Includes > +#include > +#include > +#include > + > +// C++ Includes > +// Other libraries and framework includes > +#include "lldb/Core/DataBufferHeap.h" > +#include "lldb/Core/DataExtractor.h" > +#include "lldb/Core/Log.h" > +#include "lldb/Target/Process.h" > + > +#include "AuxVector.h" > + > +using namespace lldb; > +using namespace lldb_private; > + > +static bool > +GetMaxU64(DataExtractor &data, > + uint32_t *offset, uint64_t *value, unsigned int byte_size) > +{ > + uint32_t saved_offset = *offset; > + *value = data.GetMaxU64(offset, byte_size); > + return *offset != saved_offset; > +} > + > +static bool > +ParseAuxvEntry(DataExtractor &data, AuxVector::Entry &entry, > + uint32_t *offset, unsigned int byte_size) > +{ > + if (!GetMaxU64(data, offset, &entry.type, byte_size)) > + return false; > + > + if (!GetMaxU64(data, offset, &entry.value, byte_size)) > + return false; > + > + return true; > +} > + > +DataBufferSP > +AuxVector::GetAuxvData() > +{ > + static const size_t path_size = 128; > + static char path[path_size]; > + DataBufferSP buf_sp; > + int fd; > + > + // Ideally, we would simply create a FileSpec and call ReadFileContents. > + // However, files in procfs have zero size (since they are, in general, > + // dynamically generated by the kernel) which is incompatible with the > + // current ReadFileContents implementation. Therefore we simply stream the > + // data into a DataBuffer ourselves. > + if (snprintf(path, path_size, "/proc/%d/auxv", m_process->GetID()) < 0) > + return buf_sp; > + > + if ((fd = open(path, O_RDONLY, 0)) < 0) > + return buf_sp; > + > + size_t bytes_read = 0; > + std::auto_ptr buf_ap(new DataBufferHeap(1024, 0)); > + for (;;) > + { > + size_t avail = buf_ap->GetByteSize() - bytes_read; > + ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail); > + > + if (status < 0) > + break; > + > + bytes_read += status; > + > + if (status == 0) > + { > + buf_ap->SetByteSize(bytes_read); > + buf_sp.reset(buf_ap.release()); > + break; > + } > + > + if (avail - status == 0) > + buf_ap->SetByteSize(2 * buf_ap->GetByteSize()); > + } > + > + return buf_sp; > +} > + > +void > +AuxVector::ParseAuxv(DataExtractor &data) > +{ > + const unsigned int byte_size = m_process->GetAddressByteSize(); > + uint32_t offset = 0; > + > + for (;;) > + { > + Entry entry; > + > + if (!ParseAuxvEntry(data, entry, &offset, byte_size)) > + break; > + > + if (entry.type == AT_NULL) > + break; > + > + if (entry.type == AT_IGNORE) > + continue; > + > + m_auxv.push_back(entry); > + } > +} > + > +AuxVector::AuxVector(Process *process) > + : m_process(process) > +{ > + DataExtractor data; > + LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); > + > + data.SetData(GetAuxvData()); > + data.SetByteOrder(m_process->GetByteOrder()); > + data.SetAddressByteSize(m_process->GetAddressByteSize()); > + > + ParseAuxv(data); > + > + if (log) > + DumpToLog(log); > +} > + > +AuxVector::iterator > +AuxVector::FindEntry(EntryType type) const > +{ > + for (iterator I = begin(); I != end(); ++I) > + { > + if (I->type == static_cast(type)) > + return I; > + } > + > + return end(); > +} > + > +void > +AuxVector::DumpToLog(LogSP log) const > +{ > + if (!log) > + return; > + > + log->PutCString("AuxVector: "); > + for (iterator I = begin(); I != end(); ++I) > + { > + log->Printf(" %s [%d]: %lx", GetEntryName(*I), I->type, I->value); > + } > +} > + > +const char * > +AuxVector::GetEntryName(EntryType type) > +{ > + const char *name; > + > +#define ENTRY_NAME(_type) _type: name = #_type > + switch (type) > + { > + default: > + name = "unkown"; > + break; > + > + case ENTRY_NAME(AT_NULL); break; > + case ENTRY_NAME(AT_IGNORE); break; > + case ENTRY_NAME(AT_EXECFD); break; > + case ENTRY_NAME(AT_PHDR); break; > + case ENTRY_NAME(AT_PHENT); break; > + case ENTRY_NAME(AT_PHNUM); break; > + case ENTRY_NAME(AT_PAGESZ); break; > + case ENTRY_NAME(AT_BASE); break; > + case ENTRY_NAME(AT_FLAGS); break; > + case ENTRY_NAME(AT_ENTRY); break; > + case ENTRY_NAME(AT_NOTELF); break; > + case ENTRY_NAME(AT_UID); break; > + case ENTRY_NAME(AT_EUID); break; > + case ENTRY_NAME(AT_GID); break; > + case ENTRY_NAME(AT_EGID); break; > + case ENTRY_NAME(AT_CLKTCK); break; > + } > +#undef ENTRY_NAME > + > + return name; > +} > + > diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h > new file mode 100644 > index 0000000..7a5b370 > --- /dev/null > +++ b/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h > @@ -0,0 +1,97 @@ > +//===-- AuxVector.h ---------------------------------------------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef liblldb_AuxVector_H_ > +#define liblldb_AuxVector_H_ > + > +// C Includes > +// C++ Includes > +#include > + > +// Other libraries and framework includes > +#include "lldb/lldb-forward-rtti.h" > + > +namespace lldb_private { > +class DataExtractor; > +} > + > +/// @class AuxVector > +/// @brief Represents a processes auxiliary vector. > +/// > +/// When a process is loaded on Linux a vector of values is placed onto the > +/// stack communicating operating system specific information. On construction > +/// this class locates and parses this information and provides a simple > +/// read-only interface to the entries found. > +class AuxVector { > + > +public: > + AuxVector(lldb_private::Process *process); > + > + struct Entry { > + uint64_t type; > + uint64_t value; > + > + Entry() : type(0), value(0) { } > + }; > + > + /// Constants describing the type of entry. > + enum EntryType { > + AT_NULL = 0, ///< End of auxv. > + AT_IGNORE = 1, ///< Ignore entry. > + AT_EXECFD = 2, ///< File descriptor of program. > + AT_PHDR = 3, ///< Program headers. > + AT_PHENT = 4, ///< Size of program header. > + AT_PHNUM = 5, ///< Number of program headers. > + AT_PAGESZ = 6, ///< Page size. > + AT_BASE = 7, ///< Interpreter base address. > + AT_FLAGS = 8, ///< Flags. > + AT_ENTRY = 9, ///< Program entry point. > + AT_NOTELF = 10, ///< Set if program is not an ELF. > + AT_UID = 11, ///< UID. > + AT_EUID = 12, ///< Effective UID. > + AT_GID = 13, ///< GID. > + AT_EGID = 14, ///< Effective GID. > + AT_CLKTCK = 17 ///< Clock frequency (e.g. times(2)). > + }; > + > +private: > + typedef std::vector EntryVector; > + > +public: > + typedef EntryVector::const_iterator iterator; > + > + iterator begin() const { return m_auxv.begin(); } > + iterator end() const { return m_auxv.end(); } > + > + iterator > + FindEntry(EntryType type) const; > + > + static const char * > + GetEntryName(const Entry &entry) { > + return GetEntryName(static_cast(entry.type)); > + } > + > + static const char * > + GetEntryName(EntryType type); > + > + void > + DumpToLog(lldb::LogSP log) const; > + > +private: > + lldb_private::Process *m_process; > + EntryVector m_auxv; > + > + lldb::DataBufferSP > + GetAuxvData(); > + > + void > + ParseAuxv(lldb_private::DataExtractor &data); > +}; > + > +#endif > diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp > new file mode 100644 > index 0000000..8b4795d > --- /dev/null > +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp > @@ -0,0 +1,315 @@ > +//===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +// C Includes > +// C++ Includes > +// Other libraries and framework includes > +#include "lldb/Core/ArchSpec.h" > +#include "lldb/Core/Error.h" > +#include "lldb/Core/Log.h" > +#include "lldb/Target/Process.h" > +#include "lldb/Target/Target.h" > + > +#include "DYLDRendezvous.h" > + > +using namespace lldb; > +using namespace lldb_private; > + > +/// Locates the address of the rendezvous structure. Returns the address on > +/// success and LLDB_INVALID_ADDRESS on failure. > +static addr_t > +ResolveRendezvousAddress(Process *process) > +{ > + addr_t info_location; > + addr_t info_addr; > + Error error; > + size_t size; > + > + info_location = process->GetImageInfoAddress(); > + > + if (info_location == LLDB_INVALID_ADDRESS) > + return LLDB_INVALID_ADDRESS; > + > + info_addr = 0; > + size = process->DoReadMemory(info_location, &info_addr, > + process->GetAddressByteSize(), error); > + if (size != process->GetAddressByteSize() || error.Fail()) > + return LLDB_INVALID_ADDRESS; > + > + if (info_addr == 0) > + return LLDB_INVALID_ADDRESS; > + > + return info_addr; > +} > + > +DYLDRendezvous::DYLDRendezvous(Process *process) > + : m_process(process), > + m_rendezvous_addr(LLDB_INVALID_ADDRESS), > + m_current(), > + m_previous(), > + m_soentries(), > + m_added_soentries(), > + m_removed_soentries() > +{ > +} > + > +bool > +DYLDRendezvous::Resolve() > +{ > + const size_t word_size = 4; > + Rendezvous info; > + size_t address_size; > + size_t padding; > + addr_t info_addr; > + addr_t cursor; > + > + address_size = m_process->GetAddressByteSize(); > + padding = address_size - word_size; > + > + if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) > + cursor = info_addr = ResolveRendezvousAddress(m_process); > + else > + cursor = info_addr = m_rendezvous_addr; > + > + if (cursor == LLDB_INVALID_ADDRESS) > + return false; > + > + if (!(cursor = ReadMemory(cursor, &info.version, word_size))) > + return false; > + > + if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size))) > + return false; > + > + if (!(cursor = ReadMemory(cursor, &info.brk, address_size))) > + return false; > + > + if (!(cursor = ReadMemory(cursor, &info.state, word_size))) > + return false; > + > + if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size))) > + return false; > + > + // The rendezvous was successfully read. Update our internal state. > + m_rendezvous_addr = info_addr; > + m_previous = m_current; > + m_current = info; > + > + return UpdateSOEntries(); > +} > + > +bool > +DYLDRendezvous::IsValid() > +{ > + return m_rendezvous_addr != LLDB_INVALID_ADDRESS; > +} > + > +bool > +DYLDRendezvous::UpdateSOEntries() > +{ > + SOEntry entry; > + > + if (m_current.map_addr == 0) > + return false; > + > + // If we are about to add or remove a shared object clear out the current > + // state and take a snapshot of the currently loaded images. > + if (m_current.state == eAdd || m_current.state == eDelete) > + { > + assert(m_previous.state == eConsistent); > + m_soentries.clear(); > + m_added_soentries.clear(); > + m_removed_soentries.clear(); > + return TakeSnapshot(m_soentries); > + } > + > + // Otherwise check the previous state to determine what to expect and update > + // accordingly. > + if (m_previous.state == eAdd) > + return UpdateSOEntriesForAddition(); > + else if (m_previous.state == eDelete) > + return UpdateSOEntriesForDeletion(); > + > + return false; > +} > + > +bool > +DYLDRendezvous::UpdateSOEntriesForAddition() > +{ > + SOEntry entry; > + iterator pos; > + > + assert(m_previous.state == eAdd); > + > + if (m_current.map_addr == 0) > + return false; > + > + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) > + { > + if (!ReadSOEntryFromMemory(cursor, entry)) > + return false; > + > + if (entry.path.empty()) > + continue; > + > + pos = std::find(m_soentries.begin(), m_soentries.end(), entry); > + if (pos == m_soentries.end()) > + { > + m_soentries.push_back(entry); > + m_added_soentries.push_back(entry); > + } > + } > + > + return true; > +} > + > +bool > +DYLDRendezvous::UpdateSOEntriesForDeletion() > +{ > + SOEntryList entry_list; > + iterator pos; > + > + assert(m_previous.state == eDelete); > + > + if (!TakeSnapshot(entry_list)) > + return false; > + > + for (iterator I = begin(); I != end(); ++I) > + { > + pos = std::find(entry_list.begin(), entry_list.end(), *I); > + if (pos == entry_list.end()) > + m_removed_soentries.push_back(*I); > + } > + > + m_soentries = entry_list; > + return true; > +} > + > +bool > +DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) > +{ > + SOEntry entry; > + > + if (m_current.map_addr == 0) > + return false; > + > + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) > + { > + if (!ReadSOEntryFromMemory(cursor, entry)) > + return false; > + > + if (entry.path.empty()) > + continue; > + > + entry_list.push_back(entry); > + } > + > + return true; > +} > + > +addr_t > +DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size) > +{ > + size_t bytes_read; > + Error error; > + > + bytes_read = m_process->DoReadMemory(addr, dst, size, error); > + if (bytes_read != size || error.Fail()) > + return 0; > + > + return addr + bytes_read; > +} > + > +std::string > +DYLDRendezvous::ReadStringFromMemory(addr_t addr) > +{ > + std::string str; > + Error error; > + size_t size; > + char c; > + > + if (addr == LLDB_INVALID_ADDRESS) > + return std::string(); > + > + for (;;) { > + size = m_process->DoReadMemory(addr, &c, 1, error); > + if (size != 1 || error.Fail()) > + return std::string(); > + if (c == 0) > + break; > + else { > + str.push_back(c); > + addr++; > + } > + } > + > + return str; > +} > + > +bool > +DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) > +{ > + size_t address_size = m_process->GetAddressByteSize(); > + > + entry.clear(); > + > + if (!(addr = ReadMemory(addr, &entry.base_addr, address_size))) > + return false; > + > + if (!(addr = ReadMemory(addr, &entry.path_addr, address_size))) > + return false; > + > + if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size))) > + return false; > + > + if (!(addr = ReadMemory(addr, &entry.next, address_size))) > + return false; > + > + if (!(addr = ReadMemory(addr, &entry.prev, address_size))) > + return false; > + > + entry.path = ReadStringFromMemory(entry.path_addr); > + > + return true; > +} > + > +void > +DYLDRendezvous::DumpToLog(LogSP log) const > +{ > + int state = GetState(); > + > + if (!log) > + return; > + > + log->PutCString("DYLDRendezvous:"); > + log->Printf(" Address: %lx", GetRendezvousAddress()); > + log->Printf(" Version: %d", GetVersion()); > + log->Printf(" Link : %lx", GetLinkMapAddress()); > + log->Printf(" Break : %lx", GetBreakAddress()); > + log->Printf(" LDBase : %lx", GetLDBase()); > + log->Printf(" State : %s", > + (state == eConsistent) ? "consistent" : > + (state == eAdd) ? "add" : > + (state == eDelete) ? "delete" : "unknown"); > + > + iterator I = begin(); > + iterator E = end(); > + > + if (I != E) > + log->PutCString("DYLDRendezvous SOEntries:"); > + > + for (int i = 1; I != E; ++I, ++i) > + { > + log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); > + log->Printf(" Base : %lx", I->base_addr); > + log->Printf(" Path : %lx", I->path_addr); > + log->Printf(" Dyn : %lx", I->dyn_addr); > + log->Printf(" Next : %lx", I->next); > + log->Printf(" Prev : %lx", I->prev); > + } > +} > diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h > new file mode 100644 > index 0000000..e8052ae > --- /dev/null > +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h > @@ -0,0 +1,227 @@ > +//===-- DYLDRendezvous.h ----------------------------------------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef liblldb_Rendezvous_H_ > +#define liblldb_Rendezvous_H_ > + > +// C Includes > +// C++ Includes > +#include > +#include > + > +// Other libraries and framework includes > +#include "lldb/lldb-defines.h" > +#include "lldb/lldb-types.h" > + > +namespace lldb_private { > +class Process; > +} > + > +/// @class DYLDRendezvous > +/// @brief Interface to the runtime linker. > +/// > +/// A structure is present in a processes memory space which is updated by the > +/// runtime liker each time a module is loaded or unloaded. This class provides > +/// an interface to this structure and maintains a consistent snapshot of the > +/// currently loaded modules. > +class DYLDRendezvous { > + > + // This structure is used to hold the contents of the debug rendezvous > + // information (struct r_debug) as found in the inferiors memory. Note that > + // the layout of this struct is not binary compatible, it is simply large > + // enough to hold the information on both 32 and 64 bit platforms. > + struct Rendezvous { > + uint64_t version; > + lldb::addr_t map_addr; > + lldb::addr_t brk; > + uint64_t state; > + lldb::addr_t ldbase; > + > + Rendezvous() > + : version(0), map_addr(0), brk(0), state(0), ldbase(0) { } > + }; > + > +public: > + DYLDRendezvous(lldb_private::Process *process); > + > + /// Update the internal snapshot of runtime linker rendezvous and recompute > + /// the currently loaded modules. > + /// > + /// This method should be called once one start up, then once each time the > + /// runtime linker enters the function given by GetBreakAddress(). > + /// > + /// @returns true on success and false on failure. > + /// > + /// @see GetBreakAddress(). > + bool > + Resolve(); > + > + /// @returns true if this rendezvous has been located in the inferiors > + /// address space and false otherwise. > + bool > + IsValid(); > + > + /// @returns the address of the rendezvous structure in the inferiors > + /// address space. > + lldb::addr_t > + GetRendezvousAddress() const { return m_rendezvous_addr; } > + > + /// @returns the version of the rendezvous protocol being used. > + int > + GetVersion() const { return m_current.version; } > + > + /// @returns address in the inferiors address space containing the linked > + /// list of shared object descriptors. > + lldb::addr_t > + GetLinkMapAddress() const { return m_current.map_addr; } > + > + /// A breakpoint should be set at this address and Resolve called on each > + /// hit. > + /// > + /// @returns the address of a function called by the runtime linker each > + /// time a module is loaded/unloaded, or about to be loaded/unloaded. > + /// > + /// @see Resolve() > + lldb::addr_t > + GetBreakAddress() const { return m_current.brk; } > + > + /// Returns the current state of the rendezvous structure. > + int > + GetState() const { return m_current.state; } > + > + /// @returns the base address of the runtime linker in the inferiors address > + /// space. > + lldb::addr_t > + GetLDBase() const { return m_current.ldbase; } > + > + /// @returns true if modules have been loaded into the inferior since the > + /// last call to Resolve(). > + bool > + ModulesDidLoad() const { return !m_added_soentries.empty(); } > + > + /// @returns true if modules have been unloaded from the inferior since the > + /// last call to Resolve(). > + bool > + ModulesDidUnload() const { return !m_removed_soentries.empty(); } > + > + void > + DumpToLog(lldb::LogSP log) const; > + > + /// @brief Constants describing the state of the rendezvous. > + /// > + /// @see GetState(). > + enum RendezvousState { > + eConsistent, > + eAdd, > + eDelete > + }; > + > + /// @brief Structure representing the shared objects currently loaded into > + /// the inferior process. > + /// > + /// This object is a rough analogue to the struct link_map object which > + /// actually lives in the inferiors memory. > + struct SOEntry { > + lldb::addr_t base_addr; ///< Base address of the loaded object. > + lldb::addr_t path_addr; ///< String naming the shared object. > + lldb::addr_t dyn_addr; ///< Dynamic section of shared object. > + lldb::addr_t next; ///< Address of next so_entry. > + lldb::addr_t prev; ///< Address of previous so_entry. > + std::string path; ///< File name of shared object. > + > + SOEntry() { clear(); } > + > + bool operator ==(const SOEntry &entry) { > + return this->path == entry.path; > + } > + > + void clear() { > + base_addr = 0; > + path_addr = 0; > + dyn_addr = 0; > + next = 0; > + prev = 0; > + path.clear(); > + } > + }; > + > +protected: > + typedef std::list SOEntryList; > + > +public: > + typedef SOEntryList::const_iterator iterator; > + > + /// Iterators over all currently loaded modules. > + iterator begin() const { return m_soentries.begin(); } > + iterator end() const { return m_soentries.end(); } > + > + /// Iterators over all modules loaded into the inferior since the last call > + /// to Resolve(). > + iterator loaded_begin() const { return m_added_soentries.begin(); } > + iterator loaded_end() const { return m_added_soentries.end(); } > + > + /// Iterators over all modules unloaded from the inferior since the last > + /// call to Resolve(). > + iterator unloaded_begin() const { return m_removed_soentries.begin(); } > + iterator unloaded_end() const { return m_removed_soentries.end(); } > + > +protected: > + lldb_private::Process *m_process; > + > + /// Location of the r_debug structure in the inferiors address space. > + lldb::addr_t m_rendezvous_addr; > + > + /// Current and previous snapshots of the rendezvous structure. > + Rendezvous m_current; > + Rendezvous m_previous; > + > + /// List of SOEntry objects corresponding to the current link map state. > + SOEntryList m_soentries; > + > + /// List of SOEntry's added to the link map since the last call to Resolve(). > + SOEntryList m_added_soentries; > + > + /// List of SOEntry's removed from the link map since the last call to > + /// Resolve(). > + SOEntryList m_removed_soentries; > + > + /// Reads @p size bytes from the inferiors address space starting at @p > + /// addr. > + /// > + /// @returns addr + size if the read was successful and false otherwise. > + lldb::addr_t > + ReadMemory(lldb::addr_t addr, void *dst, size_t size); > + > + /// Reads a null-terminated C string from the memory location starting at @p > + /// addr. > + std::string > + ReadStringFromMemory(lldb::addr_t addr); > + > + /// Reads an SOEntry starting at @p addr. > + bool > + ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); > + > + /// Updates the current set of SOEntries, the set of added entries, and the > + /// set of removed entries. > + bool > + UpdateSOEntries(); > + > + bool > + UpdateSOEntriesForAddition(); > + > + bool > + UpdateSOEntriesForDeletion(); > + > + /// Reads the current list of shared objects according to the link map > + /// supplied by the runtime linker. > + bool > + TakeSnapshot(SOEntryList &entry_list); > +}; > + > +#endif > diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp > new file mode 100644 > index 0000000..0802ff6 > --- /dev/null > +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp > @@ -0,0 +1,371 @@ > +//===-- DynamicLoaderLinux.h ------------------------------------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +// C Includes > +// C++ Includes > +#include > + > +// Other libraries and framework includes > +#include "lldb/Core/PluginManager.h" > +#include "lldb/Core/Log.h" > +#include "lldb/Target/Process.h" > +#include "lldb/Target/Target.h" > + > +#include "AuxVector.h" > +#include "DynamicLoaderLinuxDYLD.h" > + > +using namespace lldb; > +using namespace lldb_private; > + > +void > +DynamicLoaderLinuxDYLD::Initialize() > +{ > + PluginManager::RegisterPlugin(GetPluginNameStatic(), > + GetPluginDescriptionStatic(), > + CreateInstance); > +} > + > +void > +DynamicLoaderLinuxDYLD::Terminate() > +{ > +} > + > +const char * > +DynamicLoaderLinuxDYLD::GetPluginName() > +{ > + return "DynamicLoaderLinuxDYLD"; > +} > + > +const char * > +DynamicLoaderLinuxDYLD::GetShortPluginName() > +{ > + return "linux-dyld"; > +} > + > +const char * > +DynamicLoaderLinuxDYLD::GetPluginNameStatic() > +{ > + return "dynamic-loader.linux-dyld"; > +} > + > +const char * > +DynamicLoaderLinuxDYLD::GetPluginDescriptionStatic() > +{ > + return "Dynamic loader plug-in that watches for shared library " > + "loads/unloads in Linux processes."; > +} > + > +void > +DynamicLoaderLinuxDYLD::GetPluginCommandHelp(const char *command, Stream *strm) > +{ > +} > + > +uint32_t > +DynamicLoaderLinuxDYLD::GetPluginVersion() > +{ > + return 1; > +} > + > +DynamicLoader * > +DynamicLoaderLinuxDYLD::CreateInstance(Process *process) > +{ > + return new DynamicLoaderLinuxDYLD(process); > +} > + > +DynamicLoaderLinuxDYLD::DynamicLoaderLinuxDYLD(Process *process) > + : DynamicLoader(process), > + m_rendezvous(process), > + m_load_offset(LLDB_INVALID_ADDRESS), > + m_entry_point(LLDB_INVALID_ADDRESS), > + m_auxv(NULL) > +{ > +} > + > +DynamicLoaderLinuxDYLD::~DynamicLoaderLinuxDYLD() > +{ > +} > + > +void > +DynamicLoaderLinuxDYLD::DidAttach() > +{ > + ModuleSP executable; > + addr_t load_offset; > + > + m_auxv.reset(new AuxVector(m_process)); > + > + executable = m_process->GetTarget().GetExecutableModule(); > + load_offset = ComputeLoadOffset(); > + > + if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS) > + { > + ModuleList module_list; > + module_list.Append(executable); > + UpdateLoadedSections(executable, load_offset); > + m_process->GetTarget().ModulesDidLoad(module_list); > + } > +} > + > +void > +DynamicLoaderLinuxDYLD::DidLaunch() > +{ > + ModuleSP executable; > + addr_t load_offset; > + > + m_auxv.reset(new AuxVector(m_process)); > + > + executable = m_process->GetTarget().GetExecutableModule(); > + load_offset = ComputeLoadOffset(); > + > + if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS) > + { > + ModuleList module_list; > + module_list.Append(executable); > + UpdateLoadedSections(executable, load_offset); > + ProbeEntry(); > + m_process->GetTarget().ModulesDidLoad(module_list); > + } > +} > + > +Error > +DynamicLoaderLinuxDYLD::ExecutePluginCommand(Args &command, Stream *strm) > +{ > + return Error(); > +} > + > +Log * > +DynamicLoaderLinuxDYLD::EnablePluginLogging(Stream *strm, Args &command) > +{ > + return NULL; > +} > + > +Error > +DynamicLoaderLinuxDYLD::CanLoadImage() > +{ > + return Error(); > +} > + > +void > +DynamicLoaderLinuxDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr) > +{ > + ObjectFile *obj_file = module->GetObjectFile(); > + SectionList *sections = obj_file->GetSectionList(); > + SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); > + const size_t num_sections = sections->GetSize(); > + > + for (unsigned i = 0; i < num_sections; ++i) > + { > + Section *section = sections->GetSectionAtIndex(i).get(); > + lldb::addr_t new_load_addr = section->GetFileAddress() + base_addr; > + lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section); > + > + // If the file address of the section is zero then this is not an > + // allocatable/loadable section (property of ELF sh_addr). Skip it. > + if (new_load_addr == base_addr) > + continue; > + > + if (old_load_addr == LLDB_INVALID_ADDRESS || > + old_load_addr != new_load_addr) > + load_list.SetSectionLoadAddress(section, new_load_addr); > + } > +} > + > +void > +DynamicLoaderLinuxDYLD::ProbeEntry() > +{ > + Breakpoint *entry_break; > + addr_t entry; > + > + if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) > + return; > + > + entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get(); > + entry_break->SetCallback(EntryBreakpointHit, this, true); > +} > + > +// The runtime linker has run and initialized the rendezvous structure once the > +// process has hit its entry point. When we hit the corresponding breakpoint we > +// interrogate the rendezvous structure to get the load addresses of all > +// dependent modules for the process. Similarly, we can discover the runtime > +// linker function and setup a breakpoint to notify us of any dynamically loaded > +// modules (via dlopen). > +bool > +DynamicLoaderLinuxDYLD::EntryBreakpointHit(void *baton, > + StoppointCallbackContext *context, > + user_id_t break_id, > + user_id_t break_loc_id) > +{ > + DynamicLoaderLinuxDYLD* dyld_instance; > + > + dyld_instance = static_cast(baton); > + dyld_instance->LoadAllCurrentModules(); > + dyld_instance->SetRendezvousBreakpoint(); > + return false; // Continue running. > +} > + > +void > +DynamicLoaderLinuxDYLD::SetRendezvousBreakpoint() > +{ > + Breakpoint *dyld_break; > + addr_t break_addr; > + > + break_addr = m_rendezvous.GetBreakAddress(); > + dyld_break = m_process->GetTarget().CreateBreakpoint(break_addr, true).get(); > + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); > +} > + > +bool > +DynamicLoaderLinuxDYLD::RendezvousBreakpointHit(void *baton, > + StoppointCallbackContext *context, > + user_id_t break_id, > + user_id_t break_loc_id) > +{ > + DynamicLoaderLinuxDYLD* dyld_instance; > + > + dyld_instance = static_cast(baton); > + dyld_instance->RefreshModules(); > + > + // Return true to stop the target, false to just let the target run. > + return dyld_instance->GetStopWhenImagesChange(); > +} > + > +void > +DynamicLoaderLinuxDYLD::RefreshModules() > +{ > + if (!m_rendezvous.Resolve()) > + return; > + > + DYLDRendezvous::iterator I; > + DYLDRendezvous::iterator E; > + > + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); > + > + if (m_rendezvous.ModulesDidLoad()) > + { > + ModuleList new_modules; > + > + E = m_rendezvous.loaded_end(); > + for (I = m_rendezvous.loaded_begin(); I != E; ++I) > + { > + FileSpec file(I->path.c_str(), true); > + ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); > + if (!module_sp.empty()) > + new_modules.Append(module_sp); > + } > + m_process->GetTarget().ModulesDidLoad(new_modules); > + } > + > + if (m_rendezvous.ModulesDidUnload()) > + { > + ModuleList old_modules; > + > + E = m_rendezvous.unloaded_end(); > + for (I = m_rendezvous.unloaded_begin(); I != E; ++I) > + { > + FileSpec file(I->path.c_str(), true); > + ModuleSP module_sp = loaded_modules.FindFirstModuleForFileSpec(file); > + if (!module_sp.empty()) > + old_modules.Append(module_sp); > + } > + m_process->GetTarget().ModulesDidUnload(old_modules); > + } > +} > + > +ThreadPlanSP > +DynamicLoaderLinuxDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop_others) > +{ > + LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); > + ThreadPlanSP thread_plan_sp; > + > + if (log) > + log->PutCString("DynamicLoaderLinuxDYLD: " > + "GetStepThroughTrampolinePlan not implemented\n"); > + > + return thread_plan_sp; > +} > + > +void > +DynamicLoaderLinuxDYLD::LoadAllCurrentModules() > +{ > + DYLDRendezvous::iterator I; > + DYLDRendezvous::iterator E; > + ModuleList module_list; > + > + if (!m_rendezvous.Resolve()) > + return; > + > + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) > + { > + FileSpec file(I->path.c_str(), false); > + ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); > + if (!module_sp.empty()) > + module_list.Append(module_sp); > + } > + > + m_process->GetTarget().ModulesDidLoad(module_list); > +} > + > +ModuleSP > +DynamicLoaderLinuxDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr) > +{ > + Target &target = m_process->GetTarget(); > + ModuleList &modules = target.GetImages(); > + ModuleSP module_sp; > + > + if ((module_sp = modules.FindFirstModuleForFileSpec(file))) > + { > + UpdateLoadedSections(module_sp, base_addr); > + } > + else if ((module_sp = target.GetSharedModule(file, target.GetArchitecture()))) > + { > + UpdateLoadedSections(module_sp, base_addr); > + modules.Append(module_sp); > + } > + > + return module_sp; > +} > + > +addr_t > +DynamicLoaderLinuxDYLD::ComputeLoadOffset() > +{ > + addr_t virt_entry; > + > + if (m_load_offset != LLDB_INVALID_ADDRESS) > + return m_load_offset; > + > + if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) > + return LLDB_INVALID_ADDRESS; > + > + ModuleSP module = m_process->GetTarget().GetExecutableModule(); > + ObjectFile *exe = module->GetObjectFile(); > + Address file_entry = exe->GetEntryPoint(); > + > + if (!file_entry.IsValid()) > + return LLDB_INVALID_ADDRESS; > + > + m_load_offset = virt_entry - file_entry.GetFileAddress(); > + return m_load_offset; > +} > + > +addr_t > +DynamicLoaderLinuxDYLD::GetEntryPoint() > +{ > + if (m_entry_point != LLDB_INVALID_ADDRESS) > + return m_entry_point; > + > + if (m_auxv.get() == NULL) > + return LLDB_INVALID_ADDRESS; > + > + AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY); > + > + if (I == m_auxv->end()) > + return LLDB_INVALID_ADDRESS; > + > + m_entry_point = static_cast(I->value); > + return m_entry_point; > +} > diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h > new file mode 100644 > index 0000000..bc537ce > --- /dev/null > +++ b/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h > @@ -0,0 +1,165 @@ > +//===-- DynamicLoaderLinux.h ------------------------------------*- C++ -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > +//===----------------------------------------------------------------------===// > + > +#ifndef liblldb_DynamicLoaderLinux_H_ > +#define liblldb_DynamicLoaderLinux_H_ > + > +// C Includes > +// C++ Includes > +// Other libraries and framework includes > +#include "lldb/Breakpoint/StoppointCallbackContext.h" > +#include "lldb/Target/DynamicLoader.h" > + > +#include "DYLDRendezvous.h" > + > +class AuxVector; > + > +class DynamicLoaderLinuxDYLD : public lldb_private::DynamicLoader > +{ > +public: > + > + static void > + Initialize(); > + > + static void > + Terminate(); > + > + static const char * > + GetPluginNameStatic(); > + > + static const char * > + GetPluginDescriptionStatic(); > + > + static lldb_private::DynamicLoader * > + CreateInstance(lldb_private::Process *process); > + > + DynamicLoaderLinuxDYLD(lldb_private::Process *process); > + > + virtual > + ~DynamicLoaderLinuxDYLD(); > + > + //------------------------------------------------------------------ > + // DynamicLoader protocol > + //------------------------------------------------------------------ > + > + virtual void > + DidAttach(); > + > + virtual void > + DidLaunch(); > + > + virtual lldb::ThreadPlanSP > + GetStepThroughTrampolinePlan(lldb_private::Thread &thread, > + bool stop_others); > + > + virtual lldb_private::Error > + CanLoadImage(); > + > + //------------------------------------------------------------------ > + // PluginInterface protocol > + //------------------------------------------------------------------ > + virtual const char * > + GetPluginName(); > + > + virtual const char * > + GetShortPluginName(); > + > + virtual uint32_t > + GetPluginVersion(); > + > + virtual void > + GetPluginCommandHelp(const char *command, lldb_private::Stream *strm); > + > + virtual lldb_private::Error > + ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm); > + > + virtual lldb_private::Log * > + EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command); > + > +protected: > + /// Runtime linker rendezvous structure. > + DYLDRendezvous m_rendezvous; > + > + /// Virtual load address of the inferior process. > + lldb::addr_t m_load_offset; > + > + /// Virtual entry address of the inferior process. > + lldb::addr_t m_entry_point; > + > + /// Auxiliary vector of the inferior process. > + std::auto_ptr m_auxv; > + > + /// Enables a breakpoint on a function called by the runtime > + /// linker each time a module is loaded or unloaded. > + void > + SetRendezvousBreakpoint(); > + > + /// Callback routine which updates the current list of loaded modules based > + /// on the information supplied by the runtime linker. > + static bool > + RendezvousBreakpointHit(void *baton, > + lldb_private::StoppointCallbackContext *context, > + lldb::user_id_t break_id, > + lldb::user_id_t break_loc_id); > + > + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set > + /// of loaded modules. > + void > + RefreshModules(); > + > + /// Updates the load address of every allocatable section in @p module. > + /// > + /// @param module The module to traverse. > + /// > + /// @param base_addr The virtual base address @p module is loaded at. > + void > + UpdateLoadedSections(lldb::ModuleSP module, > + lldb::addr_t base_addr = 0); > + > + /// Locates or creates a module given by @p file and updates/loads the > + /// resulting module at the virtual base address @p base_addr. > + lldb::ModuleSP > + LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t base_addr); > + > + /// Resolves the entry point for the current inferior process and sets a > + /// breakpoint at that address. > + void > + ProbeEntry(); > + > + /// Callback routine invoked when we hit the breakpoint on process entry. > + /// > + /// This routine is responsible for resolving the load addresses of all > + /// dependent modules required by the inferior and setting up the rendezvous > + /// breakpoint. > + static bool > + EntryBreakpointHit(void *baton, > + lldb_private::StoppointCallbackContext *context, > + lldb::user_id_t break_id, > + lldb::user_id_t break_loc_id); > + > + /// Helper for the entry breakpoint callback. Resolves the load addresses > + /// of all dependent modules. > + void > + LoadAllCurrentModules(); > + > + /// Computes a value for m_load_offset returning the computed address on > + /// success and LLDB_INVALID_ADDRESS on failure. > + lldb::addr_t > + ComputeLoadOffset(); > + > + /// Computes a value for m_entry_point returning the computed address on > + /// success and LLDB_INVALID_ADDRESS on failure. > + lldb::addr_t > + GetEntryPoint(); > + > +private: > + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderLinuxDYLD); > +}; > + > +#endif // liblldb_DynamicLoaderLinuxDYLD_H_ > diff --git a/source/Plugins/DynamicLoader/Linux-DYLD/Makefile b/source/Plugins/DynamicLoader/Linux-DYLD/Makefile > new file mode 100644 > index 0000000..94025dd > --- /dev/null > +++ b/source/Plugins/DynamicLoader/Linux-DYLD/Makefile > @@ -0,0 +1,14 @@ > +##===- source/Plugins/DynamicLoader/Linux-DYLD/Makefile ----*- Makefile -*-===## > +# > +# The LLVM Compiler Infrastructure > +# > +# This file is distributed under the University of Illinois Open Source > +# License. See LICENSE.TXT for details. > +# > +##===----------------------------------------------------------------------===## > + > +LLDB_LEVEL := ../../../.. > +LIBRARYNAME := lldbPluginDynamicLoaderLinux > +BUILD_ARCHIVE = 1 > + > +include $(LLDB_LEVEL)/Makefile > diff --git a/source/Plugins/Makefile b/source/Plugins/Makefile > index 14eed8a..a3d644f 100644 > --- a/source/Plugins/Makefile > +++ b/source/Plugins/Makefile > @@ -23,7 +23,7 @@ DIRS += DynamicLoader/MacOSX-DYLD ObjectContainer/Universal-Mach-O \ > endif > > ifeq ($(HOST_OS),Linux) > -DIRS += Process/Linux > +DIRS += Process/Linux DynamicLoader/Linux-DYLD > endif > > include $(LLDB_LEVEL)/Makefile > diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp > index 00bdda5..d7fe1da 100644 > --- a/source/Plugins/Process/Linux/ProcessLinux.cpp > +++ b/source/Plugins/Process/Linux/ProcessLinux.cpp > @@ -13,6 +13,7 @@ > #include "lldb/Core/PluginManager.h" > #include "lldb/Host/Host.h" > #include "lldb/Symbol/ObjectFile.h" > +#include "lldb/Target/DynamicLoader.h" > #include "lldb/Target/Target.h" > > #include "ProcessLinux.h" > @@ -102,6 +103,19 @@ ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid) > } > > Error > +ProcessLinux::WillLaunch(Module* module) > +{ > + Error error; > + > + m_dyld_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.linux-dyld")); > + if (m_dyld_ap.get() == NULL) > + error.SetErrorString("unable to find the dynamic loader named " > + "'dynamic-loader.linux-dyld'"); > + > + return error; > +} > + > +Error > ProcessLinux::DoLaunch(Module *module, > char const *argv[], > char const *envp[], > @@ -128,6 +142,13 @@ ProcessLinux::DoLaunch(Module *module, > return error; > } > > +void > +ProcessLinux::DidLaunch() > +{ > + if (m_dyld_ap.get() != NULL) > + m_dyld_ap->DidLaunch(); > +} > + > Error > ProcessLinux::DoResume() > { > @@ -371,6 +392,12 @@ ProcessLinux::GetByteOrder() const > return m_byte_order; > } > > +DynamicLoader * > +ProcessLinux::GetDynamicLoader() > +{ > + return m_dyld_ap.get(); > +} > + > //------------------------------------------------------------------------------ > // ProcessInterface protocol. > > diff --git a/source/Plugins/Process/Linux/ProcessLinux.h b/source/Plugins/Process/Linux/ProcessLinux.h > index 3e23a7a..fbf14df 100644 > --- a/source/Plugins/Process/Linux/ProcessLinux.h > +++ b/source/Plugins/Process/Linux/ProcessLinux.h > @@ -60,6 +60,9 @@ public: > CanDebug(lldb_private::Target &target); > > virtual lldb_private::Error > + WillLaunch(lldb_private::Module *module); > + > + virtual lldb_private::Error > DoAttachToProcessWithID(lldb::pid_t pid); > > virtual lldb_private::Error > @@ -71,6 +74,9 @@ public: > const char *stdout_path, > const char *stderr_path); > > + virtual void > + DidLaunch(); > + > virtual lldb_private::Error > DoResume(); > > @@ -131,6 +137,9 @@ public: > virtual lldb::addr_t > GetImageInfoAddress(); > > + virtual lldb_private::DynamicLoader * > + GetDynamicLoader(); > + > //------------------------------------------------------------------ > // PluginInterface protocol > //------------------------------------------------------------------ > @@ -176,6 +185,9 @@ private: > lldb_private::Mutex m_message_mutex; > std::queue m_message_queue; > > + /// Dynamic loader plugin associated with this process. > + std::auto_ptr m_dyld_ap; > + > /// Updates the loaded sections provided by the executable. > /// > /// FIXME: It would probably be better to delegate this task to the > diff --git a/source/lldb.cpp b/source/lldb.cpp > index 05c7f4b..ac281a2 100644 > --- a/source/lldb.cpp > +++ b/source/lldb.cpp > @@ -44,6 +44,7 @@ > > #ifdef __linux__ > #include "Plugins/Process/Linux/ProcessLinux.h" > +#include "Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h" > #endif > > using namespace lldb; > @@ -94,6 +95,7 @@ lldb_private::Initialize () > #endif > #ifdef __linux__ > ProcessLinux::Initialize(); > + DynamicLoaderLinuxDYLD::Initialize(); > #endif > } > } > @@ -137,6 +139,7 @@ lldb_private::Terminate () > > #ifdef __linux__ > ProcessLinux::Terminate(); > + DynamicLoaderLinuxDYLD::Terminate(); > #endif > > Log::Terminate(); > -- > 1.7.3.5 > _______________________________________________ > lldb-commits mailing list > lldb-commits at cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits From wilsons at start.ca Sun Jan 16 10:56:16 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sun, 16 Jan 2011 16:56:16 -0000 Subject: [Lldb-commits] [lldb] r123583 - in /lldb/trunk/source/Plugins/Process/Linux: LinuxThread.cpp LinuxThread.h Message-ID: <20110116165616.85F3E2A6C12C@llvm.org> Author: wilsons Date: Sun Jan 16 10:56:16 2011 New Revision: 123583 URL: http://llvm.org/viewvc/llvm-project?rev=123583&view=rev Log: Make a mandatory call to DestroyThread() in ~LinuxThread(). Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp?rev=123583&r1=123582&r2=123583&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.cpp Sun Jan 16 10:56:16 2011 @@ -31,6 +31,11 @@ { } +LinuxThread::~LinuxThread() +{ + DestroyThread(); +} + ProcessMonitor & LinuxThread::GetMonitor() { Modified: lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h?rev=123583&r1=123582&r2=123583&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h (original) +++ lldb/trunk/source/Plugins/Process/Linux/LinuxThread.h Sun Jan 16 10:56:16 2011 @@ -29,6 +29,8 @@ public: LinuxThread(lldb_private::Process &process, lldb::tid_t tid); + virtual ~LinuxThread(); + void RefreshStateAfterStop(); From wilsons at start.ca Sun Jan 16 13:45:39 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sun, 16 Jan 2011 19:45:39 -0000 Subject: [Lldb-commits] [lldb] r123592 - in /lldb/trunk: lib/ source/ source/Plugins/ source/Plugins/DynamicLoader/Linux-DYLD/ source/Plugins/Process/Linux/ Message-ID: <20110116194540.1D4872A6C12C@llvm.org> Author: wilsons Date: Sun Jan 16 13:45:39 2011 New Revision: 123592 URL: http://llvm.org/viewvc/llvm-project?rev=123592&view=rev Log: Initial support for a DynamicLoader plugin on Linux. This patch is enough to have shared objects recognized by LLDB. We can handle position independent executables. We can handle dynamically loaded modules brought in via dlopen. The DYLDRendezvous class provides an interface to a structure present in the address space of ELF-based processes. This structure provides the address of a function which is called by the linker each time a shared object is loaded and unloaded (thus a breakpoint at that address will let LLDB intercept such events), a list of entries describing the currently loaded shared objects, plus a few other things. On Linux, processes are brought up with an auxiliary vector on the stack. One element in this vector contains the (possibly dynamic) entry address of the process. One does not need to walk the stack to find this information as it is also available under /proc//auxv. The new AuxVector class provides a convenient read-only view of this auxiliary vector information. We use the dynamic entry address and the address as specified in the object file to compute the actual load address of the inferior image. This strategy works for both normal executables and PIE's. Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/Makefile Modified: lldb/trunk/lib/Makefile lldb/trunk/source/Plugins/Makefile lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h lldb/trunk/source/lldb.cpp Modified: lldb/trunk/lib/Makefile URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lib/Makefile?rev=123592&r1=123591&r2=123592&view=diff ============================================================================== --- lldb/trunk/lib/Makefile (original) +++ lldb/trunk/lib/Makefile Sun Jan 16 13:45:39 2011 @@ -67,7 +67,8 @@ endif ifeq ($(HOST_OS),Linux) - USEDLIBS += lldbPluginProcessLinux.a + USEDLIBS += lldbPluginProcessLinux.a \ + lldbPluginDynamicLoaderLinux.a endif include $(LEVEL)/Makefile.common Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp?rev=123592&view=auto ============================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp (added) +++ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.cpp Sun Jan 16 13:45:39 2011 @@ -0,0 +1,191 @@ +//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include +#include +#include + +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" + +#include "AuxVector.h" + +using namespace lldb; +using namespace lldb_private; + +static bool +GetMaxU64(DataExtractor &data, + uint32_t *offset, uint64_t *value, unsigned int byte_size) +{ + uint32_t saved_offset = *offset; + *value = data.GetMaxU64(offset, byte_size); + return *offset != saved_offset; +} + +static bool +ParseAuxvEntry(DataExtractor &data, AuxVector::Entry &entry, + uint32_t *offset, unsigned int byte_size) +{ + if (!GetMaxU64(data, offset, &entry.type, byte_size)) + return false; + + if (!GetMaxU64(data, offset, &entry.value, byte_size)) + return false; + + return true; +} + +DataBufferSP +AuxVector::GetAuxvData() +{ + static const size_t path_size = 128; + static char path[path_size]; + DataBufferSP buf_sp; + int fd; + + // Ideally, we would simply create a FileSpec and call ReadFileContents. + // However, files in procfs have zero size (since they are, in general, + // dynamically generated by the kernel) which is incompatible with the + // current ReadFileContents implementation. Therefore we simply stream the + // data into a DataBuffer ourselves. + if (snprintf(path, path_size, "/proc/%d/auxv", m_process->GetID()) < 0) + return buf_sp; + + if ((fd = open(path, O_RDONLY, 0)) < 0) + return buf_sp; + + size_t bytes_read = 0; + std::auto_ptr buf_ap(new DataBufferHeap(1024, 0)); + for (;;) + { + size_t avail = buf_ap->GetByteSize() - bytes_read; + ssize_t status = read(fd, buf_ap->GetBytes() + bytes_read, avail); + + if (status < 0) + break; + + bytes_read += status; + + if (status == 0) + { + buf_ap->SetByteSize(bytes_read); + buf_sp.reset(buf_ap.release()); + break; + } + + if (avail - status == 0) + buf_ap->SetByteSize(2 * buf_ap->GetByteSize()); + } + + return buf_sp; +} + +void +AuxVector::ParseAuxv(DataExtractor &data) +{ + const unsigned int byte_size = m_process->GetAddressByteSize(); + uint32_t offset = 0; + + for (;;) + { + Entry entry; + + if (!ParseAuxvEntry(data, entry, &offset, byte_size)) + break; + + if (entry.type == AT_NULL) + break; + + if (entry.type == AT_IGNORE) + continue; + + m_auxv.push_back(entry); + } +} + +AuxVector::AuxVector(Process *process) + : m_process(process) +{ + DataExtractor data; + LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + + data.SetData(GetAuxvData()); + data.SetByteOrder(m_process->GetByteOrder()); + data.SetAddressByteSize(m_process->GetAddressByteSize()); + + ParseAuxv(data); + + if (log) + DumpToLog(log); +} + +AuxVector::iterator +AuxVector::FindEntry(EntryType type) const +{ + for (iterator I = begin(); I != end(); ++I) + { + if (I->type == static_cast(type)) + return I; + } + + return end(); +} + +void +AuxVector::DumpToLog(LogSP log) const +{ + if (!log) + return; + + log->PutCString("AuxVector: "); + for (iterator I = begin(); I != end(); ++I) + { + log->Printf(" %s [%d]: %lx", GetEntryName(*I), I->type, I->value); + } +} + +const char * +AuxVector::GetEntryName(EntryType type) +{ + const char *name; + +#define ENTRY_NAME(_type) _type: name = #_type + switch (type) + { + default: + name = "unkown"; + break; + + case ENTRY_NAME(AT_NULL); break; + case ENTRY_NAME(AT_IGNORE); break; + case ENTRY_NAME(AT_EXECFD); break; + case ENTRY_NAME(AT_PHDR); break; + case ENTRY_NAME(AT_PHENT); break; + case ENTRY_NAME(AT_PHNUM); break; + case ENTRY_NAME(AT_PAGESZ); break; + case ENTRY_NAME(AT_BASE); break; + case ENTRY_NAME(AT_FLAGS); break; + case ENTRY_NAME(AT_ENTRY); break; + case ENTRY_NAME(AT_NOTELF); break; + case ENTRY_NAME(AT_UID); break; + case ENTRY_NAME(AT_EUID); break; + case ENTRY_NAME(AT_GID); break; + case ENTRY_NAME(AT_EGID); break; + case ENTRY_NAME(AT_CLKTCK); break; + } +#undef ENTRY_NAME + + return name; +} + Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h?rev=123592&view=auto ============================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h (added) +++ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/AuxVector.h Sun Jan 16 13:45:39 2011 @@ -0,0 +1,97 @@ +//===-- AuxVector.h ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_AuxVector_H_ +#define liblldb_AuxVector_H_ + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +#include "lldb/lldb-forward-rtti.h" + +namespace lldb_private { +class DataExtractor; +} + +/// @class AuxVector +/// @brief Represents a processes auxiliary vector. +/// +/// When a process is loaded on Linux a vector of values is placed onto the +/// stack communicating operating system specific information. On construction +/// this class locates and parses this information and provides a simple +/// read-only interface to the entries found. +class AuxVector { + +public: + AuxVector(lldb_private::Process *process); + + struct Entry { + uint64_t type; + uint64_t value; + + Entry() : type(0), value(0) { } + }; + + /// Constants describing the type of entry. + enum EntryType { + AT_NULL = 0, ///< End of auxv. + AT_IGNORE = 1, ///< Ignore entry. + AT_EXECFD = 2, ///< File descriptor of program. + AT_PHDR = 3, ///< Program headers. + AT_PHENT = 4, ///< Size of program header. + AT_PHNUM = 5, ///< Number of program headers. + AT_PAGESZ = 6, ///< Page size. + AT_BASE = 7, ///< Interpreter base address. + AT_FLAGS = 8, ///< Flags. + AT_ENTRY = 9, ///< Program entry point. + AT_NOTELF = 10, ///< Set if program is not an ELF. + AT_UID = 11, ///< UID. + AT_EUID = 12, ///< Effective UID. + AT_GID = 13, ///< GID. + AT_EGID = 14, ///< Effective GID. + AT_CLKTCK = 17 ///< Clock frequency (e.g. times(2)). + }; + +private: + typedef std::vector EntryVector; + +public: + typedef EntryVector::const_iterator iterator; + + iterator begin() const { return m_auxv.begin(); } + iterator end() const { return m_auxv.end(); } + + iterator + FindEntry(EntryType type) const; + + static const char * + GetEntryName(const Entry &entry) { + return GetEntryName(static_cast(entry.type)); + } + + static const char * + GetEntryName(EntryType type); + + void + DumpToLog(lldb::LogSP log) const; + +private: + lldb_private::Process *m_process; + EntryVector m_auxv; + + lldb::DataBufferSP + GetAuxvData(); + + void + ParseAuxv(lldb_private::DataExtractor &data); +}; + +#endif Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp?rev=123592&view=auto ============================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp (added) +++ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.cpp Sun Jan 16 13:45:39 2011 @@ -0,0 +1,315 @@ +//===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "DYLDRendezvous.h" + +using namespace lldb; +using namespace lldb_private; + +/// Locates the address of the rendezvous structure. Returns the address on +/// success and LLDB_INVALID_ADDRESS on failure. +static addr_t +ResolveRendezvousAddress(Process *process) +{ + addr_t info_location; + addr_t info_addr; + Error error; + size_t size; + + info_location = process->GetImageInfoAddress(); + + if (info_location == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + info_addr = 0; + size = process->DoReadMemory(info_location, &info_addr, + process->GetAddressByteSize(), error); + if (size != process->GetAddressByteSize() || error.Fail()) + return LLDB_INVALID_ADDRESS; + + if (info_addr == 0) + return LLDB_INVALID_ADDRESS; + + return info_addr; +} + +DYLDRendezvous::DYLDRendezvous(Process *process) + : m_process(process), + m_rendezvous_addr(LLDB_INVALID_ADDRESS), + m_current(), + m_previous(), + m_soentries(), + m_added_soentries(), + m_removed_soentries() +{ +} + +bool +DYLDRendezvous::Resolve() +{ + const size_t word_size = 4; + Rendezvous info; + size_t address_size; + size_t padding; + addr_t info_addr; + addr_t cursor; + + address_size = m_process->GetAddressByteSize(); + padding = address_size - word_size; + + if (m_rendezvous_addr == LLDB_INVALID_ADDRESS) + cursor = info_addr = ResolveRendezvousAddress(m_process); + else + cursor = info_addr = m_rendezvous_addr; + + if (cursor == LLDB_INVALID_ADDRESS) + return false; + + if (!(cursor = ReadMemory(cursor, &info.version, word_size))) + return false; + + if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size))) + return false; + + if (!(cursor = ReadMemory(cursor, &info.brk, address_size))) + return false; + + if (!(cursor = ReadMemory(cursor, &info.state, word_size))) + return false; + + if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size))) + return false; + + // The rendezvous was successfully read. Update our internal state. + m_rendezvous_addr = info_addr; + m_previous = m_current; + m_current = info; + + return UpdateSOEntries(); +} + +bool +DYLDRendezvous::IsValid() +{ + return m_rendezvous_addr != LLDB_INVALID_ADDRESS; +} + +bool +DYLDRendezvous::UpdateSOEntries() +{ + SOEntry entry; + + if (m_current.map_addr == 0) + return false; + + // If we are about to add or remove a shared object clear out the current + // state and take a snapshot of the currently loaded images. + if (m_current.state == eAdd || m_current.state == eDelete) + { + assert(m_previous.state == eConsistent); + m_soentries.clear(); + m_added_soentries.clear(); + m_removed_soentries.clear(); + return TakeSnapshot(m_soentries); + } + + // Otherwise check the previous state to determine what to expect and update + // accordingly. + if (m_previous.state == eAdd) + return UpdateSOEntriesForAddition(); + else if (m_previous.state == eDelete) + return UpdateSOEntriesForDeletion(); + + return false; +} + +bool +DYLDRendezvous::UpdateSOEntriesForAddition() +{ + SOEntry entry; + iterator pos; + + assert(m_previous.state == eAdd); + + if (m_current.map_addr == 0) + return false; + + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) + { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; + + if (entry.path.empty()) + continue; + + pos = std::find(m_soentries.begin(), m_soentries.end(), entry); + if (pos == m_soentries.end()) + { + m_soentries.push_back(entry); + m_added_soentries.push_back(entry); + } + } + + return true; +} + +bool +DYLDRendezvous::UpdateSOEntriesForDeletion() +{ + SOEntryList entry_list; + iterator pos; + + assert(m_previous.state == eDelete); + + if (!TakeSnapshot(entry_list)) + return false; + + for (iterator I = begin(); I != end(); ++I) + { + pos = std::find(entry_list.begin(), entry_list.end(), *I); + if (pos == entry_list.end()) + m_removed_soentries.push_back(*I); + } + + m_soentries = entry_list; + return true; +} + +bool +DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list) +{ + SOEntry entry; + + if (m_current.map_addr == 0) + return false; + + for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next) + { + if (!ReadSOEntryFromMemory(cursor, entry)) + return false; + + if (entry.path.empty()) + continue; + + entry_list.push_back(entry); + } + + return true; +} + +addr_t +DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size) +{ + size_t bytes_read; + Error error; + + bytes_read = m_process->DoReadMemory(addr, dst, size, error); + if (bytes_read != size || error.Fail()) + return 0; + + return addr + bytes_read; +} + +std::string +DYLDRendezvous::ReadStringFromMemory(addr_t addr) +{ + std::string str; + Error error; + size_t size; + char c; + + if (addr == LLDB_INVALID_ADDRESS) + return std::string(); + + for (;;) { + size = m_process->DoReadMemory(addr, &c, 1, error); + if (size != 1 || error.Fail()) + return std::string(); + if (c == 0) + break; + else { + str.push_back(c); + addr++; + } + } + + return str; +} + +bool +DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) +{ + size_t address_size = m_process->GetAddressByteSize(); + + entry.clear(); + + if (!(addr = ReadMemory(addr, &entry.base_addr, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.path_addr, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.next, address_size))) + return false; + + if (!(addr = ReadMemory(addr, &entry.prev, address_size))) + return false; + + entry.path = ReadStringFromMemory(entry.path_addr); + + return true; +} + +void +DYLDRendezvous::DumpToLog(LogSP log) const +{ + int state = GetState(); + + if (!log) + return; + + log->PutCString("DYLDRendezvous:"); + log->Printf(" Address: %lx", GetRendezvousAddress()); + log->Printf(" Version: %d", GetVersion()); + log->Printf(" Link : %lx", GetLinkMapAddress()); + log->Printf(" Break : %lx", GetBreakAddress()); + log->Printf(" LDBase : %lx", GetLDBase()); + log->Printf(" State : %s", + (state == eConsistent) ? "consistent" : + (state == eAdd) ? "add" : + (state == eDelete) ? "delete" : "unknown"); + + iterator I = begin(); + iterator E = end(); + + if (I != E) + log->PutCString("DYLDRendezvous SOEntries:"); + + for (int i = 1; I != E; ++I, ++i) + { + log->Printf("\n SOEntry [%d] %s", i, I->path.c_str()); + log->Printf(" Base : %lx", I->base_addr); + log->Printf(" Path : %lx", I->path_addr); + log->Printf(" Dyn : %lx", I->dyn_addr); + log->Printf(" Next : %lx", I->next); + log->Printf(" Prev : %lx", I->prev); + } +} Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h?rev=123592&view=auto ============================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h (added) +++ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DYLDRendezvous.h Sun Jan 16 13:45:39 2011 @@ -0,0 +1,227 @@ +//===-- DYLDRendezvous.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Rendezvous_H_ +#define liblldb_Rendezvous_H_ + +// C Includes +// C++ Includes +#include +#include + +// Other libraries and framework includes +#include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" + +namespace lldb_private { +class Process; +} + +/// @class DYLDRendezvous +/// @brief Interface to the runtime linker. +/// +/// A structure is present in a processes memory space which is updated by the +/// runtime liker each time a module is loaded or unloaded. This class provides +/// an interface to this structure and maintains a consistent snapshot of the +/// currently loaded modules. +class DYLDRendezvous { + + // This structure is used to hold the contents of the debug rendezvous + // information (struct r_debug) as found in the inferiors memory. Note that + // the layout of this struct is not binary compatible, it is simply large + // enough to hold the information on both 32 and 64 bit platforms. + struct Rendezvous { + uint64_t version; + lldb::addr_t map_addr; + lldb::addr_t brk; + uint64_t state; + lldb::addr_t ldbase; + + Rendezvous() + : version(0), map_addr(0), brk(0), state(0), ldbase(0) { } + }; + +public: + DYLDRendezvous(lldb_private::Process *process); + + /// Update the internal snapshot of runtime linker rendezvous and recompute + /// the currently loaded modules. + /// + /// This method should be called once one start up, then once each time the + /// runtime linker enters the function given by GetBreakAddress(). + /// + /// @returns true on success and false on failure. + /// + /// @see GetBreakAddress(). + bool + Resolve(); + + /// @returns true if this rendezvous has been located in the inferiors + /// address space and false otherwise. + bool + IsValid(); + + /// @returns the address of the rendezvous structure in the inferiors + /// address space. + lldb::addr_t + GetRendezvousAddress() const { return m_rendezvous_addr; } + + /// @returns the version of the rendezvous protocol being used. + int + GetVersion() const { return m_current.version; } + + /// @returns address in the inferiors address space containing the linked + /// list of shared object descriptors. + lldb::addr_t + GetLinkMapAddress() const { return m_current.map_addr; } + + /// A breakpoint should be set at this address and Resolve called on each + /// hit. + /// + /// @returns the address of a function called by the runtime linker each + /// time a module is loaded/unloaded, or about to be loaded/unloaded. + /// + /// @see Resolve() + lldb::addr_t + GetBreakAddress() const { return m_current.brk; } + + /// Returns the current state of the rendezvous structure. + int + GetState() const { return m_current.state; } + + /// @returns the base address of the runtime linker in the inferiors address + /// space. + lldb::addr_t + GetLDBase() const { return m_current.ldbase; } + + /// @returns true if modules have been loaded into the inferior since the + /// last call to Resolve(). + bool + ModulesDidLoad() const { return !m_added_soentries.empty(); } + + /// @returns true if modules have been unloaded from the inferior since the + /// last call to Resolve(). + bool + ModulesDidUnload() const { return !m_removed_soentries.empty(); } + + void + DumpToLog(lldb::LogSP log) const; + + /// @brief Constants describing the state of the rendezvous. + /// + /// @see GetState(). + enum RendezvousState { + eConsistent, + eAdd, + eDelete + }; + + /// @brief Structure representing the shared objects currently loaded into + /// the inferior process. + /// + /// This object is a rough analogue to the struct link_map object which + /// actually lives in the inferiors memory. + struct SOEntry { + lldb::addr_t base_addr; ///< Base address of the loaded object. + lldb::addr_t path_addr; ///< String naming the shared object. + lldb::addr_t dyn_addr; ///< Dynamic section of shared object. + lldb::addr_t next; ///< Address of next so_entry. + lldb::addr_t prev; ///< Address of previous so_entry. + std::string path; ///< File name of shared object. + + SOEntry() { clear(); } + + bool operator ==(const SOEntry &entry) { + return this->path == entry.path; + } + + void clear() { + base_addr = 0; + path_addr = 0; + dyn_addr = 0; + next = 0; + prev = 0; + path.clear(); + } + }; + +protected: + typedef std::list SOEntryList; + +public: + typedef SOEntryList::const_iterator iterator; + + /// Iterators over all currently loaded modules. + iterator begin() const { return m_soentries.begin(); } + iterator end() const { return m_soentries.end(); } + + /// Iterators over all modules loaded into the inferior since the last call + /// to Resolve(). + iterator loaded_begin() const { return m_added_soentries.begin(); } + iterator loaded_end() const { return m_added_soentries.end(); } + + /// Iterators over all modules unloaded from the inferior since the last + /// call to Resolve(). + iterator unloaded_begin() const { return m_removed_soentries.begin(); } + iterator unloaded_end() const { return m_removed_soentries.end(); } + +protected: + lldb_private::Process *m_process; + + /// Location of the r_debug structure in the inferiors address space. + lldb::addr_t m_rendezvous_addr; + + /// Current and previous snapshots of the rendezvous structure. + Rendezvous m_current; + Rendezvous m_previous; + + /// List of SOEntry objects corresponding to the current link map state. + SOEntryList m_soentries; + + /// List of SOEntry's added to the link map since the last call to Resolve(). + SOEntryList m_added_soentries; + + /// List of SOEntry's removed from the link map since the last call to + /// Resolve(). + SOEntryList m_removed_soentries; + + /// Reads @p size bytes from the inferiors address space starting at @p + /// addr. + /// + /// @returns addr + size if the read was successful and false otherwise. + lldb::addr_t + ReadMemory(lldb::addr_t addr, void *dst, size_t size); + + /// Reads a null-terminated C string from the memory location starting at @p + /// addr. + std::string + ReadStringFromMemory(lldb::addr_t addr); + + /// Reads an SOEntry starting at @p addr. + bool + ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry); + + /// Updates the current set of SOEntries, the set of added entries, and the + /// set of removed entries. + bool + UpdateSOEntries(); + + bool + UpdateSOEntriesForAddition(); + + bool + UpdateSOEntriesForDeletion(); + + /// Reads the current list of shared objects according to the link map + /// supplied by the runtime linker. + bool + TakeSnapshot(SOEntryList &entry_list); +}; + +#endif Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp?rev=123592&view=auto ============================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp (added) +++ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.cpp Sun Jan 16 13:45:39 2011 @@ -0,0 +1,371 @@ +//===-- DynamicLoaderLinux.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +// C++ Includes +#include + +// Other libraries and framework includes +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" + +#include "AuxVector.h" +#include "DynamicLoaderLinuxDYLD.h" + +using namespace lldb; +using namespace lldb_private; + +void +DynamicLoaderLinuxDYLD::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +DynamicLoaderLinuxDYLD::Terminate() +{ +} + +const char * +DynamicLoaderLinuxDYLD::GetPluginName() +{ + return "DynamicLoaderLinuxDYLD"; +} + +const char * +DynamicLoaderLinuxDYLD::GetShortPluginName() +{ + return "linux-dyld"; +} + +const char * +DynamicLoaderLinuxDYLD::GetPluginNameStatic() +{ + return "dynamic-loader.linux-dyld"; +} + +const char * +DynamicLoaderLinuxDYLD::GetPluginDescriptionStatic() +{ + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in Linux processes."; +} + +void +DynamicLoaderLinuxDYLD::GetPluginCommandHelp(const char *command, Stream *strm) +{ +} + +uint32_t +DynamicLoaderLinuxDYLD::GetPluginVersion() +{ + return 1; +} + +DynamicLoader * +DynamicLoaderLinuxDYLD::CreateInstance(Process *process) +{ + return new DynamicLoaderLinuxDYLD(process); +} + +DynamicLoaderLinuxDYLD::DynamicLoaderLinuxDYLD(Process *process) + : DynamicLoader(process), + m_rendezvous(process), + m_load_offset(LLDB_INVALID_ADDRESS), + m_entry_point(LLDB_INVALID_ADDRESS), + m_auxv(NULL) +{ +} + +DynamicLoaderLinuxDYLD::~DynamicLoaderLinuxDYLD() +{ +} + +void +DynamicLoaderLinuxDYLD::DidAttach() +{ + ModuleSP executable; + addr_t load_offset; + + m_auxv.reset(new AuxVector(m_process)); + + executable = m_process->GetTarget().GetExecutableModule(); + load_offset = ComputeLoadOffset(); + + if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS) + { + ModuleList module_list; + module_list.Append(executable); + UpdateLoadedSections(executable, load_offset); + m_process->GetTarget().ModulesDidLoad(module_list); + } +} + +void +DynamicLoaderLinuxDYLD::DidLaunch() +{ + ModuleSP executable; + addr_t load_offset; + + m_auxv.reset(new AuxVector(m_process)); + + executable = m_process->GetTarget().GetExecutableModule(); + load_offset = ComputeLoadOffset(); + + if (!executable.empty() && load_offset != LLDB_INVALID_ADDRESS) + { + ModuleList module_list; + module_list.Append(executable); + UpdateLoadedSections(executable, load_offset); + ProbeEntry(); + m_process->GetTarget().ModulesDidLoad(module_list); + } +} + +Error +DynamicLoaderLinuxDYLD::ExecutePluginCommand(Args &command, Stream *strm) +{ + return Error(); +} + +Log * +DynamicLoaderLinuxDYLD::EnablePluginLogging(Stream *strm, Args &command) +{ + return NULL; +} + +Error +DynamicLoaderLinuxDYLD::CanLoadImage() +{ + return Error(); +} + +void +DynamicLoaderLinuxDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr) +{ + ObjectFile *obj_file = module->GetObjectFile(); + SectionList *sections = obj_file->GetSectionList(); + SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList(); + const size_t num_sections = sections->GetSize(); + + for (unsigned i = 0; i < num_sections; ++i) + { + Section *section = sections->GetSectionAtIndex(i).get(); + lldb::addr_t new_load_addr = section->GetFileAddress() + base_addr; + lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section); + + // If the file address of the section is zero then this is not an + // allocatable/loadable section (property of ELF sh_addr). Skip it. + if (new_load_addr == base_addr) + continue; + + if (old_load_addr == LLDB_INVALID_ADDRESS || + old_load_addr != new_load_addr) + load_list.SetSectionLoadAddress(section, new_load_addr); + } +} + +void +DynamicLoaderLinuxDYLD::ProbeEntry() +{ + Breakpoint *entry_break; + addr_t entry; + + if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) + return; + + entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get(); + entry_break->SetCallback(EntryBreakpointHit, this, true); +} + +// The runtime linker has run and initialized the rendezvous structure once the +// process has hit its entry point. When we hit the corresponding breakpoint we +// interrogate the rendezvous structure to get the load addresses of all +// dependent modules for the process. Similarly, we can discover the runtime +// linker function and setup a breakpoint to notify us of any dynamically loaded +// modules (via dlopen). +bool +DynamicLoaderLinuxDYLD::EntryBreakpointHit(void *baton, + StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id) +{ + DynamicLoaderLinuxDYLD* dyld_instance; + + dyld_instance = static_cast(baton); + dyld_instance->LoadAllCurrentModules(); + dyld_instance->SetRendezvousBreakpoint(); + return false; // Continue running. +} + +void +DynamicLoaderLinuxDYLD::SetRendezvousBreakpoint() +{ + Breakpoint *dyld_break; + addr_t break_addr; + + break_addr = m_rendezvous.GetBreakAddress(); + dyld_break = m_process->GetTarget().CreateBreakpoint(break_addr, true).get(); + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); +} + +bool +DynamicLoaderLinuxDYLD::RendezvousBreakpointHit(void *baton, + StoppointCallbackContext *context, + user_id_t break_id, + user_id_t break_loc_id) +{ + DynamicLoaderLinuxDYLD* dyld_instance; + + dyld_instance = static_cast(baton); + dyld_instance->RefreshModules(); + + // Return true to stop the target, false to just let the target run. + return dyld_instance->GetStopWhenImagesChange(); +} + +void +DynamicLoaderLinuxDYLD::RefreshModules() +{ + if (!m_rendezvous.Resolve()) + return; + + DYLDRendezvous::iterator I; + DYLDRendezvous::iterator E; + + ModuleList &loaded_modules = m_process->GetTarget().GetImages(); + + if (m_rendezvous.ModulesDidLoad()) + { + ModuleList new_modules; + + E = m_rendezvous.loaded_end(); + for (I = m_rendezvous.loaded_begin(); I != E; ++I) + { + FileSpec file(I->path.c_str(), true); + ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); + if (!module_sp.empty()) + new_modules.Append(module_sp); + } + m_process->GetTarget().ModulesDidLoad(new_modules); + } + + if (m_rendezvous.ModulesDidUnload()) + { + ModuleList old_modules; + + E = m_rendezvous.unloaded_end(); + for (I = m_rendezvous.unloaded_begin(); I != E; ++I) + { + FileSpec file(I->path.c_str(), true); + ModuleSP module_sp = loaded_modules.FindFirstModuleForFileSpec(file); + if (!module_sp.empty()) + old_modules.Append(module_sp); + } + m_process->GetTarget().ModulesDidUnload(old_modules); + } +} + +ThreadPlanSP +DynamicLoaderLinuxDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop_others) +{ + LogSP log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + ThreadPlanSP thread_plan_sp; + + if (log) + log->PutCString("DynamicLoaderLinuxDYLD: " + "GetStepThroughTrampolinePlan not implemented\n"); + + return thread_plan_sp; +} + +void +DynamicLoaderLinuxDYLD::LoadAllCurrentModules() +{ + DYLDRendezvous::iterator I; + DYLDRendezvous::iterator E; + ModuleList module_list; + + if (!m_rendezvous.Resolve()) + return; + + for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) + { + FileSpec file(I->path.c_str(), false); + ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr); + if (!module_sp.empty()) + module_list.Append(module_sp); + } + + m_process->GetTarget().ModulesDidLoad(module_list); +} + +ModuleSP +DynamicLoaderLinuxDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr) +{ + Target &target = m_process->GetTarget(); + ModuleList &modules = target.GetImages(); + ModuleSP module_sp; + + if ((module_sp = modules.FindFirstModuleForFileSpec(file))) + { + UpdateLoadedSections(module_sp, base_addr); + } + else if ((module_sp = target.GetSharedModule(file, target.GetArchitecture()))) + { + UpdateLoadedSections(module_sp, base_addr); + modules.Append(module_sp); + } + + return module_sp; +} + +addr_t +DynamicLoaderLinuxDYLD::ComputeLoadOffset() +{ + addr_t virt_entry; + + if (m_load_offset != LLDB_INVALID_ADDRESS) + return m_load_offset; + + if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS) + return LLDB_INVALID_ADDRESS; + + ModuleSP module = m_process->GetTarget().GetExecutableModule(); + ObjectFile *exe = module->GetObjectFile(); + Address file_entry = exe->GetEntryPoint(); + + if (!file_entry.IsValid()) + return LLDB_INVALID_ADDRESS; + + m_load_offset = virt_entry - file_entry.GetFileAddress(); + return m_load_offset; +} + +addr_t +DynamicLoaderLinuxDYLD::GetEntryPoint() +{ + if (m_entry_point != LLDB_INVALID_ADDRESS) + return m_entry_point; + + if (m_auxv.get() == NULL) + return LLDB_INVALID_ADDRESS; + + AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY); + + if (I == m_auxv->end()) + return LLDB_INVALID_ADDRESS; + + m_entry_point = static_cast(I->value); + return m_entry_point; +} Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h?rev=123592&view=auto ============================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h (added) +++ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h Sun Jan 16 13:45:39 2011 @@ -0,0 +1,165 @@ +//===-- DynamicLoaderLinux.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_DynamicLoaderLinux_H_ +#define liblldb_DynamicLoaderLinux_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Target/DynamicLoader.h" + +#include "DYLDRendezvous.h" + +class AuxVector; + +class DynamicLoaderLinuxDYLD : public lldb_private::DynamicLoader +{ +public: + + static void + Initialize(); + + static void + Terminate(); + + static const char * + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process); + + DynamicLoaderLinuxDYLD(lldb_private::Process *process); + + virtual + ~DynamicLoaderLinuxDYLD(); + + //------------------------------------------------------------------ + // DynamicLoader protocol + //------------------------------------------------------------------ + + virtual void + DidAttach(); + + virtual void + DidLaunch(); + + virtual lldb::ThreadPlanSP + GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others); + + virtual lldb_private::Error + CanLoadImage(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual const char * + GetPluginName(); + + virtual const char * + GetShortPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + GetPluginCommandHelp(const char *command, lldb_private::Stream *strm); + + virtual lldb_private::Error + ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm); + + virtual lldb_private::Log * + EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command); + +protected: + /// Runtime linker rendezvous structure. + DYLDRendezvous m_rendezvous; + + /// Virtual load address of the inferior process. + lldb::addr_t m_load_offset; + + /// Virtual entry address of the inferior process. + lldb::addr_t m_entry_point; + + /// Auxiliary vector of the inferior process. + std::auto_ptr m_auxv; + + /// Enables a breakpoint on a function called by the runtime + /// linker each time a module is loaded or unloaded. + void + SetRendezvousBreakpoint(); + + /// Callback routine which updates the current list of loaded modules based + /// on the information supplied by the runtime linker. + static bool + RendezvousBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set + /// of loaded modules. + void + RefreshModules(); + + /// Updates the load address of every allocatable section in @p module. + /// + /// @param module The module to traverse. + /// + /// @param base_addr The virtual base address @p module is loaded at. + void + UpdateLoadedSections(lldb::ModuleSP module, + lldb::addr_t base_addr = 0); + + /// Locates or creates a module given by @p file and updates/loads the + /// resulting module at the virtual base address @p base_addr. + lldb::ModuleSP + LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t base_addr); + + /// Resolves the entry point for the current inferior process and sets a + /// breakpoint at that address. + void + ProbeEntry(); + + /// Callback routine invoked when we hit the breakpoint on process entry. + /// + /// This routine is responsible for resolving the load addresses of all + /// dependent modules required by the inferior and setting up the rendezvous + /// breakpoint. + static bool + EntryBreakpointHit(void *baton, + lldb_private::StoppointCallbackContext *context, + lldb::user_id_t break_id, + lldb::user_id_t break_loc_id); + + /// Helper for the entry breakpoint callback. Resolves the load addresses + /// of all dependent modules. + void + LoadAllCurrentModules(); + + /// Computes a value for m_load_offset returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t + ComputeLoadOffset(); + + /// Computes a value for m_entry_point returning the computed address on + /// success and LLDB_INVALID_ADDRESS on failure. + lldb::addr_t + GetEntryPoint(); + +private: + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderLinuxDYLD); +}; + +#endif // liblldb_DynamicLoaderLinuxDYLD_H_ Added: lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/Makefile URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/Makefile?rev=123592&view=auto ============================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/Makefile (added) +++ lldb/trunk/source/Plugins/DynamicLoader/Linux-DYLD/Makefile Sun Jan 16 13:45:39 2011 @@ -0,0 +1,14 @@ +##===- source/Plugins/DynamicLoader/Linux-DYLD/Makefile ----*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginDynamicLoaderLinux +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile Modified: lldb/trunk/source/Plugins/Makefile URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Makefile?rev=123592&r1=123591&r2=123592&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Makefile (original) +++ lldb/trunk/source/Plugins/Makefile Sun Jan 16 13:45:39 2011 @@ -23,7 +23,7 @@ endif ifeq ($(HOST_OS),Linux) -DIRS += Process/Linux +DIRS += Process/Linux DynamicLoader/Linux-DYLD endif include $(LLDB_LEVEL)/Makefile Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp?rev=123592&r1=123591&r2=123592&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.cpp Sun Jan 16 13:45:39 2011 @@ -13,6 +13,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Host/Host.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Target.h" #include "ProcessLinux.h" @@ -102,6 +103,19 @@ } Error +ProcessLinux::WillLaunch(Module* module) +{ + Error error; + + m_dyld_ap.reset(DynamicLoader::FindPlugin(this, "dynamic-loader.linux-dyld")); + if (m_dyld_ap.get() == NULL) + error.SetErrorString("unable to find the dynamic loader named " + "'dynamic-loader.linux-dyld'"); + + return error; +} + +Error ProcessLinux::DoLaunch(Module *module, char const *argv[], char const *envp[], @@ -128,6 +142,13 @@ return error; } +void +ProcessLinux::DidLaunch() +{ + if (m_dyld_ap.get() != NULL) + m_dyld_ap->DidLaunch(); +} + Error ProcessLinux::DoResume() { @@ -371,6 +392,12 @@ return m_byte_order; } +DynamicLoader * +ProcessLinux::GetDynamicLoader() +{ + return m_dyld_ap.get(); +} + //------------------------------------------------------------------------------ // ProcessInterface protocol. Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h?rev=123592&r1=123591&r2=123592&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h (original) +++ lldb/trunk/source/Plugins/Process/Linux/ProcessLinux.h Sun Jan 16 13:45:39 2011 @@ -60,6 +60,9 @@ CanDebug(lldb_private::Target &target); virtual lldb_private::Error + WillLaunch(lldb_private::Module *module); + + virtual lldb_private::Error DoAttachToProcessWithID(lldb::pid_t pid); virtual lldb_private::Error @@ -71,6 +74,9 @@ const char *stdout_path, const char *stderr_path); + virtual void + DidLaunch(); + virtual lldb_private::Error DoResume(); @@ -131,6 +137,9 @@ virtual lldb::addr_t GetImageInfoAddress(); + virtual lldb_private::DynamicLoader * + GetDynamicLoader(); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -176,6 +185,9 @@ lldb_private::Mutex m_message_mutex; std::queue m_message_queue; + /// Dynamic loader plugin associated with this process. + std::auto_ptr m_dyld_ap; + /// Updates the loaded sections provided by the executable. /// /// FIXME: It would probably be better to delegate this task to the Modified: lldb/trunk/source/lldb.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=123592&r1=123591&r2=123592&view=diff ============================================================================== --- lldb/trunk/source/lldb.cpp (original) +++ lldb/trunk/source/lldb.cpp Sun Jan 16 13:45:39 2011 @@ -44,6 +44,7 @@ #ifdef __linux__ #include "Plugins/Process/Linux/ProcessLinux.h" +#include "Plugins/DynamicLoader/Linux-DYLD/DynamicLoaderLinuxDYLD.h" #endif using namespace lldb; @@ -94,6 +95,7 @@ #endif #ifdef __linux__ ProcessLinux::Initialize(); + DynamicLoaderLinuxDYLD::Initialize(); #endif } } @@ -137,6 +139,7 @@ #ifdef __linux__ ProcessLinux::Terminate(); + DynamicLoaderLinuxDYLD::Terminate(); #endif Log::Terminate(); From wilsons at start.ca Sun Jan 16 14:25:22 2011 From: wilsons at start.ca (Stephen Wilson) Date: Sun, 16 Jan 2011 15:25:22 -0500 Subject: [Lldb-commits] [PATCH][RFC] Linux DynamicLoader plugin. In-Reply-To: (Greg Clayton's message of "Sat, 15 Jan 2011 15:48:37 -0800") References: Message-ID: Greg Clayton writes: > Looks good, and great news that linux now has a dynamic loader. Committed in r123592. > The nice thing is if you want remote linux debugging, we can modify > the ProcessGDBRemote plug-in, on linux by default, to use this dynamic > loader plug-in since they are completely pluggable. We would need to > just write a linux remote debug server. The current "debugserver" > project really needs to be re-written from the ground up using the > classes we have in LLDB (StringExtractor, GDBRemoteCommunication, > StringExtractorGDBRemote). Out of curiosity, would you be OK with a debug server written in plain C? Main reason is that on many embedded systems a C++ runtime is not available. I do not have any plans at the moment to work on it, I am just curious if such an effort could be folded into LLDB proper instead of being an independent project. > One might also be able to make slight modifications to the existing > GDB gdbserver binary (from the current GDB sources) for linux, and use > it as the remote stub to connect to with LLDB! That is an interesting option. Will keep it in mind. Take care, -- steve From gclayton at apple.com Sun Jan 16 20:02:07 2011 From: gclayton at apple.com (Greg Clayton) Date: Sun, 16 Jan 2011 18:02:07 -0800 Subject: [Lldb-commits] [PATCH][RFC] Linux DynamicLoader plugin. In-Reply-To: References: Message-ID: On Jan 16, 2011, at 12:25 PM, Stephen Wilson wrote: > Greg Clayton writes: >> Looks good, and great news that linux now has a dynamic loader. > > Committed in r123592. > >> The nice thing is if you want remote linux debugging, we can modify >> the ProcessGDBRemote plug-in, on linux by default, to use this dynamic >> loader plug-in since they are completely pluggable. We would need to >> just write a linux remote debug server. The current "debugserver" >> project really needs to be re-written from the ground up using the >> classes we have in LLDB (StringExtractor, GDBRemoteCommunication, >> StringExtractorGDBRemote). > > Out of curiosity, would you be OK with a debug server written in plain > C? Main reason is that on many embedded systems a C++ runtime is not > available. I do not have any plans at the moment to work on it, I am > just curious if such an effort could be folded into LLDB proper instead > of being an independent project. Anyone else is welcome to do this, but on darwin, we won't be doing this. Why? We want to be sure to share the debugging backend for both the native and remote debugging. Right now we have disabled the native debugging plug-in for MacOSX and we debug remotely even when debugging local processes. We do this by spawning a debugserver instance and attach to a known port number (passed in via a command line option) and then have the debugserver launch the inferior process. Partly to insulate lldb from bad things happening to parent processes when debugging a child process, and partly so we are just ready for remote debugging. Soon we plan to re-enable the native debugging plug-in, but we plan to switch over to using the DNB.h interface that we use inside debugserver for local debugging. Previously we were maintaining both a copy of the debugging backend in both debugserver and in ProcessMacOSX which was a bit tedious and sometimes we would fix something in one and not the other. BTW: the interface in DNB.h is a nice concise C level debugging interface that could be used for the simpler GDB remote server. If the GDB remote server was written in C, then each new debug target could just implement their own implementation of the DNB.h interface and have it both work for native and remote debugging. The interface in DNB.h is designed to be dynamic to allow for self describing registers and register sets, and much more. >> One might also be able to make slight modifications to the existing >> GDB gdbserver binary (from the current GDB sources) for linux, and use >> it as the remote stub to connect to with LLDB! > > That is an interesting option. Will keep it in mind. > > > Take care, > > -- > steve From gclayton at apple.com Sun Jan 16 21:46:26 2011 From: gclayton at apple.com (Greg Clayton) Date: Mon, 17 Jan 2011 03:46:26 -0000 Subject: [Lldb-commits] [lldb] r123613 - in /lldb/trunk: include/lldb/ include/lldb/API/ include/lldb/Core/ include/lldb/Expression/ include/lldb/Symbol/ lldb.xcodeproj/ source/API/ source/Commands/ source/Core/ source/Expression/ source/Interpreter/ source/Plugins/Disassembler/llvm/ source/Plugins/Process/gdb-remote/ source/Plugins/SymbolFile/DWARF/ source/Symbol/ source/Target/ test/class_types/ Message-ID: <20110117034627.26FD42A6C12C@llvm.org> Author: gclayton Date: Sun Jan 16 21:46:26 2011 New Revision: 123613 URL: http://llvm.org/viewvc/llvm-project?rev=123613&view=rev Log: A few of the issue I have been trying to track down and fix have been due to the way LLDB lazily gets complete definitions for types within the debug info. When we run across a class/struct/union definition in the DWARF, we will only parse the full definition if we need to. This works fine for top level types that are assigned directly to variables and arguments, but when we have a variable with a class, lets say "A" for this example, that has a member: "B *m_b". Initially we don't need to hunt down a definition for this class unless we are ever asked to do something with it ("expr m_b->getDecl()" for example). With my previous approach to lazy type completion, we would be able to take a "A *a" and get a complete type for it, but we wouldn't be able to then do an "a->m_b->getDecl()" unless we always expanded all types within a class prior to handing out the type. Expanding everything is very costly and it would be great if there were a better way. A few months ago I worked with the llvm/clang folks to have the ExternalASTSource class be able to complete classes if there weren't completed yet: class ExternalASTSource { .... virtual void CompleteType (clang::TagDecl *Tag); virtual void CompleteType (clang::ObjCInterfaceDecl *Class); }; This was great, because we can now have the class that is producing the AST (SymbolFileDWARF and SymbolFileDWARFDebugMap) sign up as external AST sources and the object that creates the forward declaration types can now also complete them anywhere within the clang type system. This patch makes a few major changes: - lldb_private::Module classes now own the AST context. Previously the TypeList objects did. - The DWARF parsers now sign up as an external AST sources so they can complete types. - All of the pure clang type system wrapper code we have in LLDB (ClangASTContext, ClangASTType, and more) can now be iterating through children of any type, and if a class/union/struct type (clang::RecordType or ObjC interface) is found that is incomplete, we can ask the AST to get the definition. - The SymbolFileDWARFDebugMap class now will create and use a single AST that all child SymbolFileDWARF classes will share (much like what happens when we have a complete linked DWARF for an executable). We will need to modify some of the ClangUserExpression code to take more advantage of this completion ability in the near future. Meanwhile we should be better off now that we can be accessing any children of variables through pointers and always be able to resolve the clang type if needed. Modified: lldb/trunk/include/lldb/API/SBValue.h lldb/trunk/include/lldb/Core/Module.h lldb/trunk/include/lldb/Core/ValueObject.h lldb/trunk/include/lldb/Core/ValueObjectChild.h lldb/trunk/include/lldb/Core/ValueObjectConstResult.h lldb/trunk/include/lldb/Core/ValueObjectRegister.h lldb/trunk/include/lldb/Core/ValueObjectVariable.h lldb/trunk/include/lldb/Expression/ClangASTSource.h lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h lldb/trunk/include/lldb/Symbol/ClangASTContext.h lldb/trunk/include/lldb/Symbol/SymbolFile.h lldb/trunk/include/lldb/Symbol/TaggedASTType.h lldb/trunk/include/lldb/Symbol/Type.h lldb/trunk/include/lldb/Symbol/TypeList.h lldb/trunk/include/lldb/lldb-forward.h lldb/trunk/lldb.xcodeproj/project.pbxproj lldb/trunk/source/API/SBType.cpp lldb/trunk/source/API/SBValue.cpp lldb/trunk/source/Commands/CommandObjectArgs.cpp lldb/trunk/source/Core/Module.cpp lldb/trunk/source/Core/ValueObject.cpp lldb/trunk/source/Core/ValueObjectChild.cpp lldb/trunk/source/Core/ValueObjectConstResult.cpp lldb/trunk/source/Core/ValueObjectRegister.cpp lldb/trunk/source/Core/ValueObjectVariable.cpp lldb/trunk/source/Expression/ClangASTSource.cpp lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp lldb/trunk/source/Interpreter/CommandInterpreter.cpp lldb/trunk/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h lldb/trunk/source/Symbol/ClangASTContext.cpp lldb/trunk/source/Symbol/ClangASTType.cpp lldb/trunk/source/Symbol/SymbolFile.cpp lldb/trunk/source/Symbol/SymbolVendor.cpp lldb/trunk/source/Symbol/Type.cpp lldb/trunk/source/Symbol/TypeList.cpp lldb/trunk/source/Target/StackFrame.cpp lldb/trunk/source/Target/ThreadPlanTracer.cpp lldb/trunk/test/class_types/TestClassTypes.py Modified: lldb/trunk/include/lldb/API/SBValue.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBValue.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/API/SBValue.h (original) +++ lldb/trunk/include/lldb/API/SBValue.h Sun Jan 16 21:46:26 2011 @@ -106,6 +106,9 @@ bool GetExpressionPath (lldb::SBStream &description); + + bool + GetExpressionPath (lldb::SBStream &description, bool qualify_cxx_base_classes); protected: friend class SBValueList; Modified: lldb/trunk/include/lldb/Core/Module.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Module.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/Module.h (original) +++ lldb/trunk/include/lldb/Core/Module.h Sun Jan 16 21:46:26 2011 @@ -16,6 +16,7 @@ #include "lldb/Symbol/ObjectFile.h" #include "lldb/Host/Mutex.h" #include "lldb/Host/TimeValue.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/Symtab.h" @@ -561,6 +562,9 @@ m_is_dynamic_loader_module = b; } + ClangASTContext & + GetClangASTContext (); + protected: //------------------------------------------------------------------ // Member Variables @@ -573,9 +577,11 @@ ConstString m_object_name; ///< The name an object within this module that is selected, or empty of the module is represented by \a m_file. std::auto_ptr m_objfile_ap; ///< A pointer to the object file parser for this module. std::auto_ptr m_symfile_ap; ///< A pointer to the symbol vendor for this module. + ClangASTContext m_ast; ///< The AST context for this module. bool m_did_load_objfile:1, m_did_load_symbol_vendor:1, m_did_parse_uuid:1, + m_did_init_ast:1, m_is_dynamic_loader_module:1; //------------------------------------------------------------------ Modified: lldb/trunk/include/lldb/Core/ValueObject.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/ValueObject.h (original) +++ lldb/trunk/include/lldb/Core/ValueObject.h Sun Jan 16 21:46:26 2011 @@ -44,7 +44,7 @@ virtual clang::ASTContext * GetClangAST () = 0; - virtual void * + virtual lldb::clang_type_t GetClangType () = 0; virtual lldb::ValueType @@ -88,7 +88,7 @@ } virtual void - GetExpressionPath (Stream &s); + GetExpressionPath (Stream &s, bool qualify_cxx_base_classes); virtual bool IsInScope (StackFrame *frame) Modified: lldb/trunk/include/lldb/Core/ValueObjectChild.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObjectChild.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/ValueObjectChild.h (original) +++ lldb/trunk/include/lldb/Core/ValueObjectChild.h Sun Jan 16 21:46:26 2011 @@ -67,7 +67,7 @@ return m_clang_ast; } - virtual void * + virtual lldb::clang_type_t GetClangType () { return m_clang_type; Modified: lldb/trunk/include/lldb/Core/ValueObjectConstResult.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObjectConstResult.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/ValueObjectConstResult.h (original) +++ lldb/trunk/include/lldb/Core/ValueObjectConstResult.h Sun Jan 16 21:46:26 2011 @@ -57,7 +57,7 @@ virtual clang::ASTContext * GetClangAST (); - virtual void * + virtual lldb::clang_type_t GetClangType (); virtual lldb::ValueType Modified: lldb/trunk/include/lldb/Core/ValueObjectRegister.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObjectRegister.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/ValueObjectRegister.h (original) +++ lldb/trunk/include/lldb/Core/ValueObjectRegister.h Sun Jan 16 21:46:26 2011 @@ -37,7 +37,7 @@ virtual clang::ASTContext * GetClangAST (); - virtual void * + virtual lldb::clang_type_t GetClangType (); virtual lldb::ValueType @@ -82,7 +82,7 @@ virtual clang::ASTContext * GetClangAST (); - virtual void * + virtual lldb::clang_type_t GetClangType (); virtual lldb::ValueType @@ -130,7 +130,7 @@ virtual clang::ASTContext * GetClangAST (); - virtual void * + virtual lldb::clang_type_t GetClangType (); virtual lldb::ValueType Modified: lldb/trunk/include/lldb/Core/ValueObjectVariable.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObjectVariable.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Core/ValueObjectVariable.h (original) +++ lldb/trunk/include/lldb/Core/ValueObjectVariable.h Sun Jan 16 21:46:26 2011 @@ -36,7 +36,7 @@ virtual clang::ASTContext * GetClangAST (); - virtual void * + virtual lldb::clang_type_t GetClangType (); virtual ConstString Modified: lldb/trunk/include/lldb/Expression/ClangASTSource.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ClangASTSource.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/ClangASTSource.h (original) +++ lldb/trunk/include/lldb/Expression/ClangASTSource.h Sun Jan 16 21:46:26 2011 @@ -13,7 +13,7 @@ #include #include "clang/Basic/IdentifierTable.h" -#include "clang/Sema/ExternalSemaSource.h" +#include "clang/AST/ExternalASTSource.h" namespace lldb_private { @@ -30,7 +30,7 @@ /// to Clang for these names, consulting the ClangExpressionDeclMap to do /// the actual lookups. //---------------------------------------------------------------------- -class ClangASTSource : public clang::ExternalSemaSource +class ClangASTSource : public clang::ExternalASTSource { public: //------------------------------------------------------------------ @@ -44,8 +44,8 @@ /// @param[in] declMap /// A reference to the LLDB object that handles entity lookup. //------------------------------------------------------------------ - ClangASTSource(clang::ASTContext &context, - ClangExpressionDeclMap &decl_map) : + ClangASTSource (clang::ASTContext &context, + ClangExpressionDeclMap &decl_map) : m_ast_context (context), m_decl_map (decl_map), m_active_lookups () @@ -60,27 +60,59 @@ //------------------------------------------------------------------ /// Interface stub that returns NULL. //------------------------------------------------------------------ - clang::Decl *GetExternalDecl(uint32_t); + virtual clang::Decl * + GetExternalDecl(uint32_t) + { + // These are only required for AST source that want to lazily load + // the declarations (or parts thereof) that they return. + return NULL; + } //------------------------------------------------------------------ /// Interface stub that returns NULL. //------------------------------------------------------------------ - clang::Stmt *GetExternalDeclStmt(uint64_t); + virtual clang::Stmt * + GetExternalDeclStmt(uint64_t) + { + // These are only required for AST source that want to lazily load + // the declarations (or parts thereof) that they return. + return NULL; + } //------------------------------------------------------------------ /// Interface stub that returns an undifferentiated Selector. //------------------------------------------------------------------ - clang::Selector GetExternalSelector(uint32_t); + virtual clang::Selector + GetExternalSelector(uint32_t) + { + // These are also optional, although it might help with ObjC + // debugging if we have respectable signatures. But a more + // efficient interface (that didn't require scanning all files + // for method signatures!) might help. + return clang::Selector(); + } //------------------------------------------------------------------ /// Interface stub that returns 0. //------------------------------------------------------------------ - uint32_t GetNumExternalSelectors(); + virtual uint32_t + GetNumExternalSelectors() + { + // These are also optional, although it might help with ObjC + // debugging if we have respectable signatures. But a more + // efficient interface (that didn't require scanning all files + // for method signatures!) might help. + return 0; + } //------------------------------------------------------------------ /// Interface stub that returns NULL. //------------------------------------------------------------------ - clang::CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); + virtual clang::CXXBaseSpecifier * + GetExternalCXXBaseSpecifiers(uint64_t Offset) + { + return NULL; + } //------------------------------------------------------------------ /// Look up all Decls that match a particular name. Only handles @@ -96,22 +128,31 @@ /// @return /// Whatever SetExternalVisibleDeclsForName returns. //------------------------------------------------------------------ - clang::DeclContextLookupResult + virtual clang::DeclContextLookupResult FindExternalVisibleDeclsByName (const clang::DeclContext *DC, clang::DeclarationName Name); //------------------------------------------------------------------ /// Interface stub. //------------------------------------------------------------------ - void MaterializeVisibleDecls (const clang::DeclContext *DC); + virtual void + MaterializeVisibleDecls (const clang::DeclContext *DC); //------------------------------------------------------------------ /// Interface stub that returns true. //------------------------------------------------------------------ - bool FindExternalLexicalDecls (const clang::DeclContext *DC, - bool (*isKindWeWant)(clang::Decl::Kind), - llvm::SmallVectorImpl &Decls); + virtual bool + FindExternalLexicalDecls (const clang::DeclContext *DC, + bool (*isKindWeWant)(clang::Decl::Kind), + llvm::SmallVectorImpl &Decls); + + virtual void + CompleteType (clang::TagDecl *Tag); + + virtual void + CompleteType (clang::ObjCInterfaceDecl *Class); + //------------------------------------------------------------------ /// Called on entering a translation unit. Tells Clang by calling /// setHasExternalVisibleStorage() and setHasExternalLexicalStorage() Modified: lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h (original) +++ lldb/trunk/include/lldb/Expression/ClangExpressionDeclMap.h Sun Jan 16 21:46:26 2011 @@ -20,6 +20,7 @@ // Other libraries and framework includes // Project includes #include "llvm/ADT/DenseMap.h" +#include "lldb/lldb-include.h" #include "lldb/Core/ClangForward.h" #include "lldb/Core/Value.h" #include "lldb/Expression/ClangExpressionVariable.h" @@ -27,20 +28,8 @@ #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/ExecutionContext.h" -namespace llvm { - class Type; - class Value; -} - namespace lldb_private { -class ClangExpressionVariables; -class ClangPersistentVariables; -class Error; -class Function; -class NameSearchContext; -class Variable; - //---------------------------------------------------------------------- /// @class ClangExpressionDeclMap ClangExpressionDeclMap.h "lldb/Expression/ClangExpressionDeclMap.h" /// @brief Manages named entities that are defined in LLDB's debug information. @@ -430,11 +419,19 @@ /// True if a $__lldb variable has been found. //------------------------------------------------------------------ bool - GetLookupsEnabled () + GetLookupsEnabled () const { assert(m_parser_vars.get()); return m_parser_vars->m_enable_lookups; } + + bool + GetImportInProgress () const + { + if (m_parser_vars.get()) + return m_parser_vars->m_ignore_lookups; + return false; + } //------------------------------------------------------------------ /// [Used by ClangASTSource] Indicate that a $__lldb variable has Modified: lldb/trunk/include/lldb/Symbol/ClangASTContext.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangASTContext.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/ClangASTContext.h (original) +++ lldb/trunk/include/lldb/Symbol/ClangASTContext.h Sun Jan 16 21:46:26 2011 @@ -18,6 +18,8 @@ #include // Other libraries and framework includes +#include "llvm/ADT/OwningPtr.h" + // Project includes #include "lldb/lldb-enumerations.h" #include "lldb/Core/ClangForward.h" @@ -50,10 +52,13 @@ eTypeIsVector = (1u << 16) }; + typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *); + typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton, clang::ObjCInterfaceDecl *); + //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - ClangASTContext(const char *target_triple); + ClangASTContext (const char *triple = NULL); ~ClangASTContext(); @@ -99,6 +104,22 @@ void SetTargetTriple (const char *target_triple); + bool + HasExternalSource (); + + void + SetExternalSource (llvm::OwningPtr &ast_source_ap); + + void + RemoveExternalSource (); + + bool + GetCompleteType (lldb::clang_type_t clang_type); + + static bool + GetCompleteType (clang::ASTContext *ast, + lldb::clang_type_t clang_type); + //------------------------------------------------------------------ // Basic Types //------------------------------------------------------------------ @@ -108,7 +129,7 @@ uint32_t bit_size); static lldb::clang_type_t - GetBuiltinTypeForEncodingAndBitSize (clang::ASTContext *ast_context, + GetBuiltinTypeForEncodingAndBitSize (clang::ASTContext *ast, lldb::Encoding encoding, uint32_t bit_size); @@ -119,7 +140,7 @@ uint32_t bit_size); static lldb::clang_type_t - GetBuiltInType_void(clang::ASTContext *ast_context); + GetBuiltInType_void(clang::ASTContext *ast); lldb::clang_type_t GetBuiltInType_void() @@ -146,7 +167,7 @@ GetVoidPtrType(bool is_const); static lldb::clang_type_t - GetVoidPtrType(clang::ASTContext *ast_context, bool is_const); + GetVoidPtrType(clang::ASTContext *ast, bool is_const); static lldb::clang_type_t CopyType(clang::ASTContext *dest_context, @@ -159,7 +180,7 @@ clang::Decl *source_decl); static bool - AreTypesSame(clang::ASTContext *ast_context, + AreTypesSame(clang::ASTContext *ast, lldb::clang_type_t type1, lldb::clang_type_t type2); @@ -170,6 +191,13 @@ return ClangASTContext::AreTypesSame(getASTContext(), type1, type2); } + + lldb::clang_type_t + GetTypeForDecl (clang::TagDecl *decl); + + lldb::clang_type_t + GetTypeForDecl (clang::ObjCInterfaceDecl *objc_decl); + //------------------------------------------------------------------ // CVR modifiers //------------------------------------------------------------------ @@ -194,7 +222,7 @@ lldb::LanguageType language); static bool - AddFieldToRecordType (clang::ASTContext *ast_context, + AddFieldToRecordType (clang::ASTContext *ast, lldb::clang_type_t record_qual_type, const char *name, lldb::clang_type_t field_type, @@ -217,7 +245,7 @@ } static clang::CXXMethodDecl * - AddMethodToCXXRecordType (clang::ASTContext *ast_context, + AddMethodToCXXRecordType (clang::ASTContext *ast, lldb::clang_type_t record_opaque_type, const char *name, lldb::clang_type_t method_type, @@ -254,7 +282,7 @@ uint32_t& bitfield_bit_size); static bool - FieldIsBitfield (clang::ASTContext *ast_context, + FieldIsBitfield (clang::ASTContext *ast, clang::FieldDecl* field, uint32_t& bitfield_bit_size); @@ -274,7 +302,7 @@ bool isInternal); static bool - AddObjCClassIVar (clang::ASTContext *ast_context, + AddObjCClassIVar (clang::ASTContext *ast, lldb::clang_type_t class_opaque_type, const char *name, lldb::clang_type_t ivar_opaque_type, @@ -312,7 +340,7 @@ static clang::ObjCMethodDecl * - AddMethodToObjCObjectType (clang::ASTContext *ast_context, + AddMethodToObjCObjectType (clang::ASTContext *ast, lldb::clang_type_t class_opaque_type, const char *name, // the full symbol name as seen in the symbol table ("-[NString stringWithCString:]") lldb::clang_type_t method_opaque_type, @@ -331,6 +359,8 @@ access); } + static bool + SetHasExternalStorage (lldb::clang_type_t clang_type, bool has_extern); //------------------------------------------------------------------ // Aggregate Types @@ -341,11 +371,12 @@ // Returns a mask containing bits from the ClangASTContext::eTypeXXX enumerations static uint32_t GetTypeInfo (lldb::clang_type_t clang_type, - clang::ASTContext *ast_context, // The AST for clang_type (can be NULL) + clang::ASTContext *ast, // The AST for clang_type (can be NULL) lldb::clang_type_t *pointee_or_element_type); // (can be NULL) static uint32_t - GetNumChildren (lldb::clang_type_t clang_type, + GetNumChildren (clang::ASTContext *ast, + lldb::clang_type_t clang_type, bool omit_empty_base_classes); static uint32_t @@ -365,7 +396,7 @@ bool &child_is_base_class); static lldb::clang_type_t - GetChildClangTypeAtIndex (clang::ASTContext *ast_context, + GetChildClangTypeAtIndex (clang::ASTContext *ast, const char *parent_name, lldb::clang_type_t parent_clang_type, uint32_t idx, @@ -381,7 +412,7 @@ // Lookup a child given a name. This function will match base class names // and member member names in "clang_type" only, not descendants. static uint32_t - GetIndexOfChildWithName (clang::ASTContext *ast_context, + GetIndexOfChildWithName (clang::ASTContext *ast, lldb::clang_type_t clang_type, const char *name, bool omit_empty_base_classes); @@ -392,7 +423,7 @@ // TODO: Return all matches for a given name by returning a vector> // so we catch all names that match a given child name, not just the first. static size_t - GetIndexOfChildMemberWithName (clang::ASTContext *ast_context, + GetIndexOfChildMemberWithName (clang::ASTContext *ast, lldb::clang_type_t clang_type, const char *name, bool omit_empty_base_classes, @@ -452,7 +483,7 @@ bool is_inline); static lldb::clang_type_t - CreateFunctionType (clang::ASTContext *ast_context, + CreateFunctionType (clang::ASTContext *ast, lldb::clang_type_t result_type, lldb::clang_type_t *args, unsigned num_args, @@ -611,7 +642,7 @@ GetArraySize (lldb::clang_type_t clang_type); //static bool - //ConvertFloatValueToString (clang::ASTContext *ast_context, + //ConvertFloatValueToString (clang::ASTContext *ast, // lldb::clang_type_t clang_type, // const uint8_t* bytes, // size_t byte_size, @@ -619,7 +650,7 @@ // std::string &float_str); static size_t - ConvertStringToFloatValue (clang::ASTContext *ast_context, + ConvertStringToFloatValue (clang::ASTContext *ast, lldb::clang_type_t clang_type, const char *s, uint8_t *dst, @@ -635,7 +666,7 @@ // Classes that inherit from ClangASTContext can see and modify these //------------------------------------------------------------------ std::string m_target_triple; - std::auto_ptr m_ast_context_ap; + std::auto_ptr m_ast_ap; std::auto_ptr m_language_options_ap; std::auto_ptr m_file_manager_ap; std::auto_ptr m_file_system_options_ap; @@ -647,7 +678,9 @@ std::auto_ptr m_identifier_table_ap; std::auto_ptr m_selector_table_ap; std::auto_ptr m_builtins_ap; - + CompleteTagDeclCallback m_callback_tag_decl; + CompleteObjCInterfaceDeclCallback m_callback_objc_decl; + void * m_callback_baton; private: //------------------------------------------------------------------ // For ClangASTContext only Modified: lldb/trunk/include/lldb/Symbol/SymbolFile.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/SymbolFile.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/SymbolFile.h (original) +++ lldb/trunk/include/lldb/Symbol/SymbolFile.h Sun Jan 16 21:46:26 2011 @@ -56,7 +56,47 @@ { } + //------------------------------------------------------------------ + /// Get a mask of what this symbol file supports for the object file + /// that it was constructed with. + /// + /// Each symbol file gets to respond with a mask of abilities that + /// it supports for each object file. This happens when we are + /// trying to figure out which symbol file plug-in will get used + /// for a given object file. The plug-in that resoonds with the + /// best mix of "SymbolFile::Abilities" bits set, will get chosen to + /// be the symbol file parser. This allows each plug-in to check for + /// sections that contain data a symbol file plug-in would need. For + /// example the DWARF plug-in requires DWARF sections in a file that + /// contain debug information. If the DWARF plug-in doesn't find + /// these sections, it won't respond with many ability bits set, and + /// we will probably fall back to the symbol table SymbolFile plug-in + /// which uses any information in the symbol table. Also, plug-ins + /// might check for some specific symbols in a symbol table in the + /// case where the symbol table contains debug information (STABS + /// and COFF). Not a lot of work should happen in these functions + /// as the plug-in might not get selected due to another plug-in + /// having more abilities. Any initialization work should be saved + /// for "void SymbolFile::InitializeObject()" which will get called + /// on the SymbolFile object with the best set of abilities. + /// + /// @return + /// A uint32_t mask containing bits from the SymbolFile::Abilities + /// enumeration. Any bits that are set represent an ability that + /// this symbol plug-in can parse from the object file. + ///------------------------------------------------------------------ virtual uint32_t GetAbilities () = 0; + + //------------------------------------------------------------------ + /// Initialize the SymbolFile object. + /// + /// The SymbolFile object with the best set of abilities (detected + /// in "uint32_t SymbolFile::GetAbilities()) will have this function + /// called if it is chosen to parse an object file. More complete + /// initialization can happen in this function which will get called + /// prior to any other functions in the SymbolFile protocol. + //------------------------------------------------------------------ + virtual void InitializeObject() {} //------------------------------------------------------------------ // Compile Unit function calls @@ -83,6 +123,8 @@ virtual uint32_t FindTypes (const SymbolContext& sc, const ConstString &name, bool append, uint32_t max_matches, TypeList& types) = 0; // virtual uint32_t FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, TypeList& types) = 0; virtual TypeList * GetTypeList (); + virtual ClangASTContext & + GetClangASTContext (); virtual ClangNamespaceDecl FindNamespace (const SymbolContext& sc, const ConstString &name) = 0; @@ -90,7 +132,7 @@ ObjectFile* GetObjectFile() { return m_obj_file; } const ObjectFile* GetObjectFile() const { return m_obj_file; } protected: - ObjectFile* m_obj_file; // The object file that symbols can be extracted from. + ObjectFile* m_obj_file; // The object file that symbols can be extracted from. private: DISALLOW_COPY_AND_ASSIGN (SymbolFile); Modified: lldb/trunk/include/lldb/Symbol/TaggedASTType.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/TaggedASTType.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/TaggedASTType.h (original) +++ lldb/trunk/include/lldb/Symbol/TaggedASTType.h Sun Jan 16 21:46:26 2011 @@ -20,7 +20,7 @@ template class TaggedASTType : public ClangASTType { public: - TaggedASTType (void *type, clang::ASTContext *ast_context) : + TaggedASTType (lldb::clang_type_t type, clang::ASTContext *ast_context) : ClangASTType(type, ast_context) { } TaggedASTType (const TaggedASTType &tw) : Modified: lldb/trunk/include/lldb/Symbol/Type.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/Type.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/Type.h (original) +++ lldb/trunk/include/lldb/Symbol/Type.h Sun Jan 16 21:46:26 2011 @@ -226,6 +226,21 @@ uint32_t GetEncodingMask (); + void * + CreateClangPointerType (Type *type); + + void * + CreateClangTypedefType (Type *typedef_type, Type *base_type); + + // For C++98 references (&) + void * + CreateClangLValueReferenceType (Type *type); + + // For C++0x references (&&) + void * + CreateClangRValueReferenceType (Type *type); + + protected: ConstString m_name; SymbolFile *m_symbol_file; Modified: lldb/trunk/include/lldb/Symbol/TypeList.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/TypeList.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/Symbol/TypeList.h (original) +++ lldb/trunk/include/lldb/Symbol/TypeList.h Sun Jan 16 21:46:26 2011 @@ -11,7 +11,6 @@ #define liblldb_TypeList_h_ #include "lldb/lldb-private.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/Type.h" #include @@ -23,7 +22,7 @@ //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ - TypeList(const char *target_triple = NULL); + TypeList(); virtual ~TypeList(); @@ -52,31 +51,10 @@ lldb::TypeSP GetTypeAtIndex(uint32_t idx); - //------------------------------------------------------------------ - // Classes that inherit from TypeList can see and modify these - //------------------------------------------------------------------ - ClangASTContext & - GetClangASTContext (); - - void * - CreateClangPointerType (Type *type); - - void * - CreateClangTypedefType (Type *typedef_type, Type *base_type); - - // For C++98 references (&) - void * - CreateClangLValueReferenceType (Type *type); - - // For C++0x references (&&) - void * - CreateClangRValueReferenceType (Type *type); - private: typedef std::multimap collection; typedef collection::iterator iterator; typedef collection::const_iterator const_iterator; - ClangASTContext m_ast; ///< The type abtract syntax tree. collection m_types; Modified: lldb/trunk/include/lldb/lldb-forward.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/lldb-forward.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/include/lldb/lldb-forward.h (original) +++ lldb/trunk/include/lldb/lldb-forward.h Sun Jan 16 21:46:26 2011 @@ -48,6 +48,8 @@ class ClangExpressionVariable; class ClangExpressionVariableList; class ClangExpressionVariableList; +class ClangExpressionVariables; +class ClangPersistentVariables; class CommandInterpreter; class CommandObject; class CommandReturnObject; @@ -90,6 +92,7 @@ class Module; class ModuleList; class Mutex; +class NameSearchContext; class ObjCLanguageRuntime; class ObjectContainer; class ObjectFile; Modified: lldb/trunk/lldb.xcodeproj/project.pbxproj URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/lldb.xcodeproj/project.pbxproj?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/lldb.xcodeproj/project.pbxproj (original) +++ lldb/trunk/lldb.xcodeproj/project.pbxproj Sun Jan 16 21:46:26 2011 @@ -305,6 +305,8 @@ 26DE20611161902700A093E2 /* SBBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE20601161902600A093E2 /* SBBlock.cpp */; }; 26DE20631161904200A093E2 /* SBLineEntry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE20621161904200A093E2 /* SBLineEntry.cpp */; }; 26DE20651161904E00A093E2 /* SBSymbol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26DE20641161904E00A093E2 /* SBSymbol.cpp */; }; + 26E6902F129C6BD500DDECD9 /* ClangExternalASTSourceCallbacks.h in Headers */ = {isa = PBXBuildFile; fileRef = 26E6902E129C6BD500DDECD9 /* ClangExternalASTSourceCallbacks.h */; }; + 26E69031129C6BEF00DDECD9 /* ClangExternalASTSourceCallbacks.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E69030129C6BEF00DDECD9 /* ClangExternalASTSourceCallbacks.cpp */; }; 26F5C27710F3D9E4009D5894 /* Driver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F5C27310F3D9E4009D5894 /* Driver.cpp */; }; 26F5C27810F3D9E4009D5894 /* IOChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26F5C27510F3D9E4009D5894 /* IOChannel.cpp */; }; 26F5C32510F3DF23009D5894 /* libpython.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C32410F3DF23009D5894 /* libpython.dylib */; }; @@ -896,6 +898,8 @@ 26E3EEE411A9901300FBADB6 /* UnwindMacOSXFrameBackchain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UnwindMacOSXFrameBackchain.h; path = Utility/UnwindMacOSXFrameBackchain.h; sourceTree = ""; }; 26E3EEF711A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RegisterContextMacOSXFrameBackchain.cpp; path = Utility/RegisterContextMacOSXFrameBackchain.cpp; sourceTree = ""; }; 26E3EEF811A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextMacOSXFrameBackchain.h; path = Utility/RegisterContextMacOSXFrameBackchain.h; sourceTree = ""; }; + 26E6902E129C6BD500DDECD9 /* ClangExternalASTSourceCallbacks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClangExternalASTSourceCallbacks.h; path = include/lldb/Symbol/ClangExternalASTSourceCallbacks.h; sourceTree = ""; }; + 26E69030129C6BEF00DDECD9 /* ClangExternalASTSourceCallbacks.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClangExternalASTSourceCallbacks.cpp; path = source/Symbol/ClangExternalASTSourceCallbacks.cpp; sourceTree = ""; }; 26F5C26A10F3D9A4009D5894 /* lldb */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = lldb; sourceTree = BUILT_PRODUCTS_DIR; }; 26F5C27210F3D9E4009D5894 /* lldb-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "lldb-Info.plist"; path = "tools/driver/lldb-Info.plist"; sourceTree = ""; }; 26F5C27310F3D9E4009D5894 /* Driver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Driver.cpp; path = tools/driver/Driver.cpp; sourceTree = ""; }; @@ -1750,6 +1754,8 @@ 26BC7F1410F1B8EC00F91463 /* ClangASTContext.cpp */, 49E45FA911F660DC008F7B28 /* ClangASTType.h */, 49E45FAD11F660FE008F7B28 /* ClangASTType.cpp */, + 26E6902E129C6BD500DDECD9 /* ClangExternalASTSourceCallbacks.h */, + 26E69030129C6BEF00DDECD9 /* ClangExternalASTSourceCallbacks.cpp */, 266A42D7128E40040090CF7C /* ClangNamespaceDecl.h */, 266A42D5128E3FFB0090CF7C /* ClangNamespaceDecl.cpp */, 26BC7C5710F1B6E900F91463 /* CompileUnit.h */, @@ -2291,6 +2297,7 @@ 4C61978F12823D4300FAFFCC /* AppleObjCRuntimeV1.h in Headers */, 4CC2A14D128C7409001531C4 /* ThreadPlanTracer.h in Headers */, 266A42D8128E40040090CF7C /* ClangNamespaceDecl.h in Headers */, + 26E6902F129C6BD500DDECD9 /* ClangExternalASTSourceCallbacks.h in Headers */, 4C7CF7E41295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2790,6 +2797,7 @@ 4C61978E12823D4300FAFFCC /* AppleObjCRuntimeV1.cpp in Sources */, 4CC2A149128C73ED001531C4 /* ThreadPlanTracer.cpp in Sources */, 266A42D6128E3FFB0090CF7C /* ClangNamespaceDecl.cpp in Sources */, + 26E69031129C6BEF00DDECD9 /* ClangExternalASTSourceCallbacks.cpp in Sources */, 4C7CF7E61295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp in Sources */, B296983712C2FB98002D92C3 /* CommandObjectVersion.cpp in Sources */, ); @@ -2939,6 +2947,11 @@ GCC_ENABLE_OBJC_GC = supported; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + __STDC_CONSTANT_MACROS, + __STDC_LIMIT_MACROS, + LLDB_CONFIGURATION_DEBUG, + ); HEADER_SEARCH_PATHS = ""; INFOPLIST_FILE = "resources/LLDB-Info.plist"; INSTALL_PATH = /Developer/Library/PrivateFrameworks; @@ -2948,7 +2961,7 @@ "$(LLVM_BUILD_DIR)", ); LLVM_BUILD_DIR = "$(SRCROOT)/llvm"; - LLVM_CONFIGURATION = "Debug+Asserts"; + LLVM_CONFIGURATION = Release; OTHER_CFLAGS = ( "-DFOR_DYLD=0", "-DSUPPORT_REMOTE_UNWINDING", @@ -2991,6 +3004,11 @@ FRAMEWORK_VERSION = A; GCC_ENABLE_OBJC_GC = supported; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + __STDC_CONSTANT_MACROS, + __STDC_LIMIT_MACROS, + LLDB_CONFIGURATION_RELEASE, + ); HEADER_SEARCH_PATHS = ""; INFOPLIST_FILE = "resources/LLDB-Info.plist"; INSTALL_PATH = /Developer/Library/PrivateFrameworks; @@ -3100,6 +3118,11 @@ FRAMEWORK_VERSION = A; GCC_ENABLE_OBJC_GC = supported; GCC_INLINES_ARE_PRIVATE_EXTERN = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + __STDC_CONSTANT_MACROS, + __STDC_LIMIT_MACROS, + LLDB_CONFIGURATION_BUILD_AND_INTEGRATION, + ); HEADER_SEARCH_PATHS = ""; INFOPLIST_FILE = "resources/LLDB-Info.plist"; INSTALL_PATH = /Developer/Library/PrivateFrameworks; Modified: lldb/trunk/source/API/SBType.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBType.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/API/SBType.cpp (original) +++ lldb/trunk/source/API/SBType.cpp Sun Jan 16 21:46:26 2011 @@ -96,7 +96,9 @@ SBType::GetNumberChildren (bool omit_empty_base_classes) { if (IsValid ()) - return ClangASTContext::GetNumChildren(m_type, omit_empty_base_classes); + return ClangASTContext::GetNumChildren (static_cast(m_ast), + m_type, + omit_empty_base_classes); return 0; } Modified: lldb/trunk/source/API/SBValue.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBValue.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/API/SBValue.cpp (original) +++ lldb/trunk/source/API/SBValue.cpp Sun Jan 16 21:46:26 2011 @@ -457,7 +457,18 @@ { if (m_opaque_sp) { - m_opaque_sp->GetExpressionPath (description.ref()); + m_opaque_sp->GetExpressionPath (description.ref(), false); + return true; + } + return false; +} + +bool +SBValue::GetExpressionPath (SBStream &description, bool qualify_cxx_base_classes) +{ + if (m_opaque_sp) + { + m_opaque_sp->GetExpressionPath (description.ref(), qualify_cxx_base_classes); return true; } return false; Modified: lldb/trunk/source/Commands/CommandObjectArgs.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Commands/CommandObjectArgs.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Commands/CommandObjectArgs.cpp (original) +++ lldb/trunk/source/Commands/CommandObjectArgs.cpp Sun Jan 16 21:46:26 2011 @@ -156,15 +156,7 @@ return false; } - TypeList *thread_type_list = thread_module->GetTypeList (); - if (!thread_type_list) - { - result.AppendError ("The module has no type list."); - result.SetStatus (eReturnStatusFailed); - return false; - } - - ClangASTContext &ast_context = thread_type_list->GetClangASTContext(); + ClangASTContext &ast_context = thread_module->GetClangASTContext(); ValueList value_list; Modified: lldb/trunk/source/Core/Module.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Module.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Core/Module.cpp (original) +++ lldb/trunk/source/Core/Module.cpp Sun Jan 16 21:46:26 2011 @@ -29,9 +29,11 @@ m_object_name (), m_objfile_ap (), m_symfile_ap (), + m_ast (), m_did_load_objfile (false), m_did_load_symbol_vendor (false), m_did_parse_uuid (false), + m_did_init_ast (false), m_is_dynamic_loader_module (false) { if (object_name) @@ -60,6 +62,13 @@ m_object_name.IsEmpty() ? "" : "(", m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""), m_object_name.IsEmpty() ? "" : ")"); + // Release any auto pointers before we start tearing down our member + // variables since the object file and symbol files might need to make + // function calls back into this module object. The ordering is important + // here because symbol files can require the module object file. So we tear + // down the symbol file first, then the object file. + m_symfile_ap.reset(); + m_objfile_ap.reset(); } @@ -86,6 +95,23 @@ return m_uuid; } +ClangASTContext & +Module::GetClangASTContext () +{ + Mutex::Locker locker (m_mutex); + if (m_did_init_ast == false) + { + ObjectFile * objfile = GetObjectFile(); + ConstString target_triple; + if (objfile && objfile->GetTargetTriple(target_triple)) + { + m_did_init_ast = true; + m_ast.SetTargetTriple (target_triple.AsCString()); + } + } + return m_ast; +} + void Module::ParseAllDebugSymbols() { Modified: lldb/trunk/source/Core/ValueObject.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Core/ValueObject.cpp (original) +++ lldb/trunk/source/Core/ValueObject.cpp Sun Jan 16 21:46:26 2011 @@ -944,11 +944,11 @@ void -ValueObject::GetExpressionPath (Stream &s) +ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes) { if (m_parent) { - m_parent->GetExpressionPath (s); + m_parent->GetExpressionPath (s, qualify_cxx_base_classes); clang_type_t parent_clang_type = m_parent->GetClangType(); if (parent_clang_type) { @@ -967,11 +967,14 @@ if (IsBaseClass()) { - clang_type_t clang_type = GetClangType(); - std::string cxx_class_name; - if (ClangASTContext::GetCXXClassName (clang_type, cxx_class_name)) + if (qualify_cxx_base_classes) { - s << cxx_class_name.c_str() << "::"; + clang_type_t clang_type = GetClangType(); + std::string cxx_class_name; + if (ClangASTContext::GetCXXClassName (clang_type, cxx_class_name)) + { + s << cxx_class_name.c_str() << "::"; + } } } else @@ -1026,7 +1029,9 @@ if (flat_output) { - valobj->GetExpressionPath(s); + // If we are showing types, also qualify the C++ base classes + const bool qualify_cxx_base_classes = show_types; + valobj->GetExpressionPath(s, qualify_cxx_base_classes); s.PutCString(" ="); } else @@ -1270,7 +1275,7 @@ else { StreamString strm; - GetExpressionPath(strm); + GetExpressionPath(strm, true); if (is_pointer_type) error.SetErrorStringWithFormat("dereference failed: (%s) %s", GetTypeName().AsCString(""), strm.GetString().c_str()); @@ -1297,7 +1302,7 @@ case eAddressTypeInvalid: { StreamString expr_path_strm; - GetExpressionPath(expr_path_strm); + GetExpressionPath(expr_path_strm, true); error.SetErrorStringWithFormat("'%s' is not in memory", expr_path_strm.GetString().c_str()); } break; Modified: lldb/trunk/source/Core/ValueObjectChild.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectChild.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Core/ValueObjectChild.cpp (original) +++ lldb/trunk/source/Core/ValueObjectChild.cpp Sun Jan 16 21:46:26 2011 @@ -61,7 +61,7 @@ uint32_t ValueObjectChild::CalculateNumChildren() { - return ClangASTContext::GetNumChildren (m_clang_type, true); + return ClangASTContext::GetNumChildren (GetClangAST (), m_clang_type, true); } ConstString Modified: lldb/trunk/source/Core/ValueObjectConstResult.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectConstResult.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Core/ValueObjectConstResult.cpp (original) +++ lldb/trunk/source/Core/ValueObjectConstResult.cpp Sun Jan 16 21:46:26 2011 @@ -139,7 +139,7 @@ { } -void * +lldb::clang_type_t ValueObjectConstResult::GetClangType() { return m_value.GetClangType(); @@ -171,7 +171,7 @@ uint32_t ValueObjectConstResult::CalculateNumChildren() { - return ClangASTContext::GetNumChildren (GetClangType(), true); + return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true); } clang::ASTContext * Modified: lldb/trunk/source/Core/ValueObjectRegister.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectRegister.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Core/ValueObjectRegister.cpp (original) +++ lldb/trunk/source/Core/ValueObjectRegister.cpp Sun Jan 16 21:46:26 2011 @@ -42,7 +42,7 @@ { } -void * +lldb::clang_type_t ValueObjectRegisterContext::GetClangType () { return NULL; @@ -119,7 +119,7 @@ { } -void * +lldb::clang_type_t ValueObjectRegisterSet::GetClangType () { return NULL; @@ -227,7 +227,7 @@ { } -void * +lldb::clang_type_t ValueObjectRegister::GetClangType () { if (m_clang_type == NULL && m_reg_info) @@ -238,9 +238,7 @@ Module *exe_module = process->GetTarget().GetExecutableModule ().get(); if (exe_module) { - TypeList *type_list = exe_module->GetTypeList(); - if (type_list) - m_clang_type = type_list->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize (m_reg_info->encoding, m_reg_info->byte_size * 8); + m_clang_type = exe_module->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize (m_reg_info->encoding, m_reg_info->byte_size * 8); } } } @@ -269,11 +267,7 @@ { Module *exe_module = process->GetTarget().GetExecutableModule ().get(); if (exe_module) - { - TypeList *type_list = exe_module->GetTypeList(); - if (type_list) - return type_list->GetClangASTContext().getASTContext(); - } + return exe_module->GetClangASTContext().getASTContext(); } return NULL; } Modified: lldb/trunk/source/Core/ValueObjectVariable.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectVariable.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Core/ValueObjectVariable.cpp (original) +++ lldb/trunk/source/Core/ValueObjectVariable.cpp Sun Jan 16 21:46:26 2011 @@ -45,12 +45,12 @@ { } -void * +lldb::clang_type_t ValueObjectVariable::GetClangType () { Type *var_type = m_variable_sp->GetType(); if (var_type) - return var_type->GetClangType(); + return var_type->GetClangForwardType(); return NULL; } Modified: lldb/trunk/source/Expression/ClangASTSource.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangASTSource.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangASTSource.cpp (original) +++ lldb/trunk/source/Expression/ClangASTSource.cpp Sun Jan 16 21:46:26 2011 @@ -17,34 +17,34 @@ using namespace clang; using namespace lldb_private; -ClangASTSource::~ClangASTSource() {} +ClangASTSource::~ClangASTSource() +{ +} -void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) { +void +ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) +{ // Tell Sema to ask us when looking into the translation unit's decl. m_ast_context.getTranslationUnitDecl()->setHasExternalVisibleStorage(); m_ast_context.getTranslationUnitDecl()->setHasExternalLexicalStorage(); } -// These are only required for AST source that want to lazily load -// the declarations (or parts thereof) that they return. -Decl *ClangASTSource::GetExternalDecl(uint32_t) { return 0; } -Stmt *ClangASTSource::GetExternalDeclStmt(uint64_t) { return 0; } - -// These are also optional, although it might help with ObjC -// debugging if we have respectable signatures. But a more -// efficient interface (that didn't require scanning all files -// for method signatures!) might help. -Selector ClangASTSource::GetExternalSelector(uint32_t) { return Selector(); } -uint32_t ClangASTSource::GetNumExternalSelectors() { return 0; } -CXXBaseSpecifier *ClangASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) { return NULL; } - // The core lookup interface. -DeclContext::lookup_result ClangASTSource::FindExternalVisibleDeclsByName +DeclContext::lookup_result +ClangASTSource::FindExternalVisibleDeclsByName ( const DeclContext *decl_ctx, DeclarationName clang_decl_name ) { + if (m_decl_map.GetImportInProgress()) + return SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); + + std::string decl_name (clang_decl_name.getAsString()); + +// if (m_decl_map.DoingASTImport ()) +// return DeclContext::lookup_result(); +// switch (clang_decl_name.getNameKind()) { // Normal identifiers. case DeclarationName::Identifier: @@ -75,7 +75,6 @@ return DeclContext::lookup_result(); } - std::string decl_name (clang_decl_name.getAsString()); if (!m_decl_map.GetLookupsEnabled()) { @@ -112,25 +111,47 @@ return result; } -void ClangASTSource::MaterializeVisibleDecls(const DeclContext *DC) +void +ClangASTSource::CompleteType (TagDecl *tag_decl) +{ + puts(__PRETTY_FUNCTION__); +} + +void +ClangASTSource::CompleteType (ObjCInterfaceDecl *objc_decl) +{ + puts(__PRETTY_FUNCTION__); +} + +void +ClangASTSource::MaterializeVisibleDecls(const DeclContext *DC) { return; } // This is used to support iterating through an entire lexical context, // which isn't something the debugger should ever need to do. -bool ClangASTSource::FindExternalLexicalDecls(const DeclContext *DC, - bool (*isKindWeWant)(Decl::Kind), - llvm::SmallVectorImpl &Decls) { +bool +ClangASTSource::FindExternalLexicalDecls +( + const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + llvm::SmallVectorImpl &Decls +) +{ // true is for error, that's good enough for me return true; } -clang::ASTContext *NameSearchContext::GetASTContext() { +clang::ASTContext * +NameSearchContext::GetASTContext() +{ return &m_ast_source.m_ast_context; } -clang::NamedDecl *NameSearchContext::AddVarDecl(void *type) { +clang::NamedDecl * +NameSearchContext::AddVarDecl(void *type) +{ IdentifierInfo *ii = m_decl_name.getAsIdentifierInfo(); assert (type && "Type for variable must be non-NULL!"); @@ -148,7 +169,9 @@ return Decl; } -clang::NamedDecl *NameSearchContext::AddFunDecl (void *type) { +clang::NamedDecl * +NameSearchContext::AddFunDecl (void *type) +{ clang::FunctionDecl *func_decl = FunctionDecl::Create (m_ast_source.m_ast_context, const_cast(m_decl_context), SourceLocation(), @@ -199,7 +222,8 @@ return func_decl; } -clang::NamedDecl *NameSearchContext::AddGenericFunDecl() +clang::NamedDecl * +NameSearchContext::AddGenericFunDecl() { QualType generic_function_type(m_ast_source.m_ast_context.getFunctionType (m_ast_source.m_ast_context.getSizeType(), // result NULL, // argument types @@ -215,7 +239,8 @@ return AddFunDecl(generic_function_type.getAsOpaquePtr()); } -clang::NamedDecl *NameSearchContext::AddTypeDecl(void *type) +clang::NamedDecl * +NameSearchContext::AddTypeDecl(void *type) { QualType qual_type = QualType::getFromOpaquePtr(type); Modified: lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp (original) +++ lldb/trunk/source/Expression/ClangExpressionDeclMap.cpp Sun Jan 16 21:46:26 2011 @@ -1711,8 +1711,8 @@ log->PutCString (strm.GetData()); } - TypeFromUser user_type(type_sp->GetClangType(), - type_sp->GetClangAST()); + TypeFromUser user_type (type_sp->GetClangType(), + type_sp->GetClangAST()); AddOneType(context, user_type, false); } @@ -1748,18 +1748,9 @@ return NULL; } - TypeList *type_list = var_type->GetTypeList(); + clang::ASTContext *ast = var_type->GetClangASTContext().getASTContext(); - if (!type_list) - { - if (log) - log->PutCString("Skipped a definition because the type has no associated type list"); - return NULL; - } - - clang::ASTContext *exe_ast_ctx = type_list->GetClangASTContext().getASTContext(); - - if (!exe_ast_ctx) + if (!ast) { if (log) log->PutCString("There is no AST context for the current execution context"); @@ -1780,20 +1771,18 @@ } Error err; - if (!var_location_expr.Evaluate(&exe_ctx, exe_ast_ctx, NULL, loclist_base_load_addr, NULL, *var_location.get(), &err)) + if (!var_location_expr.Evaluate(&exe_ctx, ast, NULL, loclist_base_load_addr, NULL, *var_location.get(), &err)) { if (log) log->Printf("Error evaluating location: %s", err.AsCString()); return NULL; } - - clang::ASTContext *var_ast_context = type_list->GetClangASTContext().getASTContext(); - + void *type_to_use; if (parser_ast_context) { - type_to_use = GuardedCopyType(parser_ast_context, var_ast_context, var_opaque_type); + type_to_use = GuardedCopyType(parser_ast_context, ast, var_opaque_type); if (!type_to_use) { @@ -1834,14 +1823,13 @@ } if (user_type) - *user_type = TypeFromUser(var_opaque_type, var_ast_context); + *user_type = TypeFromUser(var_opaque_type, ast); return var_location.release(); } void -ClangExpressionDeclMap::AddOneVariable(NameSearchContext &context, - Variable* var) +ClangExpressionDeclMap::AddOneVariable (NameSearchContext &context, Variable* var) { assert (m_parser_vars.get()); @@ -1965,7 +1953,6 @@ { lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); - clang::Decl *copied_decl = ClangASTContext::CopyDecl (context.GetASTContext(), namespace_decl.GetASTContext(), namespace_decl.GetNamespaceDecl()); @@ -2012,8 +1999,7 @@ fun_address = &fun->GetAddressRange().GetBaseAddress(); - TypeList *type_list = fun_type->GetTypeList(); - fun_ast_context = type_list->GetClangASTContext().getASTContext(); + fun_ast_context = fun_type->GetClangASTContext().getASTContext(); void *copied_type = GuardedCopyType(context.GetASTContext(), fun_ast_context, fun_opaque_type); fun_decl = context.AddFunDecl(copied_type); Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original) +++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Sun Jan 16 21:46:26 2011 @@ -186,6 +186,7 @@ break_regex_cmd_ap->AddRegexCommand("^[\"']?([-+]\\[.*\\])[\"']?[[:space:]]*$", "breakpoint set --name '%1'") && break_regex_cmd_ap->AddRegexCommand("^$", "breakpoint list") && break_regex_cmd_ap->AddRegexCommand("^(-.*)$", "breakpoint set %1") && + break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])`(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%2' --shlib '%1'") && break_regex_cmd_ap->AddRegexCommand("^(.*[^[:space:]])[[:space:]]*$", "breakpoint set --name '%1'")) { CommandObjectSP break_regex_cmd_sp(break_regex_cmd_ap.release()); Modified: lldb/trunk/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp (original) +++ lldb/trunk/source/Plugins/Disassembler/llvm/DisassemblerLLVM.cpp Sun Jan 16 21:46:26 2011 @@ -25,8 +25,7 @@ #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" -#include -#include +#include using namespace lldb; using namespace lldb_private; @@ -380,12 +379,14 @@ } DisassemblerLLVM::DisassemblerLLVM(const ArchSpec &arch) : - Disassembler(arch) + Disassembler (arch), + m_disassembler (NULL) { char triple[256]; if (TripleForArchSpec (arch, triple, sizeof(triple))) { - assert(!EDGetDisassembler(&m_disassembler, triple, SyntaxForArchSpec (arch)) && "No disassembler created!"); + int err = EDGetDisassembler(&m_disassembler, triple, SyntaxForArchSpec (arch)); + assert (err == 0); } } @@ -402,6 +403,9 @@ uint32_t num_instructions ) { + if (m_disassembler == NULL) + return 0; + size_t total_inst_byte_size = 0; m_instruction_list.Clear(); Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Sun Jan 16 21:46:26 2011 @@ -574,12 +574,6 @@ m_byte_order = m_gdb_comm.GetByteOrder(); - Module * exe_module = GetTarget().GetExecutableModule().get(); - assert(exe_module); - - ObjectFile *exe_objfile = exe_module->GetObjectFile(); - assert(exe_objfile); - StreamString strm; ArchSpec inferior_arch; Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (original) +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp Sun Jan 16 21:46:26 2011 @@ -32,6 +32,7 @@ #include "lldb/Core/Value.h" #include "lldb/Symbol/Block.h" +#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/LineTable.h" #include "lldb/Symbol/ObjectFile.h" @@ -118,13 +119,6 @@ return new SymbolFileDWARF(obj_file); } - -ClangASTContext & -SymbolFileDWARF::GetClangASTContext() -{ - return GetTypeList()->GetClangASTContext(); -} - TypeList * SymbolFileDWARF::GetTypeList () { @@ -183,13 +177,61 @@ m_global_index(), m_type_index(), m_namespace_index(), - m_indexed(false), + m_indexed (false), + m_is_external_ast_source (false), m_ranges() { } SymbolFileDWARF::~SymbolFileDWARF() { + if (m_is_external_ast_source) + m_obj_file->GetModule()->GetClangASTContext().RemoveExternalSource (); +} + +static const ConstString & +GetDWARFMachOSegmentName () +{ + static ConstString g_dwarf_section_name ("__DWARF"); + return g_dwarf_section_name; +} + +ClangASTContext & +SymbolFileDWARF::GetClangASTContext () +{ + if (m_debug_map_symfile) + return m_debug_map_symfile->GetClangASTContext (); + + ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext(); + if (!m_is_external_ast_source) + { + m_is_external_ast_source = true; + llvm::OwningPtr ast_source_ap ( + new ClangExternalASTSourceCallbacks (SymbolFileDWARF::CompleteTagDecl, + SymbolFileDWARF::CompleteObjCInterfaceDecl, + this)); + + ast.SetExternalSource (ast_source_ap); + } + return ast; +} + +void +SymbolFileDWARF::InitializeObject() +{ + // Install our external AST source callbacks so we can complete Clang types. + Module *module = m_obj_file->GetModule(); + if (module) + { + const SectionList *section_list = m_obj_file->GetSectionList(); + + const Section* section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get(); + + // Memory map the DWARF mach-o segment so we have everything mmap'ed + // to keep our heap memory usage down. + if (section) + section->MemoryMapSectionDataFromObjectFile(m_obj_file, m_dwarf_data); + } } bool @@ -221,15 +263,10 @@ uint64_t debug_ranges_file_size = 0; uint64_t debug_str_file_size = 0; - static ConstString g_dwarf_section_name ("__DWARF"); - - section = section_list->FindSectionByName(g_dwarf_section_name).get(); + section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get(); if (section) - { - section->MemoryMapSectionDataFromObjectFile(m_obj_file, m_dwarf_data); section_list = §ion->GetChildren (); - } section = section_list->FindSectionByType (eSectionTypeDWARFDebugInfo, true).get(); if (section != NULL) @@ -1079,6 +1116,7 @@ size_t count = 0; const DWARFDebugInfoEntry *die; const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + uint32_t member_idx = 0; for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling()) { @@ -1155,6 +1193,17 @@ if (class_language == eLanguageTypeObjC || class_language == eLanguageTypeObjC_plus_plus) accessibility = eAccessNone; + + if (member_idx == 0 && !is_artificial && name && (strstr (name, "_vptr$") == name)) + { + // Not all compilers will mark the vtable pointer + // member as artificial (llvm-gcc). We can't have + // the virtual members in our classes otherwise it + // throws off all child offsets since we end up + // having and extra pointer sized member in our + // class layouts. + is_artificial = true; + } if (is_artificial == false) { @@ -1171,6 +1220,7 @@ bit_size); } } + ++member_idx; } break; @@ -1319,13 +1369,32 @@ return NULL; } +// This function is used when SymbolFileDWARFDebugMap owns a bunch of +// SymbolFileDWARF objects to detect if this DWARF file is the one that +// can resolve a clang_type. +bool +SymbolFileDWARF::HasForwardDeclForClangType (lldb::clang_type_t clang_type) +{ + clang_type_t clang_type_no_qualifiers = ClangASTType::RemoveFastQualifiers(clang_type); + const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers); + return die != NULL; +} + + lldb::clang_type_t SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (lldb::clang_type_t clang_type) { // We have a struct/union/class/enum that needs to be fully resolved. - const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (ClangASTType::RemoveFastQualifiers(clang_type)); + clang_type_t clang_type_no_qualifiers = ClangASTType::RemoveFastQualifiers(clang_type); + const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers); if (die == NULL) { +// if (m_debug_map_symfile) +// { +// Type *type = m_die_to_type[die]; +// if (type && type->GetSymbolFile() != this) +// return type->GetClangType(); +// } // We have already resolved this type... return clang_type; } @@ -1333,7 +1402,7 @@ // map in case anyone child members or other types require this type to get resolved. // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition // are done. - m_forward_decl_clang_type_to_die.erase (ClangASTType::RemoveFastQualifiers(clang_type)); + m_forward_decl_clang_type_to_die.erase (clang_type_no_qualifiers); DWARFDebugInfo* debug_info = DebugInfo(); @@ -2743,7 +2812,7 @@ if (namespace_name) { Declaration decl; // TODO: fill in the decl object - clang::NamespaceDecl *namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, decl, GetClangDeclContextForDIE (curr_cu, die->GetParent())); + clang::NamespaceDecl *namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, decl, GetClangDeclContextForDIE (curr_cu, die)); if (namespace_decl) { //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) => 0x%8.8x\n", decl_die->GetOffset(), die->GetOffset()); @@ -2775,7 +2844,7 @@ } clang::DeclContext *decl_ctx; - dw_offset_t die_offset = die->GetAttributeValueAsUnsigned(this, curr_cu, DW_AT_specification, DW_INVALID_OFFSET); + dw_offset_t die_offset = die->GetAttributeValueAsReference(this, curr_cu, DW_AT_specification, DW_INVALID_OFFSET); if (die_offset != DW_INVALID_OFFSET) { //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) check DW_AT_specification 0x%8.8x\n", decl_die->GetOffset(), die_offset); @@ -2784,7 +2853,7 @@ return decl_ctx; } - die_offset = die->GetAttributeValueAsUnsigned(this, curr_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET); + die_offset = die->GetAttributeValueAsReference(this, curr_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET); if (die_offset != DW_INVALID_OFFSET) { //printf ("SymbolFileDWARF::GetClangDeclContextForDIE ( die = 0x%8.8x ) check DW_AT_abstract_origin 0x%8.8x\n", decl_die->GetOffset(), die_offset); @@ -3182,6 +3251,7 @@ // When the definition needs to be defined. m_forward_decl_die_to_clang_type[die] = clang_type; m_forward_decl_clang_type_to_die[ClangASTType::RemoveFastQualifiers (clang_type)] = die; + ClangASTContext::SetHasExternalStorage (clang_type, true); } } @@ -3244,7 +3314,7 @@ DW_ATE_signed, byte_size * 8); clang_type = ast.CreateEnumerationType (type_name_cstr, - GetClangDeclContextForDIE (dwarf_cu, die->GetParent()), + GetClangDeclContextForDIE (dwarf_cu, die), decl, enumerator_clang_type); } @@ -3268,6 +3338,7 @@ m_die_to_type[die] = type_sp.get(); +#if LEAVE_ENUMS_FORWARD_DECLARED // Leave this as a forward declaration until we need // to know the details of the type. lldb_private::Type // will automatically call the SymbolFile virtual function @@ -3275,7 +3346,16 @@ // When the definition needs to be defined. m_forward_decl_die_to_clang_type[die] = clang_type; m_forward_decl_clang_type_to_die[ClangASTType::RemoveFastQualifiers (clang_type)] = die; - + ClangASTContext::SetHasExternalStorage (clang_type, true); +#else + ast.StartTagDeclarationDefinition (clang_type); + if (die->HasChildren()) + { + SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu)); + ParseChildEnumerators(sc, clang_type, type_sp->GetByteSize(), dwarf_cu, die); + } + ast.CompleteTagDeclarationDefinition (clang_type); +#endif } } break; @@ -4165,3 +4245,21 @@ return NULL; } +void +SymbolFileDWARF::CompleteTagDecl (void *baton, clang::TagDecl *decl) +{ + SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; + clang_type_t clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); +} + +void +SymbolFileDWARF::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl) +{ + SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton; + clang_type_t clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); +} + Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h (original) +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h Sun Jan 16 21:46:26 2011 @@ -26,7 +26,6 @@ #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Flags.h" #include "lldb/Core/UniqueCStringMap.h" -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolContext.h" @@ -81,6 +80,7 @@ virtual ~SymbolFileDWARF(); virtual uint32_t GetAbilities (); + virtual void InitializeObject(); //------------------------------------------------------------------ // Compile Unit function calls @@ -108,12 +108,25 @@ virtual uint32_t FindFunctions(const lldb_private::ConstString &name, uint32_t name_type_mask, bool append, lldb_private::SymbolContextList& sc_list); virtual uint32_t FindFunctions(const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list); virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::TypeList& types); -// virtual uint32_t FindTypes(const lldb_private::SymbolContext& sc, const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb::Type::Encoding encoding, lldb::user_id_t udt_uid, lldb_private::TypeList& types); - virtual lldb_private::TypeList *GetTypeList (); + virtual lldb_private::TypeList * + GetTypeList (); + virtual lldb_private::ClangASTContext & + GetClangASTContext (); + virtual lldb_private::ClangNamespaceDecl FindNamespace (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name); + + //------------------------------------------------------------------ + // ClangASTContext callbacks for external source lookups. + //------------------------------------------------------------------ + static void + CompleteTagDecl (void *baton, clang::TagDecl *); + + static void + CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -186,6 +199,9 @@ return m_flags; } + bool + HasForwardDeclForClangType (lldb::clang_type_t clang_type); + protected: enum @@ -301,9 +317,6 @@ m_debug_map_symfile = debug_map_symfile; } - lldb_private::ClangASTContext & - GetClangASTContext(); - clang::NamespaceDecl * ResolveNamespaceDIE (DWARFCompileUnit *curr_cu, const DWARFDebugInfoEntry *die); @@ -333,7 +346,8 @@ NameToDIE m_global_index; // Global and static variables NameToDIE m_type_index; // All type DIE offsets NameToDIE m_namespace_index; // All type DIE offsets - bool m_indexed; + bool m_indexed:1, + m_is_external_ast_source:1; std::auto_ptr m_ranges; Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp (original) +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp Sun Jan 16 21:46:26 2011 @@ -15,6 +15,8 @@ #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/Timer.h" + +#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/VariableList.h" @@ -72,12 +74,20 @@ { } -lldb_private::ClangASTContext & -SymbolFileDWARFDebugMap::GetClangASTContext () +void +SymbolFileDWARFDebugMap::InitializeObject() { - return GetTypeList()->GetClangASTContext(); + // Install our external AST source callbacks so we can complete Clang types. + llvm::OwningPtr ast_source_ap ( + new ClangExternalASTSourceCallbacks (SymbolFileDWARFDebugMap::CompleteTagDecl, + SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl, + this)); + + GetClangASTContext().SetExternalSource (ast_source_ap); } + + void SymbolFileDWARFDebugMap::InitOSO () { @@ -1093,3 +1103,44 @@ } } + +void +SymbolFileDWARFDebugMap::CompleteTagDecl (void *baton, clang::TagDecl *decl) +{ + SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton; + clang_type_t clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + { + SymbolFileDWARF *oso_dwarf; + + for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + if (oso_dwarf->HasForwardDeclForClangType (clang_type)) + { + oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); + return; + } + } + } +} + +void +SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl) +{ + SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton; + clang_type_t clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl); + if (clang_type) + { + SymbolFileDWARF *oso_dwarf; + + for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx) + { + if (oso_dwarf->HasForwardDeclForClangType (clang_type)) + { + oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type); + return; + } + } + } +} + Modified: lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h (original) +++ lldb/trunk/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h Sun Jan 16 21:46:26 2011 @@ -48,6 +48,8 @@ virtual uint32_t GetAbilities (); + virtual void InitializeObject(); + //------------------------------------------------------------------ // Compile Unit function calls //------------------------------------------------------------------ @@ -70,11 +72,20 @@ virtual uint32_t FindFunctions (const lldb_private::ConstString &name, uint32_t name_type_mask, bool append, lldb_private::SymbolContextList& sc_list); virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool append, lldb_private::SymbolContextList& sc_list); virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, bool append, uint32_t max_matches, lldb_private::TypeList& types); -// virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types); virtual lldb_private::ClangNamespaceDecl FindNamespace (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name); + + //------------------------------------------------------------------ + // ClangASTContext callbacks for external source lookups. + //------------------------------------------------------------------ + static void + CompleteTagDecl (void *baton, clang::TagDecl *); + + static void + CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *); + //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ @@ -200,9 +211,6 @@ const DWARFDebugInfoEntry *die, const lldb_private::ConstString &type_name); - lldb_private::ClangASTContext & - GetClangASTContext (); - //------------------------------------------------------------------ // Member Variables //------------------------------------------------------------------ Modified: lldb/trunk/source/Symbol/ClangASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTContext.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Symbol/ClangASTContext.cpp (original) +++ lldb/trunk/source/Symbol/ClangASTContext.cpp Sun Jan 16 21:46:26 2011 @@ -14,7 +14,24 @@ #include // Other libraries and framework includes + +// Clang headers like to use NDEBUG inside of them to enable/disable debug +// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing +// or another. This is bad because it means that if clang was built in release +// mode, it assumes that you are building in release mode which is not always +// the case. You can end up with functions that are defined as empty in header +// files when NDEBUG is not defined, and this can cause link errors with the +// clang .a files that you have since you might be missing functions in the .a +// file. So we have to define NDEBUG when including clang headers to avoid any +// mismatches. This is covered by rdar://problem/8691220 + +#ifndef NDEBUG +#define LLDB_DEFINED_NDEBUG_FOR_CLANG #define NDEBUG +// Need to include assert.h so it is as clang would expect it to be (disabled) +#include +#endif + #include "clang/AST/ASTContext.h" #include "clang/AST/ASTImporter.h" #include "clang/AST/CXXInheritance.h" @@ -29,7 +46,13 @@ #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/LangStandard.h" + +#ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG #undef NDEBUG +#undef LLDB_DEFINED_NDEBUG_FOR_CLANG +// Need to re-include assert.h so it is as _we_ would expect it to be (enabled) +#include +#endif #include "lldb/Core/dwarf.h" #include "lldb/Core/Flags.h" @@ -42,6 +65,76 @@ using namespace llvm; using namespace clang; + +static bool +GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type) +{ + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + case clang::Type::Enum: + { + clang::TagType *tag_type = dyn_cast(qual_type.getTypePtr()); + if (tag_type) + { + clang::TagDecl *tag_decl = tag_type->getDecl(); + if (tag_decl) + { + if (tag_decl->getDefinition()) + return true; + + if (tag_decl->hasExternalLexicalStorage()) + { + ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (external_ast_source) + { + external_ast_source->CompleteType(tag_decl); + return !tag_type->isIncompleteType(); + } + } + return false; + } + } + + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + clang::ObjCObjectType *objc_class_type = dyn_cast(qual_type); + if (objc_class_type) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + // We currently can't complete objective C types through the newly added ASTContext + // because it only supports TagDecl objects right now... + bool is_forward_decl = class_interface_decl->isForwardDecl(); + if (is_forward_decl && class_interface_decl->hasExternalLexicalStorage()) + { + ExternalASTSource *external_ast_source = ast->getExternalSource(); + if (external_ast_source) + { + external_ast_source->CompleteType (class_interface_decl); + is_forward_decl = class_interface_decl->isForwardDecl(); + } + } + return is_forward_decl; + } + } + break; + + case clang::Type::Typedef: + return GetCompleteQualType (ast, cast(qual_type)->getDecl()->getUnderlyingType()); + + default: + break; + } + + return true; +} + + static AccessSpecifier ConvertAccessTypeToAccessSpecifier (AccessType access) { @@ -100,7 +193,7 @@ switch (IK) { case IK_None: case IK_AST: - assert(0 && "Invalid input kind!"); + assert (!"Invalid input kind!"); case IK_OpenCL: LangStd = LangStandard::lang_opencl; break; @@ -237,9 +330,9 @@ } -ClangASTContext::ClangASTContext(const char *target_triple) : +ClangASTContext::ClangASTContext (const char *target_triple) : m_target_triple(), - m_ast_context_ap(), + m_ast_ap(), m_language_options_ap(), m_source_manager_ap(), m_diagnostic_ap(), @@ -247,7 +340,11 @@ m_target_info_ap(), m_identifier_table_ap(), m_selector_table_ap(), - m_builtins_ap() + m_builtins_ap(), + m_callback_tag_decl (NULL), + m_callback_objc_decl (NULL), + m_callback_baton (NULL) + { if (target_triple && target_triple[0]) m_target_triple.assign (target_triple); @@ -266,14 +363,14 @@ m_diagnostic_ap.reset(); m_source_manager_ap.reset(); m_language_options_ap.reset(); - m_ast_context_ap.reset(); + m_ast_ap.reset(); } void ClangASTContext::Clear() { - m_ast_context_ap.reset(); + m_ast_ap.reset(); m_language_options_ap.reset(); m_source_manager_ap.reset(); m_diagnostic_ap.reset(); @@ -297,25 +394,65 @@ m_target_triple.assign(target_triple); } +bool +ClangASTContext::HasExternalSource () +{ + ASTContext *ast = getASTContext(); + if (ast) + return ast->getExternalSource () != NULL; + return false; +} + +void +ClangASTContext::SetExternalSource (llvm::OwningPtr &ast_source_ap) +{ + ASTContext *ast = getASTContext(); + if (ast) + { + ast->setExternalSource (ast_source_ap); + ast->getTranslationUnitDecl()->setHasExternalLexicalStorage(true); + //ast->getTranslationUnitDecl()->setHasExternalVisibleStorage(true); + } +} + +void +ClangASTContext::RemoveExternalSource () +{ + ASTContext *ast = getASTContext(); + + if (ast) + { + llvm::OwningPtr empty_ast_source_ap; + ast->setExternalSource (empty_ast_source_ap); + ast->getTranslationUnitDecl()->setHasExternalLexicalStorage(false); + //ast->getTranslationUnitDecl()->setHasExternalVisibleStorage(false); + } +} + + ASTContext * ClangASTContext::getASTContext() { - if (m_ast_context_ap.get() == NULL) + if (m_ast_ap.get() == NULL) { - m_ast_context_ap.reset( - new ASTContext( - *getLanguageOptions(), - *getSourceManager(), - *getTargetInfo(), - *getIdentifierTable(), - *getSelectorTable(), - *getBuiltinContext(), - 0)); + m_ast_ap.reset(new ASTContext (*getLanguageOptions(), + *getSourceManager(), + *getTargetInfo(), + *getIdentifierTable(), + *getSelectorTable(), + *getBuiltinContext(), + 0)); + + if ((m_callback_tag_decl || m_callback_objc_decl) && m_callback_baton) + { + m_ast_ap->getTranslationUnitDecl()->setHasExternalLexicalStorage(); + //m_ast_ap->getTranslationUnitDecl()->setHasExternalVisibleStorage(); + } - m_ast_context_ap->getDiagnostics().setClient(getDiagnosticClient(), false); + m_ast_ap->getDiagnostics().setClient(getDiagnosticClient(), false); } - return m_ast_context_ap.get(); + return m_ast_ap.get(); } Builtin::Context * @@ -440,9 +577,9 @@ #pragma mark Basic Types static inline bool -QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast_context, QualType qual_type) +QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast, QualType qual_type) { - uint64_t qual_type_bit_size = ast_context->getTypeSize(qual_type); + uint64_t qual_type_bit_size = ast->getTypeSize(qual_type); if (qual_type_bit_size == bit_size) return true; return false; @@ -451,63 +588,63 @@ clang_type_t ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (Encoding encoding, uint32_t bit_size) { - ASTContext *ast_context = getASTContext(); + ASTContext *ast = getASTContext(); - assert (ast_context != NULL); + assert (ast != NULL); - return GetBuiltinTypeForEncodingAndBitSize (ast_context, encoding, bit_size); + return GetBuiltinTypeForEncodingAndBitSize (ast, encoding, bit_size); } clang_type_t -ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (ASTContext *ast_context, Encoding encoding, uint32_t bit_size) +ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (ASTContext *ast, Encoding encoding, uint32_t bit_size) { - if (!ast_context) + if (!ast) return NULL; switch (encoding) { case eEncodingInvalid: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy)) - return ast_context->VoidPtrTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->VoidPtrTy)) + return ast->VoidPtrTy.getAsOpaquePtr(); break; case eEncodingUint: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) - return ast_context->UnsignedCharTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) - return ast_context->UnsignedShortTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) - return ast_context->UnsignedIntTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) - return ast_context->UnsignedLongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) - return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) - return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) + return ast->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) + return ast->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) + return ast->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy)) + return ast->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy)) + return ast->UnsignedLongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty)) + return ast->UnsignedInt128Ty.getAsOpaquePtr(); break; case eEncodingSint: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) - return ast_context->CharTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) - return ast_context->ShortTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) - return ast_context->IntTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) - return ast_context->LongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) - return ast_context->LongLongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) - return ast_context->Int128Ty.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) + return ast->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy)) + return ast->ShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy)) + return ast->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongTy)) + return ast->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy)) + return ast->LongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty)) + return ast->Int128Ty.getAsOpaquePtr(); break; case eEncodingIEEE754: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy)) - return ast_context->FloatTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy)) - return ast_context->DoubleTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy)) - return ast_context->LongDoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy)) + return ast->FloatTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy)) + return ast->DoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy)) + return ast->LongDoubleTy.getAsOpaquePtr(); break; case eEncodingVector: @@ -521,11 +658,11 @@ clang_type_t ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name, uint32_t dw_ate, uint32_t bit_size) { - ASTContext *ast_context = getASTContext(); + ASTContext *ast = getASTContext(); #define streq(a,b) strcmp(a,b) == 0 - assert (ast_context != NULL); - if (ast_context) + assert (ast != NULL); + if (ast) { switch (dw_ate) { @@ -533,19 +670,19 @@ break; case DW_ATE_address: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy)) - return ast_context->VoidPtrTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->VoidPtrTy)) + return ast->VoidPtrTy.getAsOpaquePtr(); break; case DW_ATE_boolean: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->BoolTy)) - return ast_context->BoolTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) - return ast_context->UnsignedCharTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) - return ast_context->UnsignedShortTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) - return ast_context->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->BoolTy)) + return ast->BoolTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) + return ast->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) + return ast->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) + return ast->UnsignedIntTy.getAsOpaquePtr(); break; case DW_ATE_lo_user: @@ -553,31 +690,31 @@ if (strcmp(type_name, "complex") == 0) { clang_type_t complex_int_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("int", DW_ATE_signed, bit_size/2); - return ast_context->getComplexType (QualType::getFromOpaquePtr(complex_int_clang_type)).getAsOpaquePtr(); + return ast->getComplexType (QualType::getFromOpaquePtr(complex_int_clang_type)).getAsOpaquePtr(); } break; case DW_ATE_complex_float: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatComplexTy)) - return ast_context->FloatComplexTy.getAsOpaquePtr(); - else if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleComplexTy)) - return ast_context->DoubleComplexTy.getAsOpaquePtr(); - else if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleComplexTy)) - return ast_context->LongDoubleComplexTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatComplexTy)) + return ast->FloatComplexTy.getAsOpaquePtr(); + else if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleComplexTy)) + return ast->DoubleComplexTy.getAsOpaquePtr(); + else if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleComplexTy)) + return ast->LongDoubleComplexTy.getAsOpaquePtr(); else { clang_type_t complex_float_clang_type = GetBuiltinTypeForDWARFEncodingAndBitSize ("float", DW_ATE_float, bit_size/2); - return ast_context->getComplexType (QualType::getFromOpaquePtr(complex_float_clang_type)).getAsOpaquePtr(); + return ast->getComplexType (QualType::getFromOpaquePtr(complex_float_clang_type)).getAsOpaquePtr(); } break; case DW_ATE_float: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy)) - return ast_context->FloatTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy)) - return ast_context->DoubleTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy)) - return ast_context->LongDoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->FloatTy)) + return ast->FloatTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->DoubleTy)) + return ast->DoubleTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongDoubleTy)) + return ast->LongDoubleTy.getAsOpaquePtr(); break; case DW_ATE_signed: @@ -585,52 +722,52 @@ { if (strstr(type_name, "long long")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) - return ast_context->LongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy)) + return ast->LongLongTy.getAsOpaquePtr(); } else if (strstr(type_name, "long")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) - return ast_context->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongTy)) + return ast->LongTy.getAsOpaquePtr(); } else if (strstr(type_name, "short")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) - return ast_context->ShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy)) + return ast->ShortTy.getAsOpaquePtr(); } else if (strstr(type_name, "char")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) - return ast_context->CharTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) - return ast_context->SignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) + return ast->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy)) + return ast->SignedCharTy.getAsOpaquePtr(); } else if (strstr(type_name, "int")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) - return ast_context->IntTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) - return ast_context->Int128Ty.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy)) + return ast->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty)) + return ast->Int128Ty.getAsOpaquePtr(); } else if (streq(type_name, "wchar_t")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->WCharTy)) - return ast_context->WCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->WCharTy)) + return ast->WCharTy.getAsOpaquePtr(); } } // We weren't able to match up a type name, just search by size - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) - return ast_context->CharTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy)) - return ast_context->ShortTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy)) - return ast_context->IntTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy)) - return ast_context->LongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy)) - return ast_context->LongLongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty)) - return ast_context->Int128Ty.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) + return ast->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->ShortTy)) + return ast->ShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->IntTy)) + return ast->IntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongTy)) + return ast->LongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->LongLongTy)) + return ast->LongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->Int128Ty)) + return ast->Int128Ty.getAsOpaquePtr(); break; case DW_ATE_signed_char: @@ -638,14 +775,14 @@ { if (streq(type_name, "signed char")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) - return ast_context->SignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy)) + return ast->SignedCharTy.getAsOpaquePtr(); } } - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy)) - return ast_context->CharTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy)) - return ast_context->SignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->CharTy)) + return ast->CharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->SignedCharTy)) + return ast->SignedCharTy.getAsOpaquePtr(); break; case DW_ATE_unsigned: @@ -653,50 +790,50 @@ { if (strstr(type_name, "long long")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) - return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy)) + return ast->UnsignedLongLongTy.getAsOpaquePtr(); } else if (strstr(type_name, "long")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) - return ast_context->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy)) + return ast->UnsignedLongTy.getAsOpaquePtr(); } else if (strstr(type_name, "short")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) - return ast_context->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) + return ast->UnsignedShortTy.getAsOpaquePtr(); } else if (strstr(type_name, "char")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) - return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) + return ast->UnsignedCharTy.getAsOpaquePtr(); } else if (strstr(type_name, "int")) { - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) - return ast_context->UnsignedIntTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) - return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) + return ast->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty)) + return ast->UnsignedInt128Ty.getAsOpaquePtr(); } } // We weren't able to match up a type name, just search by size - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) - return ast_context->UnsignedCharTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy)) - return ast_context->UnsignedShortTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy)) - return ast_context->UnsignedIntTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy)) - return ast_context->UnsignedLongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy)) - return ast_context->UnsignedLongLongTy.getAsOpaquePtr(); - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty)) - return ast_context->UnsignedInt128Ty.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) + return ast->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedShortTy)) + return ast->UnsignedShortTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedIntTy)) + return ast->UnsignedIntTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongTy)) + return ast->UnsignedLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedLongLongTy)) + return ast->UnsignedLongLongTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedInt128Ty)) + return ast->UnsignedInt128Ty.getAsOpaquePtr(); break; case DW_ATE_unsigned_char: - if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy)) - return ast_context->UnsignedCharTy.getAsOpaquePtr(); + if (QualTypeMatchesBitSize (bit_size, ast, ast->UnsignedCharTy)) + return ast->UnsignedCharTy.getAsOpaquePtr(); break; case DW_ATE_imaginary_float: @@ -710,9 +847,9 @@ } clang_type_t -ClangASTContext::GetBuiltInType_void(ASTContext *ast_context) +ClangASTContext::GetBuiltInType_void(ASTContext *ast) { - return ast_context->VoidTy.getAsOpaquePtr(); + return ast->VoidTy.getAsOpaquePtr(); } clang_type_t @@ -757,9 +894,9 @@ } clang_type_t -ClangASTContext::GetVoidPtrType (ASTContext *ast_context, bool is_const) +ClangASTContext::GetVoidPtrType (ASTContext *ast, bool is_const) { - QualType void_ptr_type(ast_context->VoidPtrTy); + QualType void_ptr_type(ast->VoidPtrTy); if (is_const) void_ptr_type.addConst(); @@ -798,11 +935,11 @@ } bool -ClangASTContext::AreTypesSame(ASTContext *ast_context, +ClangASTContext::AreTypesSame(ASTContext *ast, clang_type_t type1, clang_type_t type2) { - return ast_context->hasSameType(QualType::getFromOpaquePtr(type1), + return ast->hasSameType(QualType::getFromOpaquePtr(type1), QualType::getFromOpaquePtr(type2)); } @@ -844,16 +981,39 @@ return NULL; } + +clang_type_t +ClangASTContext::GetTypeForDecl (TagDecl *decl) +{ + // No need to call the getASTContext() accessor (which can create the AST + // if it isn't created yet, because we can't have created a decl in this + // AST if our AST didn't already exist... + if (m_ast_ap.get()) + return m_ast_ap->getTagDeclType(decl).getAsOpaquePtr(); + return NULL; +} + +clang_type_t +ClangASTContext::GetTypeForDecl (ObjCInterfaceDecl *decl) +{ + // No need to call the getASTContext() accessor (which can create the AST + // if it isn't created yet, because we can't have created a decl in this + // AST if our AST didn't already exist... + if (m_ast_ap.get()) + return m_ast_ap->getObjCInterfaceType(decl).getAsOpaquePtr(); + return NULL; +} + #pragma mark Structure, Unions, Classes clang_type_t ClangASTContext::CreateRecordType (const char *name, int kind, DeclContext *decl_ctx, LanguageType language) { - ASTContext *ast_context = getASTContext(); - assert (ast_context != NULL); + ASTContext *ast = getASTContext(); + assert (ast != NULL); if (decl_ctx == NULL) - decl_ctx = ast_context->getTranslationUnitDecl(); + decl_ctx = ast->getTranslationUnitDecl(); if (language == eLanguageTypeObjC) @@ -868,13 +1028,78 @@ // the CXXRecordDecl class since we often don't know from debug information // if something is struct or a class, so we default to always use the more // complete definition just in case. - CXXRecordDecl *decl = CXXRecordDecl::Create(*ast_context, + CXXRecordDecl *decl = CXXRecordDecl::Create(*ast, (TagDecl::TagKind)kind, decl_ctx, SourceLocation(), - name && name[0] ? &ast_context->Idents.get(name) : NULL); + name && name[0] ? &ast->Idents.get(name) : NULL); - return ast_context->getTagDeclType(decl).getAsOpaquePtr(); + return ast->getTagDeclType(decl).getAsOpaquePtr(); +} + +bool +ClangASTContext::SetHasExternalStorage (clang_type_t clang_type, bool has_extern) +{ + if (clang_type == NULL) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); + switch (type_class) + { + case clang::Type::Record: + { + CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl(); + if (cxx_record_decl) + { + cxx_record_decl->setHasExternalLexicalStorage (has_extern); + //cxx_record_decl->setHasExternalVisibleStorage (has_extern); + return true; + } + } + break; + + case clang::Type::Enum: + { + EnumDecl *enum_decl = cast(qual_type)->getDecl(); + if (enum_decl) + { + enum_decl->setHasExternalLexicalStorage (has_extern); + //enum_decl->setHasExternalVisibleStorage (has_extern); + return true; + } + } + break; + + case clang::Type::ObjCObject: + case clang::Type::ObjCInterface: + { + ObjCObjectType *objc_class_type = dyn_cast(qual_type.getTypePtr()); + assert (objc_class_type); + if (objc_class_type) + { + ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + + if (class_interface_decl) + { + if (has_extern) + class_interface_decl->setExternallyCompleted(); + class_interface_decl->setHasExternalLexicalStorage (has_extern); + //class_interface_decl->setHasExternalVisibleStorage (has_extern); + return true; + } + } + } + break; + + case clang::Type::Typedef: + return ClangASTContext::SetHasExternalStorage (cast(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), has_extern); + + default: + break; + } + return false; } static bool @@ -1092,10 +1317,11 @@ return true; } + CXXMethodDecl * ClangASTContext::AddMethodToCXXRecordType ( - ASTContext *ast_context, + ASTContext *ast, clang_type_t record_opaque_type, const char *name, clang_type_t method_opaque_type, @@ -1109,30 +1335,15 @@ if (!record_opaque_type || !method_opaque_type || !name) return NULL; - assert(ast_context); + assert(ast); - IdentifierTable *identifier_table = &ast_context->Idents; + IdentifierTable *identifier_table = &ast->Idents; assert(identifier_table); QualType record_qual_type(QualType::getFromOpaquePtr(record_opaque_type)); - clang::Type *clang_type(record_qual_type.getTypePtr()); - - if (clang_type == NULL) - return NULL; - - RecordType *record_clang_type(dyn_cast(clang_type)); - - if (record_clang_type == NULL) - return NULL; - - RecordDecl *record_decl = record_clang_type->getDecl(); - - if (record_decl == NULL) - return NULL; - - CXXRecordDecl *cxx_record_decl = dyn_cast(record_decl); + CXXRecordDecl *cxx_record_decl = record_qual_type->getAsCXXRecordDecl(); if (cxx_record_decl == NULL) return NULL; @@ -1159,19 +1370,19 @@ if (name[0] == '~') { - cxx_method_decl = CXXDestructorDecl::Create (*ast_context, + cxx_method_decl = CXXDestructorDecl::Create (*ast, cxx_record_decl, - DeclarationNameInfo (ast_context->DeclarationNames.getCXXDestructorName (ast_context->getCanonicalType (record_qual_type)), SourceLocation()), + DeclarationNameInfo (ast->DeclarationNames.getCXXDestructorName (ast->getCanonicalType (record_qual_type)), SourceLocation()), method_qual_type, NULL, is_inline, is_implicitly_declared); } - else if (decl_name == record_decl->getDeclName()) + else if (decl_name == cxx_record_decl->getDeclName()) { - cxx_method_decl = CXXConstructorDecl::Create (*ast_context, + cxx_method_decl = CXXConstructorDecl::Create (*ast, cxx_record_decl, - DeclarationNameInfo (ast_context->DeclarationNames.getCXXConstructorName (ast_context->getCanonicalType (record_qual_type)), SourceLocation()), + DeclarationNameInfo (ast->DeclarationNames.getCXXConstructorName (ast->getCanonicalType (record_qual_type)), SourceLocation()), method_qual_type, NULL, // TypeSourceInfo * is_explicit, @@ -1186,9 +1397,9 @@ { if (op_kind != NUM_OVERLOADED_OPERATORS) { - cxx_method_decl = CXXMethodDecl::Create (*ast_context, + cxx_method_decl = CXXMethodDecl::Create (*ast, cxx_record_decl, - DeclarationNameInfo (ast_context->DeclarationNames.getCXXOperatorName (op_kind), SourceLocation()), + DeclarationNameInfo (ast->DeclarationNames.getCXXOperatorName (op_kind), SourceLocation()), method_qual_type, NULL, // TypeSourceInfo * is_static, @@ -1198,9 +1409,9 @@ else if (num_params == 0) { // Conversion operators don't take params... - cxx_method_decl = CXXConversionDecl::Create (*ast_context, + cxx_method_decl = CXXConversionDecl::Create (*ast, cxx_record_decl, - DeclarationNameInfo (ast_context->DeclarationNames.getCXXConversionFunctionName (ast_context->getCanonicalType (function_Type->getResultType())), SourceLocation()), + DeclarationNameInfo (ast->DeclarationNames.getCXXConversionFunctionName (ast->getCanonicalType (function_Type->getResultType())), SourceLocation()), method_qual_type, NULL, // TypeSourceInfo * is_inline, @@ -1210,7 +1421,7 @@ if (cxx_method_decl == NULL) { - cxx_method_decl = CXXMethodDecl::Create (*ast_context, + cxx_method_decl = CXXMethodDecl::Create (*ast, cxx_record_decl, DeclarationNameInfo (decl_name, SourceLocation()), method_qual_type, @@ -1234,7 +1445,7 @@ param_index < num_params; ++param_index) { - params[param_index] = ParmVarDecl::Create (*ast_context, + params[param_index] = ParmVarDecl::Create (*ast, cxx_method_decl, SourceLocation(), NULL, // anonymous @@ -1255,7 +1466,7 @@ bool ClangASTContext::AddFieldToRecordType ( - ASTContext *ast_context, + ASTContext *ast, clang_type_t record_clang_type, const char *name, clang_type_t field_type, @@ -1266,9 +1477,9 @@ if (record_clang_type == NULL || field_type == NULL) return false; - IdentifierTable *identifier_table = &ast_context->Idents; + IdentifierTable *identifier_table = &ast->Idents; - assert (ast_context != NULL); + assert (ast != NULL); assert (identifier_table != NULL); QualType record_qual_type(QualType::getFromOpaquePtr(record_clang_type)); @@ -1285,10 +1496,10 @@ clang::Expr *bit_width = NULL; if (bitfield_bit_size != 0) { - APInt bitfield_bit_size_apint(ast_context->getTypeSize(ast_context->IntTy), bitfield_bit_size); - bit_width = new (*ast_context)IntegerLiteral (*ast_context, bitfield_bit_size_apint, ast_context->IntTy, SourceLocation()); + APInt bitfield_bit_size_apint(ast->getTypeSize(ast->IntTy), bitfield_bit_size); + bit_width = new (*ast)IntegerLiteral (*ast, bitfield_bit_size_apint, ast->IntTy, SourceLocation()); } - FieldDecl *field = FieldDecl::Create (*ast_context, + FieldDecl *field = FieldDecl::Create (*ast, record_decl, SourceLocation(), name ? &identifier_table->get(name) : NULL, // Identifier @@ -1310,7 +1521,7 @@ if (objc_class_type) { bool is_synthesized = false; - ClangASTContext::AddObjCClassIVar (ast_context, + ClangASTContext::AddObjCClassIVar (ast, record_clang_type, name, field_type, @@ -1332,12 +1543,12 @@ bool ClangASTContext::FieldIsBitfield ( - ASTContext *ast_context, + ASTContext *ast, FieldDecl* field, uint32_t& bitfield_bit_size ) { - if (ast_context == NULL || field == NULL) + if (ast == NULL || field == NULL) return false; if (field->isBitField()) @@ -1346,7 +1557,7 @@ if (bit_width_expr) { llvm::APSInt bit_width_apsint; - if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, *ast_context)) + if (bit_width_expr->isIntegerConstantExpr(bit_width_apsint, *ast)) { bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX); return true; @@ -1383,30 +1594,27 @@ } void -ClangASTContext::SetDefaultAccessForRecordFields (clang_type_t clang_qual_type, int default_accessibility, int *assigned_accessibilities, size_t num_assigned_accessibilities) +ClangASTContext::SetDefaultAccessForRecordFields (clang_type_t clang_type, int default_accessibility, int *assigned_accessibilities, size_t num_assigned_accessibilities) { - if (clang_qual_type) + if (clang_type) { - QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type)); - clang::Type *clang_type = qual_type.getTypePtr(); - if (clang_type) + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); + + RecordType *record_type = dyn_cast(qual_type.getTypePtr()); + if (record_type) { - RecordType *record_type = dyn_cast(clang_type); - if (record_type) + RecordDecl *record_decl = record_type->getDecl(); + if (record_decl) { - RecordDecl *record_decl = record_type->getDecl(); - if (record_decl) + uint32_t field_idx; + RecordDecl::field_iterator field, field_end; + for (field = record_decl->field_begin(), field_end = record_decl->field_end(), field_idx = 0; + field != field_end; + ++field, ++field_idx) { - uint32_t field_idx; - RecordDecl::field_iterator field, field_end; - for (field = record_decl->field_begin(), field_end = record_decl->field_end(), field_idx = 0; - field != field_end; - ++field, ++field_idx) - { - // If no accessibility was assigned, assign the correct one - if (field_idx < num_assigned_accessibilities && assigned_accessibilities[field_idx] == clang::AS_none) - field->setAccess ((AccessSpecifier)default_accessibility); - } + // If no accessibility was assigned, assign the correct one + if (field_idx < num_assigned_accessibilities && assigned_accessibilities[field_idx] == clang::AS_none) + field->setAccess ((AccessSpecifier)default_accessibility); } } } @@ -1442,19 +1650,11 @@ { if (class_clang_type) { - clang::Type *clang_type = QualType::getFromOpaquePtr(class_clang_type).getTypePtr(); - if (clang_type) + CXXRecordDecl *cxx_record_decl = QualType::getFromOpaquePtr(class_clang_type)->getAsCXXRecordDecl(); + if (cxx_record_decl) { - RecordType *record_type = dyn_cast(clang_type); - if (record_type) - { - CXXRecordDecl *cxx_record_decl = dyn_cast(record_type->getDecl()); - if (cxx_record_decl) - { - cxx_record_decl->setBases(base_classes, num_base_classes); - return true; - } - } + cxx_record_decl->setBases(base_classes, num_base_classes); + return true; } } return false; @@ -1470,26 +1670,26 @@ bool isInternal ) { - ASTContext *ast_context = getASTContext(); - assert (ast_context != NULL); + ASTContext *ast = getASTContext(); + assert (ast != NULL); assert (name && name[0]); if (decl_ctx == NULL) - decl_ctx = ast_context->getTranslationUnitDecl(); + decl_ctx = ast->getTranslationUnitDecl(); // NOTE: Eventually CXXRecordDecl will be merged back into RecordDecl and // we will need to update this code. I was told to currently always use // the CXXRecordDecl class since we often don't know from debug information // if something is struct or a class, so we default to always use the more // complete definition just in case. - ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create (*ast_context, + ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create (*ast, decl_ctx, SourceLocation(), - &ast_context->Idents.get(name), + &ast->Idents.get(name), SourceLocation(), isForwardDecl, isInternal); - return ast_context->getObjCInterfaceType(decl).getAsOpaquePtr(); + return ast->getObjCInterfaceType(decl).getAsOpaquePtr(); } bool @@ -1524,7 +1724,7 @@ bool ClangASTContext::AddObjCClassIVar ( - ASTContext *ast_context, + ASTContext *ast, clang_type_t class_opaque_type, const char *name, clang_type_t ivar_opaque_type, @@ -1536,9 +1736,9 @@ if (class_opaque_type == NULL || ivar_opaque_type == NULL) return false; - IdentifierTable *identifier_table = &ast_context->Idents; + IdentifierTable *identifier_table = &ast->Idents; - assert (ast_context != NULL); + assert (ast != NULL); assert (identifier_table != NULL); QualType class_qual_type(QualType::getFromOpaquePtr(class_opaque_type)); @@ -1557,11 +1757,11 @@ clang::Expr *bit_width = NULL; if (bitfield_bit_size != 0) { - APInt bitfield_bit_size_apint(ast_context->getTypeSize(ast_context->IntTy), bitfield_bit_size); - bit_width = new (*ast_context)IntegerLiteral (*ast_context, bitfield_bit_size_apint, ast_context->IntTy, SourceLocation()); + APInt bitfield_bit_size_apint(ast->getTypeSize(ast->IntTy), bitfield_bit_size); + bit_width = new (*ast)IntegerLiteral (*ast, bitfield_bit_size_apint, ast->IntTy, SourceLocation()); } - ObjCIvarDecl *field = ObjCIvarDecl::Create (*ast_context, + ObjCIvarDecl *field = ObjCIvarDecl::Create (*ast, class_interface_decl, SourceLocation(), &identifier_table->get(name), // Identifier @@ -1618,7 +1818,7 @@ ObjCMethodDecl * ClangASTContext::AddMethodToObjCObjectType ( - ASTContext *ast_context, + ASTContext *ast, clang_type_t class_opaque_type, const char *name, // the full symbol name as seen in the symbol table ("-[NString stringWithCString:]") clang_type_t method_opaque_type, @@ -1628,9 +1828,9 @@ if (class_opaque_type == NULL || method_opaque_type == NULL) return NULL; - IdentifierTable *identifier_table = &ast_context->Idents; + IdentifierTable *identifier_table = &ast->Idents; - assert (ast_context != NULL); + assert (ast != NULL); assert (identifier_table != NULL); QualType class_qual_type(QualType::getFromOpaquePtr(class_opaque_type)); @@ -1680,7 +1880,7 @@ if (selector_idents.size() == 0) return 0; - clang::Selector method_selector = ast_context->Selectors.getSelector (num_selectors_with_args ? selector_idents.size() : 0, + clang::Selector method_selector = ast->Selectors.getSelector (num_selectors_with_args ? selector_idents.size() : 0, selector_idents.data()); QualType method_qual_type (QualType::getFromOpaquePtr (method_opaque_type)); @@ -1704,7 +1904,7 @@ const unsigned num_args = method_function_prototype->getNumArgs(); - ObjCMethodDecl *objc_method_decl = ObjCMethodDecl::Create (*ast_context, + ObjCMethodDecl *objc_method_decl = ObjCMethodDecl::Create (*ast, SourceLocation(), // beginLoc, SourceLocation(), // endLoc, method_selector, @@ -1728,7 +1928,7 @@ for (int param_index = 0; param_index < num_args; ++param_index) { - params.push_back (ParmVarDecl::Create (*ast_context, + params.push_back (ParmVarDecl::Create (*ast, objc_method_decl, SourceLocation(), NULL, // anonymous @@ -1739,7 +1939,7 @@ NULL)); } - objc_method_decl->setMethodParams(*ast_context, params.data(), params.size(), num_args); + objc_method_decl->setMethodParams(*ast, params.data(), params.size(), num_args); } class_interface_decl->addDecl (objc_method_decl); @@ -1753,7 +1953,7 @@ ClangASTContext::GetTypeInfo ( clang_type_t clang_type, - clang::ASTContext *ast_context, + clang::ASTContext *ast, clang_type_t *pointee_or_element_clang_type ) { @@ -1773,8 +1973,8 @@ { case clang::BuiltinType::ObjCId: case clang::BuiltinType::ObjCClass: - if (ast_context && pointee_or_element_clang_type) - *pointee_or_element_clang_type = ast_context->ObjCBuiltinClassTy.getAsOpaquePtr(); + if (ast && pointee_or_element_clang_type) + *pointee_or_element_clang_type = ast->ObjCBuiltinClassTy.getAsOpaquePtr(); return eTypeIsBuiltIn | eTypeIsPointer | eTypeHasValue; default: @@ -1846,7 +2046,7 @@ case clang::Type::Typedef: return eTypeIsTypedef | ClangASTContext::GetTypeInfo (cast(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), - ast_context, + ast, pointee_or_element_clang_type); case clang::Type::TypeOfExpr: return 0; @@ -1893,13 +2093,13 @@ } uint32_t -ClangASTContext::GetNumChildren (clang_type_t clang_qual_type, bool omit_empty_base_classes) +ClangASTContext::GetNumChildren (clang::ASTContext *ast, clang_type_t clang_type, bool omit_empty_base_classes) { - if (clang_qual_type == NULL) + if (clang_type == NULL) return 0; uint32_t num_children = 0; - QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type)); + QualType qual_type(QualType::getFromOpaquePtr(clang_type)); const clang::Type::TypeClass type_class = qual_type->getTypeClass(); switch (type_class) { @@ -1919,7 +2119,7 @@ case clang::Type::Complex: return 0; case clang::Type::Record: - if (ClangASTType::IsDefined (clang_qual_type)) + if (ClangASTContext::GetCompleteType (ast, clang_type)) { const RecordType *record_type = cast(qual_type.getTypePtr()); const RecordDecl *record_decl = record_type->getDecl(); @@ -1994,7 +2194,8 @@ { ObjCObjectPointerType *pointer_type = cast(qual_type.getTypePtr()); QualType pointee_type = pointer_type->getPointeeType(); - uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(), + uint32_t num_pointee_children = ClangASTContext::GetNumChildren (ast, + pointee_type.getAsOpaquePtr(), omit_empty_base_classes); // If this type points to a simple type, then it has 1 child if (num_pointee_children == 0) @@ -2012,7 +2213,8 @@ { PointerType *pointer_type = cast(qual_type.getTypePtr()); QualType pointee_type (pointer_type->getPointeeType()); - uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(), + uint32_t num_pointee_children = ClangASTContext::GetNumChildren (ast, + pointee_type.getAsOpaquePtr(), omit_empty_base_classes); if (num_pointee_children == 0) { @@ -2030,7 +2232,8 @@ { ReferenceType *reference_type = cast(qual_type.getTypePtr()); QualType pointee_type = reference_type->getPointeeType(); - uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(), + uint32_t num_pointee_children = ClangASTContext::GetNumChildren (ast, + pointee_type.getAsOpaquePtr(), omit_empty_base_classes); // If this type points to a simple type, then it has 1 child if (num_pointee_children == 0) @@ -2042,7 +2245,9 @@ case clang::Type::Typedef: - num_children = ClangASTContext::GetNumChildren (cast(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), omit_empty_base_classes); + num_children = ClangASTContext::GetNumChildren (ast, + cast(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), + omit_empty_base_classes); break; default: @@ -2178,7 +2383,7 @@ clang_type_t ClangASTContext::GetChildClangTypeAtIndex ( - ASTContext *ast_context, + ASTContext *ast, const char *parent_name, clang_type_t parent_clang_type, uint32_t idx, @@ -2195,7 +2400,7 @@ if (parent_clang_type == NULL) return NULL; - if (idx < ClangASTContext::GetNumChildren (parent_clang_type, omit_empty_base_classes)) + if (idx < ClangASTContext::GetNumChildren (ast, parent_clang_type, omit_empty_base_classes)) { uint32_t bit_offset; child_bitfield_bit_size = 0; @@ -2211,21 +2416,21 @@ case clang::BuiltinType::ObjCId: case clang::BuiltinType::ObjCClass: child_name = "isa"; - child_byte_size = ast_context->getTypeSize(ast_context->ObjCBuiltinClassTy) / CHAR_BIT; - return ast_context->ObjCBuiltinClassTy.getAsOpaquePtr(); + child_byte_size = ast->getTypeSize(ast->ObjCBuiltinClassTy) / CHAR_BIT; + return ast->ObjCBuiltinClassTy.getAsOpaquePtr(); default: break; } break; - case clang::Type::Record: + if (ClangASTContext::GetCompleteType (ast, parent_clang_type)) { const RecordType *record_type = cast(parent_qual_type.getTypePtr()); const RecordDecl *record_decl = record_type->getDecl(); assert(record_decl); - const ASTRecordLayout &record_layout = ast_context->getASTRecordLayout(record_decl); + const ASTRecordLayout &record_layout = ast->getASTRecordLayout(record_decl); uint32_t child_idx = 0; const CXXRecordDecl *cxx_record_decl = dyn_cast(record_decl); @@ -2265,7 +2470,7 @@ child_name.assign(base_class_type_name.c_str()); - uint64_t clang_type_info_bit_size = ast_context->getTypeSize(base_class->getType()); + uint64_t clang_type_info_bit_size = ast->getTypeSize(base_class->getType()); // Base classes biut sizes should be a multiple of 8 bits in size assert (clang_type_info_bit_size % 8 == 0); @@ -2291,7 +2496,7 @@ // Figure out the type byte size (field_type_info.first) and // alignment (field_type_info.second) from the AST context. - std::pair field_type_info = ast_context->getTypeInfo(field->getType()); + std::pair field_type_info = ast->getTypeInfo(field->getType()); assert(field_idx < record_layout.getFieldCount()); child_byte_size = field_type_info.first / 8; @@ -2299,7 +2504,7 @@ // Figure out the field offset within the current struct/union/class type bit_offset = record_layout.getFieldOffset (field_idx); child_byte_offset = bit_offset / 8; - if (ClangASTContext::FieldIsBitfield (ast_context, *field, child_bitfield_bit_size)) + if (ClangASTContext::FieldIsBitfield (ast, *field, child_bitfield_bit_size)) child_bitfield_bit_offset = bit_offset % 8; return field->getType().getAsOpaquePtr(); @@ -2321,22 +2526,22 @@ if (class_interface_decl) { - const ASTRecordLayout &interface_layout = ast_context->getASTObjCInterfaceLayout(class_interface_decl); + const ASTRecordLayout &interface_layout = ast->getASTObjCInterfaceLayout(class_interface_decl); ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); if (superclass_interface_decl) { if (omit_empty_base_classes) { - if (ClangASTContext::GetNumChildren(ast_context->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(), omit_empty_base_classes) > 0) + if (ClangASTContext::GetNumChildren(ast, ast->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(), omit_empty_base_classes) > 0) { if (idx == 0) { - QualType ivar_qual_type(ast_context->getObjCInterfaceType(superclass_interface_decl)); + QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl)); child_name.assign(superclass_interface_decl->getNameAsString().c_str()); - std::pair ivar_type_info = ast_context->getTypeInfo(ivar_qual_type.getTypePtr()); + std::pair ivar_type_info = ast->getTypeInfo(ivar_qual_type.getTypePtr()); child_byte_size = ivar_type_info.first / 8; child_byte_offset = 0; @@ -2368,7 +2573,7 @@ child_name.assign(ivar_decl->getNameAsString().c_str()); - std::pair ivar_type_info = ast_context->getTypeInfo(ivar_qual_type.getTypePtr()); + std::pair ivar_type_info = ast->getTypeInfo(ivar_qual_type.getTypePtr()); child_byte_size = ivar_type_info.first / 8; @@ -2393,7 +2598,7 @@ if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) { - return GetChildClangTypeAtIndex (ast_context, + return GetChildClangTypeAtIndex (ast, parent_name, pointer_type->getPointeeType().getAsOpaquePtr(), idx, @@ -2417,7 +2622,7 @@ // We have a pointer to an simple type if (idx == 0) { - std::pair clang_type_info = ast_context->getTypeInfo(pointee_type); + std::pair clang_type_info = ast->getTypeInfo(pointee_type); assert(clang_type_info.first % 8 == 0); child_byte_size = clang_type_info.first / 8; child_byte_offset = 0; @@ -2434,16 +2639,19 @@ if (idx < element_count) { - std::pair field_type_info = ast_context->getTypeInfo(array->getElementType()); + if (GetCompleteQualType (ast, array->getElementType())) + { + std::pair field_type_info = ast->getTypeInfo(array->getElementType()); - char element_name[64]; - ::snprintf (element_name, sizeof (element_name), "[%u]", idx); + char element_name[64]; + ::snprintf (element_name, sizeof (element_name), "[%u]", idx); - child_name.assign(element_name); - assert(field_type_info.first % 8 == 0); - child_byte_size = field_type_info.first / 8; - child_byte_offset = idx * child_byte_size; - return array->getElementType().getAsOpaquePtr(); + child_name.assign(element_name); + assert(field_type_info.first % 8 == 0); + child_byte_size = field_type_info.first / 8; + child_byte_offset = idx * child_byte_size; + return array->getElementType().getAsOpaquePtr(); + } } } break; @@ -2459,7 +2667,7 @@ if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) { - return GetChildClangTypeAtIndex (ast_context, + return GetChildClangTypeAtIndex (ast, parent_name, pointer_type->getPointeeType().getAsOpaquePtr(), idx, @@ -2483,7 +2691,7 @@ // We have a pointer to an simple type if (idx == 0) { - std::pair clang_type_info = ast_context->getTypeInfo(pointee_type); + std::pair clang_type_info = ast->getTypeInfo(pointee_type); assert(clang_type_info.first % 8 == 0); child_byte_size = clang_type_info.first / 8; child_byte_offset = 0; @@ -2501,7 +2709,7 @@ clang_type_t pointee_clang_type = pointee_type.getAsOpaquePtr(); if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_clang_type)) { - return GetChildClangTypeAtIndex (ast_context, + return GetChildClangTypeAtIndex (ast, parent_name, pointee_clang_type, idx, @@ -2525,7 +2733,7 @@ // We have a pointer to an simple type if (idx == 0) { - std::pair clang_type_info = ast_context->getTypeInfo(pointee_type); + std::pair clang_type_info = ast->getTypeInfo(pointee_type); assert(clang_type_info.first % 8 == 0); child_byte_size = clang_type_info.first / 8; child_byte_offset = 0; @@ -2536,7 +2744,7 @@ break; case clang::Type::Typedef: - return GetChildClangTypeAtIndex (ast_context, + return GetChildClangTypeAtIndex (ast, parent_name, cast(parent_qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), idx, @@ -2560,7 +2768,7 @@ static inline bool BaseSpecifierIsEmpty (const CXXBaseSpecifier *b) { - return ClangASTContext::RecordHasFields(cast(b->getType()->getAs()->getDecl())) == false; + return ClangASTContext::RecordHasFields(b->getType()->getAsCXXRecordDecl()) == false; } static uint32_t @@ -2734,7 +2942,7 @@ size_t ClangASTContext::GetIndexOfChildMemberWithName ( - ASTContext *ast_context, + ASTContext *ast, clang_type_t clang_type, const char *name, bool omit_empty_base_classes, @@ -2748,6 +2956,7 @@ switch (type_class) { case clang::Type::Record: + if (ClangASTContext::GetCompleteType (ast, clang_type)) { const RecordType *record_type = cast(qual_type.getTypePtr()); const RecordDecl *record_decl = record_type->getDecl(); @@ -2780,7 +2989,7 @@ //const Decl *root_cdecl = cxx_record_decl->getCanonicalDecl(); // Didn't find things easily, lets let clang do its thang... - IdentifierInfo & ident_ref = ast_context->Idents.get(name, name + strlen (name)); + IdentifierInfo & ident_ref = ast->Idents.get(name, name + strlen (name)); DeclarationName decl_name(&ident_ref); CXXBasePaths paths; @@ -2872,8 +3081,8 @@ // an ivar in our superclass... child_indexes.push_back (0); - if (GetIndexOfChildMemberWithName (ast_context, - ast_context->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(), + if (GetIndexOfChildMemberWithName (ast, + ast->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(), name, omit_empty_base_classes, child_indexes)) @@ -2895,7 +3104,7 @@ case clang::Type::ObjCObjectPointer: { - return GetIndexOfChildMemberWithName (ast_context, + return GetIndexOfChildMemberWithName (ast, cast(qual_type.getTypePtr())->getPointeeType().getAsOpaquePtr(), name, omit_empty_base_classes, @@ -2911,7 +3120,7 @@ // // if (idx < element_count) // { -// std::pair field_type_info = ast_context->getTypeInfo(array->getElementType()); +// std::pair field_type_info = ast->getTypeInfo(array->getElementType()); // // char element_name[32]; // ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); @@ -2932,7 +3141,7 @@ // // if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) // { -// return GetIndexOfChildWithName (ast_context, +// return GetIndexOfChildWithName (ast, // mem_ptr_type->getPointeeType().getAsOpaquePtr(), // name); // } @@ -2947,7 +3156,7 @@ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) { - return GetIndexOfChildMemberWithName (ast_context, + return GetIndexOfChildMemberWithName (ast, reference_type->getPointeeType().getAsOpaquePtr(), name, omit_empty_base_classes, @@ -2963,7 +3172,7 @@ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) { - return GetIndexOfChildMemberWithName (ast_context, + return GetIndexOfChildMemberWithName (ast, pointer_type->getPointeeType().getAsOpaquePtr(), name, omit_empty_base_classes, @@ -2980,7 +3189,7 @@ // // We have a pointer to an simple type // if (idx == 0) // { -// std::pair clang_type_info = ast_context->getTypeInfo(pointee_type); +// std::pair clang_type_info = ast->getTypeInfo(pointee_type); // assert(clang_type_info.first % 8 == 0); // child_byte_size = clang_type_info.first / 8; // child_byte_offset = 0; @@ -2991,7 +3200,7 @@ break; case clang::Type::Typedef: - return GetIndexOfChildMemberWithName (ast_context, + return GetIndexOfChildMemberWithName (ast, cast(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), name, omit_empty_base_classes, @@ -3012,7 +3221,7 @@ uint32_t ClangASTContext::GetIndexOfChildWithName ( - ASTContext *ast_context, + ASTContext *ast, clang_type_t clang_type, const char *name, bool omit_empty_base_classes @@ -3027,6 +3236,7 @@ switch (type_class) { case clang::Type::Record: + if (ClangASTContext::GetCompleteType (ast, clang_type)) { const RecordType *record_type = cast(qual_type.getTypePtr()); const RecordDecl *record_decl = record_type->getDecl(); @@ -3110,7 +3320,7 @@ case clang::Type::ObjCObjectPointer: { - return GetIndexOfChildWithName (ast_context, + return GetIndexOfChildWithName (ast, cast(qual_type.getTypePtr())->getPointeeType().getAsOpaquePtr(), name, omit_empty_base_classes); @@ -3124,7 +3334,7 @@ // // if (idx < element_count) // { -// std::pair field_type_info = ast_context->getTypeInfo(array->getElementType()); +// std::pair field_type_info = ast->getTypeInfo(array->getElementType()); // // char element_name[32]; // ::snprintf (element_name, sizeof (element_name), "%s[%u]", parent_name ? parent_name : "", idx); @@ -3145,7 +3355,7 @@ // // if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) // { -// return GetIndexOfChildWithName (ast_context, +// return GetIndexOfChildWithName (ast, // mem_ptr_type->getPointeeType().getAsOpaquePtr(), // name); // } @@ -3160,7 +3370,7 @@ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) { - return GetIndexOfChildWithName (ast_context, + return GetIndexOfChildWithName (ast, reference_type->getPointeeType().getAsOpaquePtr(), name, omit_empty_base_classes); @@ -3175,7 +3385,7 @@ if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr())) { - return GetIndexOfChildWithName (ast_context, + return GetIndexOfChildWithName (ast, pointer_type->getPointeeType().getAsOpaquePtr(), name, omit_empty_base_classes); @@ -3191,7 +3401,7 @@ // // We have a pointer to an simple type // if (idx == 0) // { -// std::pair clang_type_info = ast_context->getTypeInfo(pointee_type); +// std::pair clang_type_info = ast->getTypeInfo(pointee_type); // assert(clang_type_info.first % 8 == 0); // child_byte_size = clang_type_info.first / 8; // child_byte_offset = 0; @@ -3202,7 +3412,7 @@ break; case clang::Type::Typedef: - return GetIndexOfChildWithName (ast_context, + return GetIndexOfChildWithName (ast, cast(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), name, omit_empty_base_classes); @@ -3293,10 +3503,10 @@ // like maybe filling in the SourceLocation with it... if (name) { - ASTContext *ast_context = getASTContext(); + ASTContext *ast = getASTContext(); if (decl_ctx == NULL) - decl_ctx = ast_context->getTranslationUnitDecl(); - return NamespaceDecl::Create(*ast_context, decl_ctx, SourceLocation(), &ast_context->Idents.get(name)); + decl_ctx = ast->getTranslationUnitDecl(); + return NamespaceDecl::Create(*ast, decl_ctx, SourceLocation(), &ast->Idents.get(name)); } return NULL; } @@ -3309,15 +3519,15 @@ { if (name) { - ASTContext *ast_context = getASTContext(); - assert (ast_context != NULL); + ASTContext *ast = getASTContext(); + assert (ast != NULL); if (name && name[0]) { - return FunctionDecl::Create(*ast_context, - ast_context->getTranslationUnitDecl(), + return FunctionDecl::Create(*ast, + ast->getTranslationUnitDecl(), SourceLocation(), - DeclarationName (&ast_context->Idents.get(name)), + DeclarationName (&ast->Idents.get(name)), QualType::getFromOpaquePtr(function_clang_type), NULL, (FunctionDecl::StorageClass)storage, @@ -3326,8 +3536,8 @@ } else { - return FunctionDecl::Create(*ast_context, - ast_context->getTranslationUnitDecl(), + return FunctionDecl::Create(*ast, + ast->getTranslationUnitDecl(), SourceLocation(), DeclarationName (), QualType::getFromOpaquePtr(function_clang_type), @@ -3341,20 +3551,20 @@ } clang_type_t -ClangASTContext::CreateFunctionType (ASTContext *ast_context, +ClangASTContext::CreateFunctionType (ASTContext *ast, clang_type_t result_type, clang_type_t *args, unsigned num_args, bool is_variadic, unsigned type_quals) { - assert (ast_context != NULL); + assert (ast != NULL); std::vector qual_type_args; for (unsigned i=0; igetFunctionType(QualType::getFromOpaquePtr(result_type), + return ast->getFunctionType(QualType::getFromOpaquePtr(result_type), qual_type_args.empty() ? NULL : &qual_type_args.front(), qual_type_args.size(), is_variadic, @@ -3369,12 +3579,12 @@ ParmVarDecl * ClangASTContext::CreateParameterDeclaration (const char *name, clang_type_t param_type, int storage) { - ASTContext *ast_context = getASTContext(); - assert (ast_context != NULL); - return ParmVarDecl::Create(*ast_context, - ast_context->getTranslationUnitDecl(), + ASTContext *ast = getASTContext(); + assert (ast != NULL); + return ParmVarDecl::Create(*ast, + ast->getTranslationUnitDecl(), SourceLocation(), - name && name[0] ? &ast_context->Idents.get(name) : NULL, + name && name[0] ? &ast->Idents.get(name) : NULL, QualType::getFromOpaquePtr(param_type), NULL, (VarDecl::StorageClass)storage, @@ -3397,10 +3607,10 @@ { if (element_type) { - ASTContext *ast_context = getASTContext(); - assert (ast_context != NULL); + ASTContext *ast = getASTContext(); + assert (ast != NULL); llvm::APInt ap_element_count (64, element_count); - return ast_context->getConstantArrayType(QualType::getFromOpaquePtr(element_type), + return ast->getConstantArrayType(QualType::getFromOpaquePtr(element_type), ap_element_count, ArrayType::Normal, 0).getAsOpaquePtr(); // ElemQuals @@ -3473,17 +3683,17 @@ unsigned NumPositiveBits = 1; unsigned NumNegativeBits = 0; - ASTContext *ast_context = getASTContext(); + ASTContext *ast = getASTContext(); QualType promotion_qual_type; // If the enum integer type is less than an integer in bit width, // then we must promote it to an integer size. - if (ast_context->getTypeSize(enum_decl->getIntegerType()) < ast_context->getTypeSize(ast_context->IntTy)) + if (ast->getTypeSize(enum_decl->getIntegerType()) < ast->getTypeSize(ast->IntTy)) { if (enum_decl->getIntegerType()->isSignedIntegerType()) - promotion_qual_type = ast_context->IntTy; + promotion_qual_type = ast->IntTy; else - promotion_qual_type = ast_context->UnsignedIntTy; + promotion_qual_type = ast->UnsignedIntTy; } else promotion_qual_type = enum_decl->getIntegerType(); @@ -3510,17 +3720,17 @@ { // TODO: Do something intelligent with the Declaration object passed in // like maybe filling in the SourceLocation with it... - ASTContext *ast_context = getASTContext(); - assert (ast_context != NULL); + ASTContext *ast = getASTContext(); + assert (ast != NULL); // TODO: ask about these... // const bool IsScoped = false; // const bool IsFixed = false; - EnumDecl *enum_decl = EnumDecl::Create (*ast_context, + EnumDecl *enum_decl = EnumDecl::Create (*ast, decl_ctx, SourceLocation(), - name && name[0] ? &ast_context->Idents.get(name) : NULL, + name && name[0] ? &ast->Idents.get(name) : NULL, SourceLocation(), NULL, false, // IsScoped @@ -3530,7 +3740,7 @@ { // TODO: check if we should be setting the promotion type too? enum_decl->setIntegerType(QualType::getFromOpaquePtr (integer_qual_type)); - return ast_context->getTagDeclType(enum_decl).getAsOpaquePtr(); + return ast->getTagDeclType(enum_decl).getAsOpaquePtr(); } return NULL; } @@ -3568,10 +3778,10 @@ { // TODO: Do something intelligent with the Declaration object passed in // like maybe filling in the SourceLocation with it... - ASTContext *ast_context = getASTContext(); + ASTContext *ast = getASTContext(); IdentifierTable *identifier_table = getIdentifierTable(); - assert (ast_context != NULL); + assert (ast != NULL); assert (identifier_table != NULL); QualType enum_qual_type (QualType::getFromOpaquePtr(enum_clang_type)); @@ -3585,14 +3795,14 @@ llvm::APSInt enum_llvm_apsint(enum_value_bit_size, false); enum_llvm_apsint = enum_value; EnumConstantDecl *enumerator_decl = - EnumConstantDecl::Create(*ast_context, - enum_type->getDecl(), - SourceLocation(), - name ? &identifier_table->get(name) : NULL, // Identifier - QualType::getFromOpaquePtr(enumerator_clang_type), - NULL, - enum_llvm_apsint); - + EnumConstantDecl::Create (*ast, + enum_type->getDecl(), + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + QualType::getFromOpaquePtr(enumerator_clang_type), + NULL, + enum_llvm_apsint); + if (enumerator_decl) { enum_type->getDecl()->addDecl(enumerator_decl); @@ -3663,8 +3873,8 @@ size_t ClangASTContext::GetPointerBitSize () { - ASTContext *ast_context = getASTContext(); - return ast_context->getTypeSize(ast_context->VoidPtrTy); + ASTContext *ast = getASTContext(); + return ast->getTypeSize(ast->VoidPtrTy); } bool @@ -3997,20 +4207,20 @@ if (clang_type) { QualType qual_type (QualType::getFromOpaquePtr(clang_type)); - ASTContext *ast_context = getASTContext(); + ASTContext *ast = getASTContext(); IdentifierTable *identifier_table = getIdentifierTable(); - assert (ast_context != NULL); + assert (ast != NULL); assert (identifier_table != NULL); if (decl_ctx == NULL) - decl_ctx = ast_context->getTranslationUnitDecl(); - TypedefDecl *decl = TypedefDecl::Create(*ast_context, - decl_ctx, - SourceLocation(), - name ? &identifier_table->get(name) : NULL, // Identifier - ast_context->CreateTypeSourceInfo(qual_type)); + decl_ctx = ast->getTranslationUnitDecl(); + TypedefDecl *decl = TypedefDecl::Create (*ast, + decl_ctx, + SourceLocation(), + name ? &identifier_table->get(name) : NULL, // Identifier + ast->CreateTypeSourceInfo(qual_type)); // Get a uniqued QualType for the typedef decl type - return ast_context->getTypedefType (decl).getAsOpaquePtr(); + return ast->getTypedefType (decl).getAsOpaquePtr(); } return NULL; } @@ -4044,7 +4254,7 @@ // so we can support remote targets. The code below also requires a patch to // llvm::APInt. //bool -//ClangASTContext::ConvertFloatValueToString (ASTContext *ast_context, clang_type_t clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str) +//ClangASTContext::ConvertFloatValueToString (ASTContext *ast, clang_type_t clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str) //{ // uint32_t count = 0; // bool is_complex = false; @@ -4079,7 +4289,7 @@ //} size_t -ClangASTContext::ConvertStringToFloatValue (ASTContext *ast_context, clang_type_t clang_type, const char *s, uint8_t *dst, size_t dst_size) +ClangASTContext::ConvertStringToFloatValue (ASTContext *ast, clang_type_t clang_type, const char *s, uint8_t *dst, size_t dst_size) { if (clang_type) { @@ -4093,9 +4303,9 @@ return false; StringRef s_sref(s); - APFloat ap_float(ast_context->getFloatTypeSemantics(qual_type), s_sref); + APFloat ap_float(ast->getFloatTypeSemantics(qual_type), s_sref); - const uint64_t bit_size = ast_context->getTypeSize (qual_type); + const uint64_t bit_size = ast->getTypeSize (qual_type); const uint64_t byte_size = bit_size / 8; if (dst_size >= byte_size) { @@ -4126,3 +4336,21 @@ return qual_type.getQualifiers().getCVRQualifiers(); } + +bool +ClangASTContext::GetCompleteType (clang::ASTContext *ast, lldb::clang_type_t clang_type) +{ + if (clang_type == NULL) + return false; + + clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type)); + return GetCompleteQualType (ast, qual_type); +} + + +bool +ClangASTContext::GetCompleteType (clang_type_t clang_type) +{ + return ClangASTContext::GetCompleteType (getASTContext(), clang_type); +} + Modified: lldb/trunk/source/Symbol/ClangASTType.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangASTType.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Symbol/ClangASTType.cpp (original) +++ lldb/trunk/source/Symbol/ClangASTType.cpp Sun Jan 16 21:46:26 2011 @@ -363,6 +363,7 @@ switch (qual_type->getTypeClass()) { case clang::Type::Record: + if (ClangASTContext::GetCompleteType (ast_context, clang_type)) { const clang::RecordType *record_type = cast(qual_type.getTypePtr()); const clang::RecordDecl *record_decl = record_type->getDecl(); @@ -491,6 +492,7 @@ return; case clang::Type::Enum: + if (ClangASTContext::GetCompleteType (ast_context, clang_type)) { const clang::EnumType *enum_type = cast(qual_type.getTypePtr()); const clang::EnumDecl *enum_decl = enum_type->getDecl(); @@ -690,7 +692,7 @@ case clang::Type::Enum: // If our format is enum or default, show the enumeration value as // its enumeration string value, else just display it as requested. - if (format == eFormatEnum || format == eFormatDefault) + if ((format == eFormatEnum || format == eFormatDefault) && ClangASTContext::GetCompleteType (ast_context, clang_type)) { const clang::EnumType *enum_type = cast(qual_type.getTypePtr()); const clang::EnumDecl *enum_decl = enum_type->getDecl(); Modified: lldb/trunk/source/Symbol/SymbolFile.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/SymbolFile.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Symbol/SymbolFile.cpp (original) +++ lldb/trunk/source/Symbol/SymbolFile.cpp Sun Jan 16 21:46:26 2011 @@ -18,7 +18,7 @@ SymbolFile* SymbolFile::FindPlugin (ObjectFile* obj_file) { - std::auto_ptr best_sym_file_ap; + std::auto_ptr best_symfile_ap; if (obj_file != NULL) { // TODO: Load any plug-ins in the appropriate plug-in search paths and @@ -27,7 +27,6 @@ //---------------------------------------------------------------------- // We currently only have one debug symbol parser... //---------------------------------------------------------------------- - std::auto_ptr best_symfile_ap; uint32_t best_symfile_abilities = 0; SymbolFileCreateInstance create_callback; @@ -41,16 +40,31 @@ if (sym_file_abilities > best_symfile_abilities) { best_symfile_abilities = sym_file_abilities; - best_sym_file_ap = curr_symfile_ap; + best_symfile_ap = curr_symfile_ap; } } } + if (best_symfile_ap.get()) + { + // Let the winning symbol file parser initialize itself more + // completely now that it has been chosen + best_symfile_ap->InitializeObject(); + } } - return best_sym_file_ap.release(); + return best_symfile_ap.release(); } TypeList * SymbolFile::GetTypeList () { - return m_obj_file->GetModule()->GetTypeList(); + if (m_obj_file) + return m_obj_file->GetModule()->GetTypeList(); + return NULL; +} + +lldb_private::ClangASTContext & +SymbolFile::GetClangASTContext () +{ + return m_obj_file->GetModule()->GetClangASTContext(); } + Modified: lldb/trunk/source/Symbol/SymbolVendor.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/SymbolVendor.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Symbol/SymbolVendor.cpp (original) +++ lldb/trunk/source/Symbol/SymbolVendor.cpp Sun Jan 16 21:46:26 2011 @@ -69,12 +69,6 @@ m_compile_units(), m_sym_file_ap() { - ObjectFile * objfile = module->GetObjectFile(); - ConstString target_triple; - if (objfile && objfile->GetTargetTriple(target_triple)) - { - m_type_list.GetClangASTContext().SetTargetTriple (target_triple.AsCString()); - } } //---------------------------------------------------------------------- Modified: lldb/trunk/source/Symbol/Type.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/Type.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Symbol/Type.cpp (original) +++ lldb/trunk/source/Symbol/Type.cpp Sun Jan 16 21:46:26 2011 @@ -284,7 +284,7 @@ case eEncodingIsPointerUID: case eEncodingIsLValueReferenceUID: case eEncodingIsRValueReferenceUID: - m_byte_size = GetTypeList()->GetClangASTContext().GetPointerBitSize() / 8; + m_byte_size = m_symbol_file->GetClangASTContext().GetPointerBitSize() / 8; break; } } @@ -295,10 +295,13 @@ uint32_t lldb_private::Type::GetNumChildren (bool omit_empty_base_classes) { - if (!ResolveClangType(eResolveStateFull)) - return 0; - return ClangASTContext::GetNumChildren (m_clang_type, omit_empty_base_classes); - + if (ResolveClangType(eResolveStateForward)) + { + return ClangASTContext::GetNumChildren (m_symbol_file->GetClangASTContext().getASTContext(), + m_clang_type, + omit_empty_base_classes); + } + return 0; } bool @@ -422,7 +425,6 @@ Type *encoding_type = NULL; if (m_clang_type == NULL) { - TypeList *type_list = GetTypeList(); encoding_type = GetEncodingType(); if (encoding_type) { @@ -449,22 +451,22 @@ break; case eEncodingIsTypedefUID: - m_clang_type = type_list->CreateClangTypedefType (this, encoding_type); + m_clang_type = CreateClangTypedefType (this, encoding_type); // Clear the name so it can get fully qualified in case the // typedef is in a namespace. m_name.Clear(); break; case eEncodingIsPointerUID: - m_clang_type = type_list->CreateClangPointerType (encoding_type); + m_clang_type = CreateClangPointerType (encoding_type); break; case eEncodingIsLValueReferenceUID: - m_clang_type = type_list->CreateClangLValueReferenceType (encoding_type); + m_clang_type = CreateClangLValueReferenceType (encoding_type); break; case eEncodingIsRValueReferenceUID: - m_clang_type = type_list->CreateClangRValueReferenceType (encoding_type); + m_clang_type = CreateClangRValueReferenceType (encoding_type); break; default: @@ -475,7 +477,7 @@ else { // We have no encoding type, return void? - clang_type_t void_clang_type = type_list->GetClangASTContext().GetBuiltInType_void(); + clang_type_t void_clang_type = GetClangASTContext().GetBuiltInType_void(); switch (m_encoding_uid_type) { case eEncodingIsUID: @@ -495,19 +497,19 @@ break; case eEncodingIsTypedefUID: - m_clang_type = type_list->GetClangASTContext().CreateTypedefType (m_name.AsCString(), void_clang_type, NULL); + m_clang_type = GetClangASTContext().CreateTypedefType (m_name.AsCString(), void_clang_type, NULL); break; case eEncodingIsPointerUID: - m_clang_type = type_list->GetClangASTContext().CreatePointerType (void_clang_type); + m_clang_type = GetClangASTContext().CreatePointerType (void_clang_type); break; case eEncodingIsLValueReferenceUID: - m_clang_type = type_list->GetClangASTContext().CreateLValueReferenceType (void_clang_type); + m_clang_type = GetClangASTContext().CreateLValueReferenceType (void_clang_type); break; case eEncodingIsRValueReferenceUID: - m_clang_type = type_list->GetClangASTContext().CreateRValueReferenceType (void_clang_type); + m_clang_type = GetClangASTContext().CreateRValueReferenceType (void_clang_type); break; default: @@ -636,16 +638,13 @@ clang::ASTContext * lldb_private::Type::GetClangAST () { - TypeList *type_list = GetTypeList(); - if (type_list) - return type_list->GetClangASTContext().getASTContext(); - return NULL; + return GetClangASTContext().getASTContext(); } lldb_private::ClangASTContext & lldb_private::Type::GetClangASTContext () { - return GetTypeList()->GetClangASTContext(); + return m_symbol_file->GetClangASTContext(); } int @@ -663,3 +662,35 @@ // return 0; } + +void * +lldb_private::Type::CreateClangPointerType (lldb_private::Type *type) +{ + assert(type); + return GetClangASTContext().CreatePointerType(type->GetClangForwardType()); +} + +void * +lldb_private::Type::CreateClangTypedefType (lldb_private::Type *typedef_type, lldb_private::Type *base_type) +{ + assert(typedef_type && base_type); + return GetClangASTContext().CreateTypedefType (typedef_type->GetName().AsCString(), + base_type->GetClangForwardType(), + typedef_type->GetSymbolFile()->GetClangDeclContextForTypeUID(typedef_type->GetID())); +} + +void * +lldb_private::Type::CreateClangLValueReferenceType (lldb_private::Type *type) +{ + assert(type); + return GetClangASTContext().CreateLValueReferenceType(type->GetClangForwardType()); +} + +void * +lldb_private::Type::CreateClangRValueReferenceType (lldb_private::Type *type) +{ + assert(type); + return GetClangASTContext().CreateRValueReferenceType (type->GetClangForwardType()); +} + + Modified: lldb/trunk/source/Symbol/TypeList.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/TypeList.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Symbol/TypeList.cpp (original) +++ lldb/trunk/source/Symbol/TypeList.cpp Sun Jan 16 21:46:26 2011 @@ -29,7 +29,6 @@ #include "llvm/Support/raw_ostream.h" // Project includes -#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/Type.h" @@ -39,8 +38,7 @@ using namespace lldb_private; using namespace clang; -TypeList::TypeList(const char *target_triple) : - m_ast (target_triple), +TypeList::TypeList() : m_types () { } @@ -94,18 +92,18 @@ //---------------------------------------------------------------------- // Find a type by name. //---------------------------------------------------------------------- -TypeList -TypeList::FindTypes (const ConstString &name) -{ - // Do we ever need to make a lookup by name map? Here we are doing - // a linear search which isn't going to be fast. - TypeList types(m_ast.getTargetInfo()->getTriple().getTriple().c_str()); - iterator pos, end; - for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) - if (pos->second->GetName() == name) - types.Insert (pos->second); - return types; -} +//TypeList +//TypeList::FindTypes (const ConstString &name) +//{ +// // Do we ever need to make a lookup by name map? Here we are doing +// // a linear search which isn't going to be fast. +// TypeList types(m_ast.getTargetInfo()->getTriple().getTriple().c_str()); +// iterator pos, end; +// for (pos = m_types.begin(), end = m_types.end(); pos != end; ++pos) +// if (pos->second->GetName() == name) +// types.Insert (pos->second); +// return types; +//} void TypeList::Clear() @@ -146,42 +144,35 @@ } } - -ClangASTContext & -TypeList::GetClangASTContext () -{ - return m_ast; -} - -void * -TypeList::CreateClangPointerType (Type *type) -{ - assert(type); - return m_ast.CreatePointerType(type->GetClangForwardType()); -} - -void * -TypeList::CreateClangTypedefType (Type *typedef_type, Type *base_type) -{ - assert(typedef_type && base_type); - return m_ast.CreateTypedefType (typedef_type->GetName().AsCString(), - base_type->GetClangForwardType(), - typedef_type->GetSymbolFile()->GetClangDeclContextForTypeUID(typedef_type->GetID())); -} - -void * -TypeList::CreateClangLValueReferenceType (Type *type) -{ - assert(type); - return m_ast.CreateLValueReferenceType(type->GetClangForwardType()); -} - -void * -TypeList::CreateClangRValueReferenceType (Type *type) -{ - assert(type); - return m_ast.CreateRValueReferenceType (type->GetClangForwardType()); -} - +//void * +//TypeList::CreateClangPointerType (Type *type) +//{ +// assert(type); +// return m_ast.CreatePointerType(type->GetClangForwardType()); +//} +// +//void * +//TypeList::CreateClangTypedefType (Type *typedef_type, Type *base_type) +//{ +// assert(typedef_type && base_type); +// return m_ast.CreateTypedefType (typedef_type->GetName().AsCString(), +// base_type->GetClangForwardType(), +// typedef_type->GetSymbolFile()->GetClangDeclContextForTypeUID(typedef_type->GetID())); +//} +// +//void * +//TypeList::CreateClangLValueReferenceType (Type *type) +//{ +// assert(type); +// return m_ast.CreateLValueReferenceType(type->GetClangForwardType()); +//} +// +//void * +//TypeList::CreateClangRValueReferenceType (Type *type) +//{ +// assert(type); +// return m_ast.CreateRValueReferenceType (type->GetClangForwardType()); +//} +// Modified: lldb/trunk/source/Target/StackFrame.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrame.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Target/StackFrame.cpp (original) +++ lldb/trunk/source/Target/StackFrame.cpp Sun Jan 16 21:46:26 2011 @@ -562,7 +562,7 @@ { // Incorrect use of "." with a pointer, or "->" with // a class/union/struct instance or reference. - valobj_sp->GetExpressionPath (var_expr_path_strm); + valobj_sp->GetExpressionPath (var_expr_path_strm, false); if (actual_is_ptr) error.SetErrorStringWithFormat ("\"%s\" is a pointer and . was used to attempt to access \"%s\". Did you mean \"%s->%s\"?", var_expr_path_strm.GetString().c_str(), @@ -583,7 +583,7 @@ if (!child_valobj_sp) { // No child member with name "child_name" - valobj_sp->GetExpressionPath (var_expr_path_strm); + valobj_sp->GetExpressionPath (var_expr_path_strm, false); if (child_name) { error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"", @@ -619,7 +619,7 @@ child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true); if (!child_valobj_sp) { - valobj_sp->GetExpressionPath (var_expr_path_strm); + valobj_sp->GetExpressionPath (var_expr_path_strm, false); error.SetErrorStringWithFormat ("failed to use pointer as array for index %i for \"(%s) %s\"", child_index, valobj_sp->GetTypeName().AsCString(""), @@ -631,7 +631,7 @@ child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true); if (!child_valobj_sp) { - valobj_sp->GetExpressionPath (var_expr_path_strm); + valobj_sp->GetExpressionPath (var_expr_path_strm, false); error.SetErrorStringWithFormat ("array index %i is not valid for \"(%s) %s\"", child_index, valobj_sp->GetTypeName().AsCString(""), @@ -640,7 +640,7 @@ } else { - valobj_sp->GetExpressionPath (var_expr_path_strm); + valobj_sp->GetExpressionPath (var_expr_path_strm, false); error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type", valobj_sp->GetTypeName().AsCString(""), var_expr_path_strm.GetString().c_str()); @@ -667,7 +667,7 @@ default: // Failure... { - valobj_sp->GetExpressionPath (var_expr_path_strm); + valobj_sp->GetExpressionPath (var_expr_path_strm, false); error.SetErrorStringWithFormat ("unexpected char '%c' encountered after \"%s\" in \"%s\"", separator_type, var_expr_path_strm.GetString().c_str(), Modified: lldb/trunk/source/Target/ThreadPlanTracer.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ThreadPlanTracer.cpp?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/source/Target/ThreadPlanTracer.cpp (original) +++ lldb/trunk/source/Target/ThreadPlanTracer.cpp Sun Jan 16 21:46:26 2011 @@ -114,13 +114,12 @@ m_abi = process.GetABI(); - ModuleSP executableModuleSP (target.GetExecutableModule()); - TypeList *type_list = executableModuleSP->GetTypeList(); + ModuleSP exe_module_sp (target.GetExecutableModule()); - if (type_list) + if (exe_module_sp) { - m_intptr_type = TypeFromUser(type_list->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, arch.GetAddressByteSize() * 8), - type_list->GetClangASTContext().getASTContext()); + m_intptr_type = TypeFromUser(exe_module_sp->GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, arch.GetAddressByteSize() * 8), + exe_module_sp->GetClangASTContext().getASTContext()); } const unsigned int buf_size = 32; Modified: lldb/trunk/test/class_types/TestClassTypes.py URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/class_types/TestClassTypes.py?rev=123613&r1=123612&r2=123613&view=diff ============================================================================== --- lldb/trunk/test/class_types/TestClassTypes.py (original) +++ lldb/trunk/test/class_types/TestClassTypes.py Sun Jan 16 21:46:26 2011 @@ -180,7 +180,7 @@ # Verify that 'frame variable this' gets the data type correct. self.expect("frame variable this",VARIABLES_DISPLAYED_CORRECTLY, - substrs = ['class C *']) + substrs = ['C *']) # Verify that frame variable -t this->m_c_int behaves correctly. self.expect("frame variable -t this->m_c_int", VARIABLES_DISPLAYED_CORRECTLY, @@ -188,7 +188,7 @@ # Verify that 'expression this' gets the data type correct. self.expect("expression this", VARIABLES_DISPLAYED_CORRECTLY, - substrs = ['class C *']) + substrs = ['C *']) # rdar://problem/8430916 # expr this->m_c_int returns an incorrect value From gclayton at apple.com Sun Jan 16 22:19:52 2011 From: gclayton at apple.com (Greg Clayton) Date: Mon, 17 Jan 2011 04:19:52 -0000 Subject: [Lldb-commits] [lldb] r123614 - in /lldb/trunk: include/lldb/Symbol/ClangExternalASTSourceCallbacks.h source/Symbol/ClangExternalASTSourceCallbacks.cpp Message-ID: <20110117041952.1A4142A6C12C@llvm.org> Author: gclayton Date: Sun Jan 16 22:19:51 2011 New Revision: 123614 URL: http://llvm.org/viewvc/llvm-project?rev=123614&view=rev Log: Added missing source files. Added: lldb/trunk/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h lldb/trunk/source/Symbol/ClangExternalASTSourceCallbacks.cpp Added: lldb/trunk/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h?rev=123614&view=auto ============================================================================== --- lldb/trunk/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h (added) +++ lldb/trunk/include/lldb/Symbol/ClangExternalASTSourceCallbacks.h Sun Jan 16 22:19:51 2011 @@ -0,0 +1,171 @@ +//===-- ClangExternalASTSourceCallbacks.h -----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_ClangExternalASTSourceCallbacks_h_ +#define liblldb_ClangExternalASTSourceCallbacks_h_ + +// C Includes +// C++ Includes +#include +#include +#include +#include + +// Other libraries and framework includes + +// Clang headers like to use NDEBUG inside of them to enable/disable debug +// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing +// or another. This is bad because it means that if clang was built in release +// mode, it assumes that you are building in release mode which is not always +// the case. You can end up with functions that are defined as empty in header +// files when NDEBUG is not defined, and this can cause link errors with the +// clang .a files that you have since you might be missing functions in the .a +// file. So we have to define NDEBUG when including clang headers to avoid any +// mismatches. This is covered by rdar://problem/8691220 + +#ifndef NDEBUG +#define LLDB_DEFINED_NDEBUG_FOR_CLANG +#define NDEBUG +// Need to include assert.h so it is as clang would expect it to be (disabled) +#include +#endif + +#include "clang/AST/ExternalASTSource.h" + +#ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG +#undef NDEBUG +#undef LLDB_DEFINED_NDEBUG_FOR_CLANG +// Need to re-include assert.h so it is as _we_ would expect it to be (enabled) +#include +#endif + +// Project includes +#include "lldb/lldb-enumerations.h" +#include "lldb/Core/ClangForward.h" +#include "lldb/Symbol/ClangASTType.h" + +namespace lldb_private { + +class ClangExternalASTSourceCallbacks : public clang::ExternalASTSource +{ +public: + + typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *); + typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton, clang::ObjCInterfaceDecl *); + + + ClangExternalASTSourceCallbacks (CompleteTagDeclCallback tag_decl_callback, + CompleteObjCInterfaceDeclCallback objc_decl_callback, + void *callback_baton) : + m_callback_tag_decl (tag_decl_callback), + m_callback_objc_decl (objc_decl_callback), + m_callback_baton (callback_baton) + { + } + + //------------------------------------------------------------------ + // clang::ExternalASTSource + //------------------------------------------------------------------ + + virtual clang::Decl * + GetExternalDecl (uint32_t ID) + { + // This method only needs to be implemented if the AST source ever + // passes back decl sets as VisibleDeclaration objects. + return 0; + } + + virtual clang::Stmt * + GetExternalDeclStmt (uint64_t Offset) + { + // This operation is meant to be used via a LazyOffsetPtr. It only + // needs to be implemented if the AST source uses methods like + // FunctionDecl::setLazyBody when building decls. + return 0; + } + + virtual clang::Selector + GetExternalSelector (uint32_t ID) + { + // This operation only needs to be implemented if the AST source + // returns non-zero for GetNumKnownSelectors(). + return clang::Selector(); + } + + virtual uint32_t + GetNumExternalSelectors() + { + return 0; + } + + virtual clang::CXXBaseSpecifier * + GetExternalCXXBaseSpecifiers(uint64_t Offset) + { + return NULL; + } + + virtual void + MaterializeVisibleDecls (const clang::DeclContext *decl_ctx) + { + return; + } + + virtual bool + FindExternalLexicalDecls (const clang::DeclContext *decl_ctx, + bool (*isKindWeWant)(clang::Decl::Kind), + llvm::SmallVectorImpl &decls) + { + // This is used to support iterating through an entire lexical context, + // which isn't something the debugger should ever need to do. + // true is for error, that's good enough for me + return true; + } + + virtual clang::DeclContextLookupResult + FindExternalVisibleDeclsByName (const clang::DeclContext *decl_ctx, + clang::DeclarationName decl_name); + + virtual void + CompleteType (clang::TagDecl *tag_decl); + + virtual void + CompleteType (clang::ObjCInterfaceDecl *objc_decl); + + void + SetExternalSourceCallbacks (CompleteTagDeclCallback tag_decl_callback, + CompleteObjCInterfaceDeclCallback objc_decl_callback, + void *callback_baton) + { + m_callback_tag_decl = tag_decl_callback; + m_callback_objc_decl = objc_decl_callback; + m_callback_baton = callback_baton; + } + + void + RemoveExternalSourceCallbacks (void *callback_baton) + { + if (callback_baton == m_callback_baton) + { + m_callback_tag_decl = NULL; + m_callback_objc_decl = NULL; + } + } + +protected: + //------------------------------------------------------------------ + // Classes that inherit from ClangExternalASTSourceCallbacks can see and modify these + //------------------------------------------------------------------ + CompleteTagDeclCallback m_callback_tag_decl; + CompleteObjCInterfaceDeclCallback m_callback_objc_decl; + void * m_callback_baton; +}; + +} // namespace lldb_private + +#endif // liblldb_ClangExternalASTSourceCallbacks_h_ Added: lldb/trunk/source/Symbol/ClangExternalASTSourceCallbacks.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Symbol/ClangExternalASTSourceCallbacks.cpp?rev=123614&view=auto ============================================================================== --- lldb/trunk/source/Symbol/ClangExternalASTSourceCallbacks.cpp (added) +++ lldb/trunk/source/Symbol/ClangExternalASTSourceCallbacks.cpp Sun Jan 16 22:19:51 2011 @@ -0,0 +1,125 @@ +//===-- ClangExternalASTSourceCallbacks.cpp ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes + +// Clang headers like to use NDEBUG inside of them to enable/disable debug +// releated features using "#ifndef NDEBUG" preprocessor blocks to do one thing +// or another. This is bad because it means that if clang was built in release +// mode, it assumes that you are building in release mode which is not always +// the case. You can end up with functions that are defined as empty in header +// files when NDEBUG is not defined, and this can cause link errors with the +// clang .a files that you have since you might be missing functions in the .a +// file. So we have to define NDEBUG when including clang headers to avoid any +// mismatches. This is covered by rdar://problem/8691220 + +#ifndef NDEBUG +#define LLDB_DEFINED_NDEBUG_FOR_CLANG +#define NDEBUG +// Need to include assert.h so it is as clang would expect it to be (disabled) +#include +#endif + +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclarationName.h" + +#ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG +#undef NDEBUG +#undef LLDB_DEFINED_NDEBUG_FOR_CLANG +// Need to re-include assert.h so it is as _we_ would expect it to be (enabled) +#include +#endif + +#include "lldb/Core/Log.h" + +using namespace clang; +using namespace lldb_private; + +clang::DeclContextLookupResult +ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName +( + const clang::DeclContext *decl_ctx, + clang::DeclarationName clang_decl_name +) +{ + std::string decl_name (clang_decl_name.getAsString()); + + switch (clang_decl_name.getNameKind()) { + // Normal identifiers. + case clang::DeclarationName::Identifier: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"Identifier\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + if (clang_decl_name.getAsIdentifierInfo()->getBuiltinID() != 0) + return SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); + break; + + case clang::DeclarationName::ObjCZeroArgSelector: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"ObjCZeroArgSelector\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::ObjCOneArgSelector: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"ObjCOneArgSelector\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::ObjCMultiArgSelector: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"ObjCMultiArgSelector\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::CXXConstructorName: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXConstructorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::CXXDestructorName: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXDestructorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::CXXConversionFunctionName: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXConversionFunctionName\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::CXXOperatorName: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXOperatorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::CXXLiteralOperatorName: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXLiteralOperatorName\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return DeclContext::lookup_result(); + break; + + case clang::DeclarationName::CXXUsingDirective: + //printf ("ClangExternalASTSourceCallbacks::FindExternalVisibleDeclsByName(decl_ctx = %p, decl_name = { kind = \"CXXUsingDirective\", name = \"%s\")\n", decl_ctx, decl_name.c_str()); + return SetNoExternalVisibleDeclsForName(decl_ctx, clang_decl_name); + } + + return DeclContext::lookup_result(); +} + +void +ClangExternalASTSourceCallbacks::CompleteType (TagDecl *tag_decl) +{ + if (m_callback_tag_decl) + m_callback_tag_decl (m_callback_baton, tag_decl); +} + +void +ClangExternalASTSourceCallbacks::CompleteType (ObjCInterfaceDecl *objc_decl) +{ + if (m_callback_objc_decl) + m_callback_objc_decl (m_callback_baton, objc_decl); +} From gclayton at apple.com Sun Jan 16 22:34:27 2011 From: gclayton at apple.com (Greg Clayton) Date: Mon, 17 Jan 2011 04:34:27 -0000 Subject: [Lldb-commits] [lldb] r123615 - /lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Message-ID: <20110117043427.281EB2A6C12C@llvm.org> Author: gclayton Date: Sun Jan 16 22:34:26 2011 New Revision: 123615 URL: http://llvm.org/viewvc/llvm-project?rev=123615&view=rev Log: Fix the objective C object validator that I broke. When we have ObjC runtime V2 and we only have gdb_class_getClass, then make sure the isa isn't NULL before trying to call gdb_class_getClass otherwise we end up deadlocking the objective C runtime. Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Modified: lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp?rev=123615&r1=123614&r2=123615&view=diff ============================================================================== --- lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (original) +++ lldb/trunk/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp Sun Jan 16 22:34:26 2011 @@ -156,7 +156,7 @@ " if ($__lldb_arg_obj == (void *)0) \n" " return; // nil is ok \n" " void **$isa_ptr = (void **)$__lldb_arg_obj; \n" - " if (!gdb_class_getClass(*$isa_ptr)) \n" + " if (*$isa_ptr == NULL || !gdb_class_getClass(*$isa_ptr)) \n" " *((volatile int *)0) = 'ocgc'; \n" "} \n", name); From gclayton at apple.com Sun Jan 16 23:51:02 2011 From: gclayton at apple.com (Greg Clayton) Date: Mon, 17 Jan 2011 05:51:02 -0000 Subject: [Lldb-commits] [lldb] r123616 - /lldb/trunk/source/Core/ValueObject.cpp Message-ID: <20110117055102.D84242A6C12C@llvm.org> Author: gclayton Date: Sun Jan 16 23:51:02 2011 New Revision: 123616 URL: http://llvm.org/viewvc/llvm-project?rev=123616&view=rev Log: Fixed the C string summary formatter to not get into an infinite loop for long strings in "char *" (with any combo if qualifiers). Modified: lldb/trunk/source/Core/ValueObject.cpp Modified: lldb/trunk/source/Core/ValueObject.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=123616&r1=123615&r2=123616&view=diff ============================================================================== --- lldb/trunk/source/Core/ValueObject.cpp (original) +++ lldb/trunk/source/Core/ValueObject.cpp Sun Jan 16 23:51:02 2011 @@ -451,29 +451,24 @@ DataExtractor data; size_t bytes_read = 0; std::vector data_buffer; - std::vector cstr_buffer; - size_t cstr_length; Error error; if (cstr_len > 0) { data_buffer.resize(cstr_len); - // Resize the formatted buffer in case every character - // uses the "\xXX" format and one extra byte for a NULL - cstr_buffer.resize(data_buffer.size() * 4 + 1); data.SetData (&data_buffer.front(), data_buffer.size(), eByteOrderHost); bytes_read = process->ReadMemory (cstr_address, &data_buffer.front(), cstr_len, error); if (bytes_read > 0) { sstr << '"'; - cstr_length = data.Dump (&sstr, - 0, // Start offset in "data" - eFormatChar, // Print as characters - 1, // Size of item (1 byte for a char!) - bytes_read, // How many bytes to print? - UINT32_MAX, // num per line - LLDB_INVALID_ADDRESS,// base address - 0, // bitfield bit size - 0); // bitfield bit offset + data.Dump (&sstr, + 0, // Start offset in "data" + eFormatChar, // Print as characters + 1, // Size of item (1 byte for a char!) + bytes_read, // How many bytes to print? + UINT32_MAX, // num per line + LLDB_INVALID_ADDRESS,// base address + 0, // bitfield bit size + 0); // bitfield bit offset sstr << '"'; } } @@ -483,13 +478,10 @@ data_buffer.resize (k_max_buf_size + 1); // NULL terminate in case we don't get the entire C string data_buffer.back() = '\0'; - // Make a formatted buffer that can contain take 4 - // bytes per character in case each byte uses the - // "\xXX" format and one extra byte for a NULL - cstr_buffer.resize (k_max_buf_size * 4 + 1); + + sstr << '"'; data.SetData (&data_buffer.front(), data_buffer.size(), eByteOrderHost); - size_t total_cstr_len = 0; while ((bytes_read = process->ReadMemory (cstr_address, &data_buffer.front(), k_max_buf_size, error)) > 0) { size_t len = strlen(&data_buffer.front()); @@ -497,25 +489,22 @@ break; if (len > bytes_read) len = bytes_read; - if (sstr.GetSize() == 0) - sstr << '"'; - - cstr_length = data.Dump (&sstr, - 0, // Start offset in "data" - eFormatChar, // Print as characters - 1, // Size of item (1 byte for a char!) - len, // How many bytes to print? - UINT32_MAX, // num per line - LLDB_INVALID_ADDRESS,// base address - 0, // bitfield bit size - 0); // bitfield bit offset + data.Dump (&sstr, + 0, // Start offset in "data" + eFormatChar, // Print as characters + 1, // Size of item (1 byte for a char!) + len, // How many bytes to print? + UINT32_MAX, // num per line + LLDB_INVALID_ADDRESS,// base address + 0, // bitfield bit size + 0); // bitfield bit offset + if (len < k_max_buf_size) break; - cstr_address += total_cstr_len; + cstr_address += k_max_buf_size; } - if (sstr.GetSize() > 0) - sstr << '"'; + sstr << '"'; } } }