[Lldb-commits] [lldb] r179437 - Added a SetData() method to ValueObject. This

Sean Callanan scallanan at apple.com
Fri Apr 12 18:21:23 PDT 2013


Author: spyffe
Date: Fri Apr 12 20:21:23 2013
New Revision: 179437

URL: http://llvm.org/viewvc/llvm-project?rev=179437&view=rev
Log:
Added a SetData() method to ValueObject.  This
lets a ValueObject's contents be set from raw
data.  This has certain limitations (notably,
registers can only be set to data that is as
large as the register) but will be useful for
the new Materializer.

I also exposed this interface through SBValue.
I have added a testcase that exercises various
special cases of SBValue::SetData().

Added:
    lldb/trunk/test/functionalities/set-data/
    lldb/trunk/test/functionalities/set-data/Makefile
    lldb/trunk/test/functionalities/set-data/TestSetData.py
    lldb/trunk/test/functionalities/set-data/main.m
Modified:
    lldb/trunk/include/lldb/API/SBValue.h
    lldb/trunk/include/lldb/Core/Scalar.h
    lldb/trunk/include/lldb/Core/ValueObject.h
    lldb/trunk/include/lldb/Core/ValueObjectDynamicValue.h
    lldb/trunk/include/lldb/Core/ValueObjectRegister.h
    lldb/trunk/source/API/SBValue.cpp
    lldb/trunk/source/Core/Scalar.cpp
    lldb/trunk/source/Core/ValueObject.cpp
    lldb/trunk/source/Core/ValueObjectDynamicValue.cpp
    lldb/trunk/source/Core/ValueObjectRegister.cpp

Modified: lldb/trunk/include/lldb/API/SBValue.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/API/SBValue.h?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/include/lldb/API/SBValue.h (original)
+++ lldb/trunk/include/lldb/API/SBValue.h Fri Apr 12 20:21:23 2013
@@ -290,6 +290,9 @@ public:
     lldb::SBData
     GetData ();
     
+    bool
+    SetData (lldb::SBData &data, lldb::SBError& error);
+    
     lldb::SBDeclaration
     GetDeclaration ();
     

Modified: lldb/trunk/include/lldb/Core/Scalar.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Scalar.h?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Scalar.h (original)
+++ lldb/trunk/include/lldb/Core/Scalar.h Fri Apr 12 20:21:23 2013
@@ -220,6 +220,9 @@ public:
 
     Error
     SetValueFromCString (const char *s, lldb::Encoding encoding, size_t byte_size);
+    
+    Error
+    SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t byte_size);
 
     static bool
     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)

Modified: lldb/trunk/include/lldb/Core/ValueObject.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObject.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObject.h Fri Apr 12 20:21:23 2013
@@ -998,6 +998,9 @@ public:
     
     virtual uint64_t
     GetData (DataExtractor& data);
+    
+    virtual bool
+    SetData (DataExtractor &data, Error &error);
 
     bool
     GetIsConstant () const

Modified: lldb/trunk/include/lldb/Core/ValueObjectDynamicValue.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObjectDynamicValue.h?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObjectDynamicValue.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObjectDynamicValue.h Fri Apr 12 20:21:23 2013
@@ -90,6 +90,9 @@ public:
     virtual bool
     SetValueFromCString (const char *value_str, Error& error);
     
+    virtual bool
+    SetData (DataExtractor &data, Error &error)
+    
 protected:
     virtual bool
     UpdateValue ();

Modified: lldb/trunk/include/lldb/Core/ValueObjectRegister.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObjectRegister.h?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObjectRegister.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObjectRegister.h Fri Apr 12 20:21:23 2013
@@ -159,6 +159,9 @@ public:
     
     virtual bool
     SetValueFromCString (const char *value_str, Error& error);
+    
+    virtual bool
+    SetData (DataExtractor &data, Error &error);
 
     virtual bool
     ResolveValue (Scalar &scalar);

Modified: lldb/trunk/source/API/SBValue.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/API/SBValue.cpp?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/source/API/SBValue.cpp (original)
+++ lldb/trunk/source/API/SBValue.cpp Fri Apr 12 20:21:23 2013
@@ -1880,6 +1880,65 @@ SBValue::GetData ()
     return sb_data;
 }
 
+bool
+SBValue::SetData (lldb::SBData &data, SBError &error)
+{
+    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
+    lldb::ValueObjectSP value_sp(GetSP());
+    bool ret = true;
+    
+    if (value_sp)
+    {
+        ProcessSP process_sp(value_sp->GetProcessSP());
+        Process::StopLocker stop_locker;
+        if (process_sp && !stop_locker.TryLock(&process_sp->GetRunLock()))
+        {
+            if (log)
+                log->Printf ("SBValue(%p)::SetData() => error: process is running", value_sp.get());
+            
+            error.SetErrorString("Process is running");
+            ret = false;
+        }
+        else
+        {
+            DataExtractor *data_extractor = data.get();
+            
+            if (!data_extractor)
+            {
+                if (log)
+                    log->Printf ("SBValue(%p)::SetData() => error: no data to set", value_sp.get());
+                
+                error.SetErrorString("No data to set");
+                ret = false;
+            }
+            else
+            {
+                Error set_error;
+                
+                value_sp->SetData(*data_extractor, set_error);
+                
+                if (!set_error.Success())
+                {
+                    error.SetErrorStringWithFormat("Couldn't set data: %s", set_error.AsCString());
+                    ret = false;
+                }
+            }
+        }
+    }
+    else
+    {
+        error.SetErrorString("Couldn't set data: invalid SBValue");
+        ret = false;
+    }
+    
+    if (log)
+        log->Printf ("SBValue(%p)::SetData (%p) => %s",
+                     value_sp.get(),
+                     data.get(),
+                     ret ? "true" : "false");
+    return ret;
+}
+
 lldb::SBDeclaration
 SBValue::GetDeclaration ()
 {

Modified: lldb/trunk/source/Core/Scalar.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Scalar.cpp?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/source/Core/Scalar.cpp (original)
+++ lldb/trunk/source/Core/Scalar.cpp Fri Apr 12 20:21:23 2013
@@ -1868,6 +1868,70 @@ Scalar::SetValueFromCString (const char
     return error;
 }
 
+Error
+Scalar::SetValueFromData (DataExtractor &data, lldb::Encoding encoding, size_t byte_size)
+{
+    Error error;
+    
+    switch (encoding)
+    {
+    case lldb::eEncodingInvalid:
+        error.SetErrorString ("invalid encoding");
+        break;
+    case lldb::eEncodingVector:
+        error.SetErrorString ("vector encoding unsupported");
+        break;
+    case lldb::eEncodingUint:
+        {
+            lldb::offset_t offset;
+            
+            switch (byte_size)
+            {
+            case 1: operator=((uint8_t)data.GetU8(&offset)); break;
+            case 2: operator=((uint16_t)data.GetU16(&offset)); break;
+            case 4: operator=((uint32_t)data.GetU32(&offset)); break;
+            case 8: operator=((uint64_t)data.GetU64(&offset)); break;
+            default:
+                error.SetErrorStringWithFormat ("unsupported unsigned integer byte size: %zu", byte_size);
+                break;
+            }
+        }
+        break;
+    case lldb::eEncodingSint:
+        {
+            lldb::offset_t offset;
+            
+            switch (byte_size)
+            {
+            case 1: operator=((int8_t)data.GetU8(&offset)); break;
+            case 2: operator=((int16_t)data.GetU16(&offset)); break;
+            case 4: operator=((int32_t)data.GetU32(&offset)); break;
+            case 8: operator=((int64_t)data.GetU64(&offset)); break;
+            default:
+                error.SetErrorStringWithFormat ("unsupported signed integer byte size: %zu", byte_size);
+                break;
+            }
+        }
+        break;
+    case lldb::eEncodingIEEE754:
+        {
+            lldb::offset_t offset;
+            
+            if (byte_size == sizeof (float))
+                operator=((float)data.GetFloat(&offset));
+            else if (byte_size == sizeof (double))
+                operator=((double)data.GetDouble(&offset));
+            else if (byte_size == sizeof (long double))
+                operator=((long double)data.GetLongDouble(&offset));
+            else
+                error.SetErrorStringWithFormat ("unsupported float byte size: %zu", byte_size);
+        }
+        break;
+    }
+    
+    return error;
+}
+
 bool
 Scalar::SignExtend (uint32_t sign_bit_pos)
 {

Modified: lldb/trunk/source/Core/ValueObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObject.cpp (original)
+++ lldb/trunk/source/Core/ValueObject.cpp Fri Apr 12 20:21:23 2013
@@ -1013,6 +1013,84 @@ ValueObject::GetData (DataExtractor& dat
     return data.GetByteSize();
 }
 
+bool
+ValueObject::SetData (DataExtractor &data, Error &error)
+{
+    error.Clear();
+    // Make sure our value is up to date first so that our location and location
+    // type is valid.
+    if (!UpdateValueIfNeeded(false))
+    {
+        error.SetErrorString("unable to read value");
+        return false;
+    }
+    
+    uint64_t count = 0;
+    Encoding encoding = ClangASTType::GetEncoding (GetClangType(), count);
+    
+    const size_t byte_size = GetByteSize();
+    
+    Value::ValueType value_type = m_value.GetValueType();
+    
+    switch (value_type)
+    {
+    case Value::eValueTypeScalar:
+        {
+            Error set_error = m_value.GetScalar().SetValueFromData(data, encoding, byte_size);
+            
+            if (!set_error.Success())
+            {
+                error.SetErrorStringWithFormat("unable to set scalar value: %s", set_error.AsCString());
+                return false;
+            }
+        }
+        break;
+    case Value::eValueTypeLoadAddress:
+        {
+            // If it is a load address, then the scalar value is the storage location
+            // of the data, and we have to shove this value down to that load location.
+            ExecutionContext exe_ctx (GetExecutionContextRef());
+            Process *process = exe_ctx.GetProcessPtr();
+            if (process)
+            {
+                addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+                size_t bytes_written = process->WriteMemory(target_addr,
+                                                            data.GetDataStart(),
+                                                            byte_size,
+                                                            error);
+                if (!error.Success())
+                    return false;
+                if (bytes_written != byte_size)
+                {
+                    error.SetErrorString("unable to write value to memory");
+                    return false;
+                }
+            }
+        }
+        break;
+    case Value::eValueTypeHostAddress:
+        {
+            // If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data.            
+            DataBufferSP buffer_sp (new DataBufferHeap(byte_size, 0));
+            m_data.SetData(buffer_sp, 0);
+            data.CopyByteOrderedData (0,
+                                      byte_size,
+                                      const_cast<uint8_t *>(m_data.GetDataStart()),
+                                      byte_size,
+                                      m_data.GetByteOrder());
+            m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
+        }
+        break;
+    case Value::eValueTypeFileAddress:
+    case Value::eValueTypeVector:
+        break;
+    }
+    
+    // If we have reached this point, then we have successfully changed the value.
+    SetNeedsUpdate();
+    return true;
+}
+
 // will compute strlen(str), but without consuming more than
 // maxlen bytes out of str (this serves the purpose of reading
 // chunks of a string without having to worry about

Modified: lldb/trunk/source/Core/ValueObjectDynamicValue.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectDynamicValue.cpp?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObjectDynamicValue.cpp (original)
+++ lldb/trunk/source/Core/ValueObjectDynamicValue.cpp Fri Apr 12 20:21:23 2013
@@ -343,3 +343,42 @@ ValueObjectDynamicValue::SetValueFromCSt
     SetNeedsUpdate();
     return ret_val;
 }
+
+bool
+ValueObjectDynamicValue::SetData (DataExtractor &data, Error &error)
+{
+    if (!UpdateValueIfNeeded(false))
+    {
+        error.SetErrorString("unable to read value");
+        return false;
+    }
+    
+    uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
+    uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
+    
+    if (my_value == UINT64_MAX || parent_value == UINT64_MAX)
+    {
+        error.SetErrorString("unable to read value");
+        return false;
+    }
+    
+    // if we are at an offset from our parent, in order to set ourselves correctly we would need
+    // to change the new value so that it refers to the correct dynamic type. we choose not to deal
+    // with that - if anything more than a value overwrite is required, you should be using the
+    // expression parser instead of the value editing facility
+    if (my_value != parent_value)
+    {
+        // but NULL'ing out a value should always be allowed
+        lldb::offset_t offset = 0;
+        
+        if (data.GetPointer(&offset) != 0)
+        {
+            error.SetErrorString("unable to modify dynamic value, use 'expression' command");
+            return false;
+        }
+    }
+    
+    bool ret_val = m_parent->SetData(data, error);
+    SetNeedsUpdate();
+    return ret_val;
+}

Modified: lldb/trunk/source/Core/ValueObjectRegister.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObjectRegister.cpp?rev=179437&r1=179436&r2=179437&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObjectRegister.cpp (original)
+++ lldb/trunk/source/Core/ValueObjectRegister.cpp Fri Apr 12 20:21:23 2013
@@ -423,6 +423,24 @@ ValueObjectRegister::SetValueFromCString
 }
 
 bool
+ValueObjectRegister::SetData (DataExtractor &data, Error &error)
+{
+    error = m_reg_value.SetValueFromData(&m_reg_info, data, 0, false);
+    if (error.Success())
+    {
+        if (m_reg_ctx_sp->WriteRegister (&m_reg_info, m_reg_value))
+        {
+            SetNeedsUpdate();
+            return true;
+        }
+        else
+            return false;
+    }
+    else
+        return false;
+}
+
+bool
 ValueObjectRegister::ResolveValue (Scalar &scalar)
 {
     if (UpdateValueIfNeeded(false)) // make sure that you are up to date before returning anything

Added: lldb/trunk/test/functionalities/set-data/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/set-data/Makefile?rev=179437&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/set-data/Makefile (added)
+++ lldb/trunk/test/functionalities/set-data/Makefile Fri Apr 12 20:21:23 2013
@@ -0,0 +1,7 @@
+LEVEL = ../../make
+
+OBJC_SOURCES := main.m
+
+include $(LEVEL)/Makefile.rules
+
+LDFLAGS += -framework Foundation

Added: lldb/trunk/test/functionalities/set-data/TestSetData.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/set-data/TestSetData.py?rev=179437&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/set-data/TestSetData.py (added)
+++ lldb/trunk/test/functionalities/set-data/TestSetData.py Fri Apr 12 20:21:23 2013
@@ -0,0 +1,70 @@
+"""
+Set the contents of variables and registers using raw data
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+ at unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+class SetDataTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "set-data")
+
+    @dsym_test
+    def test_set_data_dsym(self):
+        """Test setting the contents of variables and registers using raw data."""
+        self.buildDsym()
+        self.setData()
+
+    def setData(self):
+        """Test setting objc breakpoints using '_regexp-break' and 'breakpoint set'."""
+        exe = os.path.join(os.getcwd(), "a.out")
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        self.runCmd("br s -p First");
+        self.runCmd("br s -p Second");
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        self.expect("p myFoo.x", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ['2'])
+
+        process = self.dbg.GetSelectedTarget().GetProcess()
+        frame = process.GetSelectedThread().GetFrameAtIndex(0)
+
+        x = frame.FindVariable("myFoo").GetChildMemberWithName("x")
+
+        my_data = lldb.SBData.CreateDataFromSInt32Array(lldb.eByteOrderLittle, 8, [4])
+        err = lldb.SBError()
+
+        self.assertTrue (x.SetData(my_data, err))
+
+        self.runCmd("continue")
+
+        self.expect("p myFoo.x", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ['4'])
+
+        frame = process.GetSelectedThread().GetFrameAtIndex(0)
+
+        x = frame.FindVariable("string")
+
+        if process.GetAddressByteSize() == 8:
+            my_data = lldb.SBData.CreateDataFromUInt64Array(process.GetByteOrder(), 8, [0])
+        else:
+            my_data = lldb.SBData.CreateDataFromUInt32Array(process.GetByteOrder(), 4, [0])
+        
+        err = lldb.SBError()
+
+        self.assertTrue (x.SetData(my_data, err))
+
+        self.expect("fr var -d run-target string", VARIABLES_DISPLAYED_CORRECTLY,
+            substrs = ['NSString *', 'nil'])
+        
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/set-data/main.m
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/set-data/main.m?rev=179437&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/set-data/main.m (added)
+++ lldb/trunk/test/functionalities/set-data/main.m Fri Apr 12 20:21:23 2013
@@ -0,0 +1,19 @@
+#import <Foundation/Foundation.h>
+
+int main ()
+{
+    @autoreleasepool
+    {
+        struct foo {
+            int x;
+            int y;
+        } myFoo;
+
+        myFoo.x = 2;
+        myFoo.y = 3;    // First breakpoint
+
+        NSString *string = [NSString stringWithFormat:@"%s", "Hello world!"];
+
+        NSLog(@"%d %@", myFoo.x, string); // Second breakpoint
+    }
+}





More information about the lldb-commits mailing list