diff options
-rw-r--r-- | lldb/include/lldb/API/SBValue.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/Core/Scalar.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/Core/ValueObject.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/Core/ValueObjectDynamicValue.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/Core/ValueObjectRegister.h | 3 | ||||
-rw-r--r-- | lldb/source/API/SBValue.cpp | 59 | ||||
-rw-r--r-- | lldb/source/Core/Scalar.cpp | 64 | ||||
-rw-r--r-- | lldb/source/Core/ValueObject.cpp | 78 | ||||
-rw-r--r-- | lldb/source/Core/ValueObjectDynamicValue.cpp | 39 | ||||
-rw-r--r-- | lldb/source/Core/ValueObjectRegister.cpp | 18 | ||||
-rw-r--r-- | lldb/test/functionalities/set-data/Makefile | 7 | ||||
-rw-r--r-- | lldb/test/functionalities/set-data/TestSetData.py | 70 | ||||
-rw-r--r-- | lldb/test/functionalities/set-data/main.m | 19 |
13 files changed, 369 insertions, 0 deletions
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 91cf6380674..1f6f096ce53 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -290,6 +290,9 @@ public: lldb::SBData GetData (); + bool + SetData (lldb::SBData &data, lldb::SBError& error); + lldb::SBDeclaration GetDeclaration (); diff --git a/lldb/include/lldb/Core/Scalar.h b/lldb/include/lldb/Core/Scalar.h index 3636b243eb6..2a89a598b5a 100644 --- a/lldb/include/lldb/Core/Scalar.h +++ b/lldb/include/lldb/Core/Scalar.h @@ -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) diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 869166aacc7..056387c4fb6 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -998,6 +998,9 @@ public: virtual uint64_t GetData (DataExtractor& data); + + virtual bool + SetData (DataExtractor &data, Error &error); bool GetIsConstant () const diff --git a/lldb/include/lldb/Core/ValueObjectDynamicValue.h b/lldb/include/lldb/Core/ValueObjectDynamicValue.h index a44afc41686..9efcbee2611 100644 --- a/lldb/include/lldb/Core/ValueObjectDynamicValue.h +++ b/lldb/include/lldb/Core/ValueObjectDynamicValue.h @@ -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 (); diff --git a/lldb/include/lldb/Core/ValueObjectRegister.h b/lldb/include/lldb/Core/ValueObjectRegister.h index 5c6ab890a56..73f6e583ad6 100644 --- a/lldb/include/lldb/Core/ValueObjectRegister.h +++ b/lldb/include/lldb/Core/ValueObjectRegister.h @@ -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); diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index 906fed18128..41c12a5689e 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -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 () { diff --git a/lldb/source/Core/Scalar.cpp b/lldb/source/Core/Scalar.cpp index 0fa112c80d6..16d8230cdef 100644 --- a/lldb/source/Core/Scalar.cpp +++ b/lldb/source/Core/Scalar.cpp @@ -1868,6 +1868,70 @@ Scalar::SetValueFromCString (const char *value_str, Encoding encoding, size_t by 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) { diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index dcc9e0e8265..19dfdee5b2a 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -1013,6 +1013,84 @@ ValueObject::GetData (DataExtractor& data) 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 diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index f82c66602ba..95108f386fa 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -343,3 +343,42 @@ ValueObjectDynamicValue::SetValueFromCString (const char *value_str, Error& erro 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; +} diff --git a/lldb/source/Core/ValueObjectRegister.cpp b/lldb/source/Core/ValueObjectRegister.cpp index 9ac8aa49205..f03db384f48 100644 --- a/lldb/source/Core/ValueObjectRegister.cpp +++ b/lldb/source/Core/ValueObjectRegister.cpp @@ -423,6 +423,24 @@ ValueObjectRegister::SetValueFromCString (const char *value_str, Error& error) } 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 diff --git a/lldb/test/functionalities/set-data/Makefile b/lldb/test/functionalities/set-data/Makefile new file mode 100644 index 00000000000..9e1d63a183b --- /dev/null +++ b/lldb/test/functionalities/set-data/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../make + +OBJC_SOURCES := main.m + +include $(LEVEL)/Makefile.rules + +LDFLAGS += -framework Foundation diff --git a/lldb/test/functionalities/set-data/TestSetData.py b/lldb/test/functionalities/set-data/TestSetData.py new file mode 100644 index 00000000000..166ef6706fc --- /dev/null +++ b/lldb/test/functionalities/set-data/TestSetData.py @@ -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 + +@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() diff --git a/lldb/test/functionalities/set-data/main.m b/lldb/test/functionalities/set-data/main.m new file mode 100644 index 00000000000..e1e69dc5571 --- /dev/null +++ b/lldb/test/functionalities/set-data/main.m @@ -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 + } +} |