clayborg updated this revision to Diff 392191.
clayborg added a comment.

More documentation fixed for DataEncoder.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D115073/new/

https://reviews.llvm.org/D115073

Files:
  lldb/include/lldb/Utility/DataEncoder.h
  lldb/include/lldb/lldb-forward.h
  lldb/source/Expression/DWARFExpression.cpp
  lldb/source/Plugins/Platform/Android/AdbClient.cpp
  lldb/source/Utility/DataEncoder.cpp
  lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp
  lldb/unittests/Utility/CMakeLists.txt
  lldb/unittests/Utility/DataEncoderTest.cpp

Index: lldb/unittests/Utility/DataEncoderTest.cpp
===================================================================
--- /dev/null
+++ lldb/unittests/Utility/DataEncoderTest.cpp
@@ -0,0 +1,534 @@
+//===-- DataEncoderTest.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Utility/DataEncoder.h"
+#include "llvm/ADT/ArrayRef.h"
+#include <vector>
+using namespace lldb_private;
+using namespace llvm;
+
+TEST(DataEncoderTest, PutU8) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  offset = encoder.PutU8(offset, 11);
+  ASSERT_EQ(offset, 1U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 2, 3, 4, 5, 6, 7, 8}));
+  offset = encoder.PutU8(offset, 12);
+  ASSERT_EQ(offset, 2U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 12, 3, 4, 5, 6, 7, 8}));
+  offset = encoder.PutU8(offset, 13);
+  ASSERT_EQ(offset, 3U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 12, 13, 4, 5, 6, 7, 8}));
+  offset = encoder.PutU8(offset, 14);
+  ASSERT_EQ(offset, 4U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 12, 13, 14, 5, 6, 7, 8}));
+  // Check that putting a number to an invalid offset doesn't work and returns
+  // an error offset and doesn't modify the buffer.
+  ASSERT_EQ(encoder.PutU8(init.size(), 15), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 12, 13, 14, 5, 6, 7, 8}));
+}
+
+TEST(DataEncoderTest, AppendUnsignedLittle) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderLittle, addr_size);
+  encoder.AppendU8(0x11);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11}));
+  encoder.AppendU16(0x2233);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11, 0x33, 0x22}));
+  encoder.AppendU32(0x44556677);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x33, 0x22, 0x77, 0x66, 0x55, 0x44}));
+  encoder.AppendU64(0x8899AABBCCDDEEFF);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x33, 0x22, 0x77, 0x66, 0x55, 0x44,
+                               0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}));
+  encoder.AppendU64(0x8899AABBCCDDEEFF);
+}
+
+TEST(DataEncoderTest, AppendUnsignedBig) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderBig, addr_size);
+  encoder.AppendU8(0x11);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11}));
+  encoder.AppendU16(0x2233);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11, 0x22, 0x33}));
+  encoder.AppendU32(0x44556677);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}));
+  encoder.AppendU64(0x8899AABBCCDDEEFF);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                               0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}));
+}
+
+TEST(DataEncoderTest, AppendAddress4Little) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderLittle, addr_size);
+  encoder.AppendAddress(0x11223344);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11}));
+  encoder.AppendAddress(0x55);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x55, 0x00, 0x00, 0x00}));
+}
+
+TEST(DataEncoderTest, AppendAddress4Big) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderBig, addr_size);
+  encoder.AppendAddress(0x11223344);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44}));
+  encoder.AppendAddress(0x55);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x00, 0x00, 0x00, 0x55}));
+}
+
+TEST(DataEncoderTest, AppendAddress8Little) {
+  const uint32_t addr_size = 8;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderLittle, addr_size);
+  encoder.AppendAddress(0x11223344);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  encoder.AppendAddress(0x5566778899AABBCC);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00,
+                               0xCC, 0xBB, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55}));
+}
+
+TEST(DataEncoderTest, AppendAddress8Big) {
+  const uint32_t addr_size = 8;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderBig, addr_size);
+  encoder.AppendAddress(0x11223344);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44}));
+  encoder.AppendAddress(0x5566778899AABBCC);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44,
+                               0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC}));
+}
+
+TEST(DataEncoderTest, AppendData) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderBig, addr_size);
+  // Make sure default constructed StringRef appends nothing
+  encoder.AppendData(StringRef());
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({}));
+  // Make sure empty StringRef appends nothing
+  encoder.AppendData(StringRef(""));
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({}));
+  // Append some bytes that contains a NULL character
+  encoder.AppendData(StringRef("\x11\x00\x22", 3));
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11, 0x00, 0x22}));
+}
+
+TEST(DataEncoderTest, AppendCString) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderBig, addr_size);
+  // Make sure default constructed StringRef appends nothing
+  encoder.AppendCString(StringRef());
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({}));
+  // Make sure empty StringRef appends a NULL character since the StringRef
+  // doesn't contain a NULL in the referenced string.
+  encoder.AppendCString(StringRef(""));
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x00}));
+  // Make sure empty StringRef appends only one NULL character if StringRef
+  // does contain a NULL in the referenced string.
+  encoder.AppendCString(StringRef("\0", 1));
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x00, 0x00}));
+  // Append a string where the StringRef doesn't contain a NULL termination
+  // and verify the NULL terminate gets added
+  encoder.AppendCString(StringRef("hello"));
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x00, 0x00, 'h', 'e', 'l', 'l', 'o', 0x00}));
+  // Append a string where the StringRef does contain a NULL termination and
+  // verify only one NULL is added
+  encoder.AppendCString(StringRef("world", 6));
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x00, 0x00, 'h', 'e', 'l', 'l', 'o', 0x00,
+                               'w', 'o', 'r', 'l', 'd', '\0'}));
+}
+
+TEST(DataEncoderTest, PutU16Little) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  offset = encoder.PutU16(offset, 11);
+  ASSERT_EQ(offset, 2U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 3, 4, 5, 6, 7, 8}));
+  offset = encoder.PutU16(offset, 12);
+  ASSERT_EQ(offset, 4U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 12, 0, 5, 6, 7, 8}));
+  offset = encoder.PutU16(offset, 13);
+  ASSERT_EQ(offset, 6U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 12, 0, 13, 0, 7, 8}));
+  offset = encoder.PutU16(offset, 14);
+  ASSERT_EQ(offset, 8U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 12, 0, 13, 0, 14, 0}));
+  // Check that putting a number to an invalid offset doesn't work and returns
+  // an error offset and doesn't modify the buffer.
+  ASSERT_EQ(encoder.PutU16(init.size(), 15), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 12, 0, 13, 0, 14, 0}));
+}
+
+TEST(DataEncoderTest, PutU16Big) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderBig,
+                      addr_size);
+  offset = encoder.PutU16(offset, 11);
+  ASSERT_EQ(offset, 2U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 11, 3, 4, 5, 6, 7, 8}));
+  offset = encoder.PutU16(offset, 12);
+  ASSERT_EQ(offset, 4U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 11, 0, 12, 5, 6, 7, 8}));
+  offset = encoder.PutU16(offset, 13);
+  ASSERT_EQ(offset, 6U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 11, 0, 12, 0, 13, 7, 8}));
+  offset = encoder.PutU16(offset, 14);
+  ASSERT_EQ(offset, 8U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 11, 0, 12, 0, 13, 0, 14}));
+  // Check that putting a number to an invalid offset doesn't work and returns
+  // an error offset and doesn't modify the buffer.
+  ASSERT_EQ(encoder.PutU16(init.size(), 15), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 11, 0, 12, 0, 13, 0, 14}));
+}
+
+TEST(DataEncoderTest, PutU32Little) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  offset = encoder.PutU32(offset, 11);
+  ASSERT_EQ(offset, 4U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 0, 0, 5, 6, 7, 8}));
+  offset = encoder.PutU32(offset, 12);
+  ASSERT_EQ(offset, 8u);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 0, 0, 12, 0, 0, 0}));
+  // Check that putting a number to an invalid offset doesn't work and returns
+  // an error offset and doesn't modify the buffer.
+  ASSERT_EQ(encoder.PutU32(init.size(), 15), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 0, 0, 12, 0, 0, 0}));
+}
+
+TEST(DataEncoderTest, PutU32Big) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderBig,
+                      addr_size);
+  offset = encoder.PutU32(offset, 11);
+  ASSERT_EQ(offset, 4U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 0, 0, 11, 5, 6, 7, 8}));
+  offset = encoder.PutU32(offset, 12);
+  ASSERT_EQ(offset, 8U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 0, 0, 11, 0, 0, 0, 12}));
+  // Check that putting a number to an invalid offset doesn't work and returns
+  // an error offset and doesn't modify the buffer.
+  ASSERT_EQ(encoder.PutU32(init.size(), 15), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 0, 0, 11, 0, 0, 0, 12}));
+}
+
+TEST(DataEncoderTest, PutU64Little) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  offset = encoder.PutU64(offset, 11);
+  ASSERT_EQ(offset, 8U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 0, 0, 0, 0, 0, 0}));
+  // Check that putting a number to an invalid offset doesn't work and returns
+  // an error offset and doesn't modify the buffer.
+  ASSERT_EQ(encoder.PutU64(init.size(), 15), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 0, 0, 0, 0, 0, 0, 0}));
+}
+
+TEST(DataEncoderTest, PutU64Big) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderBig,
+                      addr_size);
+  offset = encoder.PutU64(offset, 11);
+  ASSERT_EQ(offset, 8U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 0, 0, 0, 0, 0, 0, 11}));
+  // Check that putting a number to an invalid offset doesn't work and returns
+  // an error offset and doesn't modify the buffer.
+  ASSERT_EQ(encoder.PutU64(init.size(), 15), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0, 0, 0, 0, 0, 0, 0, 11}));
+}
+
+TEST(DataEncoderTest, PutUnsignedLittle) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  // Put only the least significant byte from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 1, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 1U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x88, 2, 3, 4, 5, 6, 7, 8}));
+
+  // Put only the least significant 2 byte2 from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 2, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 2U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x88, 0x77, 3, 4, 5, 6, 7, 8}));
+
+  // Put only the least significant 4 bytes from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 4, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 4U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x88, 0x77, 0x66, 0x55, 5, 6, 7, 8}));
+
+  // Put the full uint64_t value into the encoder
+  offset = encoder.PutUnsigned(0, 8, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 8U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11}));
+}
+
+TEST(DataEncoderTest, PutUnsignedBig) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  uint32_t offset = 0;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderBig,
+                      addr_size);
+  // Put only the least significant byte from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 1, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 1U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x88, 2, 3, 4, 5, 6, 7, 8}));
+
+  // Put only the least significant 2 byte2 from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 2, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 2U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x77, 0x88, 3, 4, 5, 6, 7, 8}));
+
+  // Put only the least significant 4 bytes from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 4, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 4U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x55, 0x66, 0x77, 0x88, 5, 6, 7, 8}));
+
+  // Put the full uint64_t value into the encoder
+  offset = encoder.PutUnsigned(0, 8, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 8U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+}
+
+TEST(DataEncoderTest, PutData) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  char one_byte[] = {11};
+  char two_bytes[] = {12, 13};
+  char to_many_bytes[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  uint32_t offset = 0;
+  // Test putting zero bytes from a invalid array (NULL)
+  offset = encoder.PutData(offset, nullptr, 0);
+  ASSERT_EQ(offset, 0U);
+  ASSERT_EQ(encoder.GetData(), init);
+  // Test putting zero bytes from a valid array
+  offset = encoder.PutData(offset, one_byte, 0);
+  ASSERT_EQ(offset, 0U);
+  ASSERT_EQ(encoder.GetData(), init);
+  // Test putting one byte from a valid array
+  offset = encoder.PutData(offset, one_byte, sizeof(one_byte));
+  ASSERT_EQ(offset, 1U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 2, 3, 4, 5, 6, 7, 8}));
+  offset = encoder.PutData(offset, two_bytes, sizeof(two_bytes));
+  ASSERT_EQ(offset, 3U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 12, 13, 4, 5, 6, 7, 8}));
+  offset = encoder.PutData(0, to_many_bytes, sizeof(to_many_bytes));
+  ASSERT_EQ(offset, UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({11, 12, 13, 4, 5, 6, 7, 8}));
+}
+
+TEST(DataEncoderTest, PutCString) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  // Test putting invalid string pointer
+  ASSERT_EQ(encoder.PutCString(0, nullptr), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(), init);
+  // Test putting an empty string
+  uint32_t offset = 0;
+  offset = encoder.PutCString(offset, "");
+  ASSERT_EQ(offset, 1U);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({'\0', 2, 3, 4, 5, 6, 7, 8}));
+  // Test putting valid C string
+  offset = encoder.PutCString(offset, "hello");
+  ASSERT_EQ(offset, 7U);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({'\0', 'h', 'e', 'l', 'l', 'o', '\0', 8}));
+  // Test putting valid C string but where it won't fit in existing data and
+  // make sure data stay unchanged.
+  offset = encoder.PutCString(offset, "world");
+  ASSERT_EQ(offset, UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({'\0', 'h', 'e', 'l', 'l', 'o', '\0', 8}));
+}
+
+TEST(DataEncoderTest, PutAddressLittle4) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x11223344);
+  ASSERT_EQ(offset, addr_size);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 5, 6, 7, 8}));
+  offset = encoder.PutAddress(offset, 0x55667788);
+  ASSERT_EQ(offset, addr_size*2);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55}));
+  // Make sure we can put an address when it won't fit in the existing buffer
+  // and that the buffer doesn't get modified.
+  ASSERT_EQ(encoder.PutAddress(addr_size+1, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55}));
+  ASSERT_EQ(encoder.PutAddress(addr_size+2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55}));
+  ASSERT_EQ(encoder.PutAddress(addr_size+3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55}));
+  ASSERT_EQ(encoder.PutAddress(addr_size+4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55}));
+}
+
+TEST(DataEncoderTest, PutAddressBig4) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderBig,
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x11223344);
+  ASSERT_EQ(offset, addr_size);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 5, 6, 7, 8}));
+  offset = encoder.PutAddress(offset, 0x55667788);
+  ASSERT_EQ(offset, addr_size*2);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  // Make sure we can put an address when it won't fit in the existing buffer
+  // and that the buffer doesn't get modified.
+  ASSERT_EQ(encoder.PutAddress(addr_size+1, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(addr_size+2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(addr_size+3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(addr_size+4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+}
+
+TEST(DataEncoderTest, PutAddressLittle8) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 8;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderLittle,
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x11223344);
+  ASSERT_EQ(offset, addr_size);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  // Make sure we can put an address when it won't fit in the existing buffer
+  // and that the buffer doesn't get modified.
+  ASSERT_EQ(encoder.PutAddress(1, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.PutAddress(2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.PutAddress(3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.PutAddress(4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.PutAddress(5, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.PutAddress(6, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.PutAddress(7, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.PutAddress(8, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+}
+
+TEST(DataEncoderTest, PutAddressBig8) {
+  const ArrayRef<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 8;
+  DataEncoder encoder(init.data(), init.size(), lldb::eByteOrderBig,
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x1122334455667788);
+  ASSERT_EQ(offset, addr_size);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  // Make sure we can put an address when it won't fit in the existing buffer
+  // and that the buffer doesn't get modified.
+  ASSERT_EQ(encoder.PutAddress(1, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(5, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(6, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(7, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+  ASSERT_EQ(encoder.PutAddress(8, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(encoder.GetData(),
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}));
+}
Index: lldb/unittests/Utility/CMakeLists.txt
===================================================================
--- lldb/unittests/Utility/CMakeLists.txt
+++ lldb/unittests/Utility/CMakeLists.txt
@@ -6,6 +6,7 @@
   BroadcasterTest.cpp
   ConstStringTest.cpp
   CompletionRequestTest.cpp
+  DataEncoderTest.cpp
   DataExtractorTest.cpp
   EnvironmentTest.cpp
   EventTest.cpp
Index: lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp
===================================================================
--- lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp
+++ lldb/unittests/Process/POSIX/NativeProcessELFTest.cpp
@@ -33,14 +33,10 @@
 std::unique_ptr<llvm::MemoryBuffer> CreateAuxvData(
     MockProcessELF &process,
     llvm::ArrayRef<std::pair<AuxVector::EntryType, uint32_t>> auxv_data) {
-  auto addr_size = process.GetAddressByteSize();
-  DataBufferSP buffer_sp(
-      new DataBufferHeap(auxv_data.size() * addr_size * 2, 0));
-  DataEncoder encoder(buffer_sp, process.GetByteOrder(), addr_size);
-  uint32_t offset = 0;
+  DataEncoder encoder(process.GetByteOrder(), process.GetAddressByteSize());
   for (auto &pair : auxv_data) {
-    offset = encoder.PutAddress(offset, pair.first);
-    offset = encoder.PutAddress(offset, pair.second);
+    encoder.AppendAddress(pair.first);
+    encoder.AppendAddress(pair.second);
   }
   return llvm::MemoryBuffer::getMemBufferCopy(
       llvm::toStringRef(buffer_sp->GetData()), "");
Index: lldb/source/Utility/DataEncoder.cpp
===================================================================
--- lldb/source/Utility/DataEncoder.cpp
+++ lldb/source/Utility/DataEncoder.cpp
@@ -8,7 +8,7 @@
 
 #include "lldb/Utility/DataEncoder.h"
 
-#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/DataBufferHeap.h"
 #include "lldb/Utility/Endian.h"
 
 #include "llvm/Support/Endian.h"
@@ -22,91 +22,34 @@
 using namespace lldb_private;
 using namespace llvm::support::endian;
 
-// Default constructor.
 DataEncoder::DataEncoder()
-    : m_byte_order(endian::InlHostByteOrder()), m_addr_size(sizeof(void *)),
-      m_data_sp() {}
+    : m_data_sp(new DataBufferHeap()), m_byte_order(endian::InlHostByteOrder()),
+      m_addr_size(sizeof(void *)) {}
 
-// This constructor allows us to use data that is owned by someone else. The
-// data must stay around as long as this object is valid.
-DataEncoder::DataEncoder(void *data, uint32_t length, ByteOrder endian,
+DataEncoder::DataEncoder(const void *data, uint32_t length, ByteOrder endian,
                          uint8_t addr_size)
-    : m_start(static_cast<uint8_t *>(data)),
-      m_end(static_cast<uint8_t *>(data) + length), m_byte_order(endian),
-      m_addr_size(addr_size), m_data_sp() {}
-
-// Make a shared pointer reference to the shared data in "data_sp" and set the
-// endian swapping setting to "swap", and the address size to "addr_size". The
-// shared data reference will ensure the data lives as long as any DataEncoder
-// objects exist that have a reference to this data.
-DataEncoder::DataEncoder(const DataBufferSP &data_sp, ByteOrder endian,
-                         uint8_t addr_size)
-    : m_start(nullptr), m_end(nullptr), m_byte_order(endian),
-      m_addr_size(addr_size), m_data_sp() {
-  SetData(data_sp);
-}
+    : m_data_sp(new DataBufferHeap(data, length)), m_byte_order(endian),
+      m_addr_size(addr_size) {}
 
-DataEncoder::~DataEncoder() = default;
+DataEncoder::DataEncoder(ByteOrder endian, uint8_t addr_size)
+    : m_data_sp(new DataBufferHeap()), m_byte_order(endian),
+      m_addr_size(addr_size) {}
 
-// Clears the object contents back to a default invalid state, and release any
-// references to shared data that this object may contain.
-void DataEncoder::Clear() {
-  m_start = nullptr;
-  m_end = nullptr;
-  m_byte_order = endian::InlHostByteOrder();
-  m_addr_size = sizeof(void *);
-  m_data_sp.reset();
-}
-
-// Assign the data for this object to be a subrange of the shared data in
-// "data_sp" starting "data_offset" bytes into "data_sp" and ending
-// "data_length" bytes later. If "data_offset" is not a valid offset into
-// "data_sp", then this object will contain no bytes. If "data_offset" is
-// within "data_sp" yet "data_length" is too large, the length will be capped
-// at the number of bytes remaining in "data_sp". A ref counted pointer to the
-// data in "data_sp" will be made in this object IF the number of bytes this
-// object refers to in greater than zero (if at least one byte was available
-// starting at "data_offset") to ensure the data stays around as long as it is
-// needed. The address size and endian swap settings will remain unchanged from
-// their current settings.
-uint32_t DataEncoder::SetData(const DataBufferSP &data_sp, uint32_t data_offset,
-                              uint32_t data_length) {
-  m_start = m_end = nullptr;
-
-  if (data_length > 0) {
-    m_data_sp = data_sp;
-    if (data_sp) {
-      const size_t data_size = data_sp->GetByteSize();
-      if (data_offset < data_size) {
-        m_start = data_sp->GetBytes() + data_offset;
-        const size_t bytes_left = data_size - data_offset;
-        // Cap the length of we asked for too many
-        if (data_length <= bytes_left)
-          m_end = m_start + data_length; // We got all the bytes we wanted
-        else
-          m_end = m_start + bytes_left; // Not all the bytes requested were
-                                        // available in the shared data
-      }
-    }
-  }
-
-  uint32_t new_size = GetByteSize();
-
-  // Don't hold a shared pointer to the data buffer if we don't share any valid
-  // bytes in the shared buffer.
-  if (new_size == 0)
-    m_data_sp.reset();
+DataEncoder::~DataEncoder() = default;
 
-  return new_size;
+llvm::ArrayRef<uint8_t> DataEncoder::GetData() const {
+  return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(), GetByteSize());
 }
 
+size_t DataEncoder::GetByteSize() const { return m_data_sp->GetByteSize(); }
+
 // Extract a single unsigned char from the binary data and update the offset
 // pointed to by "offset_ptr".
 //
 // RETURNS the byte that was extracted, or zero on failure.
 uint32_t DataEncoder::PutU8(uint32_t offset, uint8_t value) {
   if (ValidOffset(offset)) {
-    m_start[offset] = value;
+    m_data_sp->GetBytes()[offset] = value;
     return offset + 1;
   }
   return UINT32_MAX;
@@ -115,9 +58,9 @@
 uint32_t DataEncoder::PutU16(uint32_t offset, uint16_t value) {
   if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
     if (m_byte_order != endian::InlHostByteOrder())
-      write16be(m_start + offset, value);
+      write16be(m_data_sp->GetBytes() + offset, value);
     else
-      write16le(m_start + offset, value);
+      write16le(m_data_sp->GetBytes() + offset, value);
 
     return offset + sizeof(value);
   }
@@ -127,9 +70,9 @@
 uint32_t DataEncoder::PutU32(uint32_t offset, uint32_t value) {
   if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
     if (m_byte_order != endian::InlHostByteOrder())
-      write32be(m_start + offset, value);
+      write32be(m_data_sp->GetBytes() + offset, value);
     else
-      write32le(m_start + offset, value);
+      write32le(m_data_sp->GetBytes() + offset, value);
 
     return offset + sizeof(value);
   }
@@ -139,9 +82,9 @@
 uint32_t DataEncoder::PutU64(uint32_t offset, uint64_t value) {
   if (ValidOffsetForDataOfSize(offset, sizeof(value))) {
     if (m_byte_order != endian::InlHostByteOrder())
-      write64be(m_start + offset, value);
+      write64be(m_data_sp->GetBytes() + offset, value);
     else
-      write64le(m_start + offset, value);
+      write64le(m_data_sp->GetBytes() + offset, value);
 
     return offset + sizeof(value);
   }
@@ -171,7 +114,7 @@
     return offset;
 
   if (ValidOffsetForDataOfSize(offset, src_len)) {
-    memcpy(m_start + offset, src, src_len);
+    memcpy(m_data_sp->GetBytes() + offset, src, src_len);
     return offset + src_len;
   }
   return UINT32_MAX;
@@ -186,3 +129,56 @@
     return PutData(offset, cstr, strlen(cstr) + 1);
   return UINT32_MAX;
 }
+
+void DataEncoder::AppendU8(uint8_t value) {
+  m_data_sp->AppendData(&value, sizeof(value));
+}
+
+void DataEncoder::AppendU16(uint16_t value) {
+  uint32_t offset = m_data_sp->GetByteSize();
+  m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+  PutU16(offset, value);
+}
+
+void DataEncoder::AppendU32(uint32_t value) {
+  uint32_t offset = m_data_sp->GetByteSize();
+  m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+  PutU32(offset, value);
+}
+
+void DataEncoder::AppendU64(uint64_t value) {
+  uint32_t offset = m_data_sp->GetByteSize();
+  m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+  PutU64(offset, value);
+}
+
+void DataEncoder::AppendAddress(lldb::addr_t addr) {
+  switch (m_addr_size) {
+  case 4:
+    AppendU32(addr);
+    break;
+  case 8:
+    AppendU64(addr);
+    break;
+  default:
+    llvm_unreachable("AppendAddress unhandled case!");
+  }
+}
+
+void DataEncoder::AppendData(llvm::StringRef data) {
+  const char *bytes = data.data();
+  const size_t length = data.size();
+  if (bytes && length > 0)
+    m_data_sp->AppendData(bytes, length);
+}
+
+void DataEncoder::AppendCString(llvm::StringRef data) {
+  const char *bytes = data.data();
+  const size_t length = data.size();
+  if (bytes) {
+    if (length > 0)
+      m_data_sp->AppendData(bytes, length);
+    if (length == 0 || bytes[length - 1] != '\0')
+      AppendU8(0);
+  }
+}
Index: lldb/source/Plugins/Platform/Android/AdbClient.cpp
===================================================================
--- lldb/source/Plugins/Platform/Android/AdbClient.cpp
+++ lldb/source/Plugins/Platform/Android/AdbClient.cpp
@@ -584,14 +584,13 @@
 Status AdbClient::SyncService::SendSyncRequest(const char *request_id,
                                                const uint32_t data_len,
                                                const void *data) {
-  const DataBufferSP data_sp(new DataBufferHeap(kSyncPacketLen, 0));
-  DataEncoder encoder(data_sp, eByteOrderLittle, sizeof(void *));
-  auto offset = encoder.PutData(0, request_id, strlen(request_id));
-  encoder.PutUnsigned(offset, 4, data_len);
-
+  DataEncoder encoder(eByteOrderLittle, sizeof(void *));
+  encoder.AppendData(llvm::StringRef(request_id));
+  encoder.AppendU32(data_len);
+  llvm::ArrayRef<uint8_t> bytes = encoder.GetData();
   Status error;
   ConnectionStatus status;
-  m_conn->Write(data_sp->GetBytes(), kSyncPacketLen, status, &error);
+  m_conn->Write(bytes.data(), kSyncPacketLen, status, &error);
   if (error.Fail())
     return error;
 
Index: lldb/source/Expression/DWARFExpression.cpp
===================================================================
--- lldb/source/Expression/DWARFExpression.cpp
+++ lldb/source/Expression/DWARFExpression.cpp
@@ -460,22 +460,19 @@
       // first, then modify it, and if all goes well, we then replace the data
       // for this expression
 
-      // So first we copy the data into a heap buffer
-      std::unique_ptr<DataBufferHeap> head_data_up(
-          new DataBufferHeap(m_data.GetDataStart(), m_data.GetByteSize()));
-
-      // Make en encoder so we can write the address into the buffer using the
-      // correct byte order (endianness)
-      DataEncoder encoder(head_data_up->GetBytes(), head_data_up->GetByteSize(),
+      // Make en encoder that contains a copy of the location expression data
+      // so we can write the address into the buffer using the correct byte
+      // order.
+      DataEncoder encoder(m_data.GetDataStart(), m_data.GetByteSize(),
                           m_data.GetByteOrder(), addr_byte_size);
 
       // Replace the address in the new buffer
-      if (encoder.PutUnsigned(offset, addr_byte_size, file_addr) == UINT32_MAX)
+      if (encoder.PutAddress(offset, file_addr) == UINT32_MAX)
         return false;
 
       // All went well, so now we can reset the data using a shared pointer to
       // the heap data so "m_data" will now correctly manage the heap data.
-      m_data.SetData(DataBufferSP(head_data_up.release()));
+      m_data.SetData(encoder.GetDataBuffer());
       return true;
     } else {
       const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op);
@@ -521,15 +518,11 @@
   // We have to make a copy of the data as we don't know if this data is from a
   // read only memory mapped buffer, so we duplicate all of the data first,
   // then modify it, and if all goes well, we then replace the data for this
-  // expression
-
-  // So first we copy the data into a heap buffer
-  std::shared_ptr<DataBufferHeap> heap_data_sp(
-      new DataBufferHeap(m_data.GetDataStart(), m_data.GetByteSize()));
+  // expression.
 
-  // Make en encoder so we can write the address into the buffer using the
-  // correct byte order (endianness)
-  DataEncoder encoder(heap_data_sp->GetBytes(), heap_data_sp->GetByteSize(),
+  // Make en encoder that contains a copy of the location expression data so we
+  // can write the address into the buffer using the correct byte order.
+  DataEncoder encoder(m_data.GetDataStart(), m_data.GetByteSize(),
                       m_data.GetByteOrder(), addr_byte_size);
 
   lldb::offset_t offset = 0;
@@ -603,7 +596,7 @@
   // and read the
   // TLS data
   m_module_wp = new_module_sp;
-  m_data.SetData(heap_data_sp);
+  m_data.SetData(encoder.GetDataBuffer());
   return true;
 }
 
@@ -2817,4 +2810,3 @@
     return MatchRegOp(*reg)(operand);
   }
 }
-
Index: lldb/include/lldb/lldb-forward.h
===================================================================
--- lldb/include/lldb/lldb-forward.h
+++ lldb/include/lldb/lldb-forward.h
@@ -65,6 +65,7 @@
 class DWARFDataExtractor;
 class DWARFExpression;
 class DataBuffer;
+class DataBufferHeap;
 class DataEncoder;
 class DataExtractor;
 class Debugger;
Index: lldb/include/lldb/Utility/DataEncoder.h
===================================================================
--- lldb/include/lldb/Utility/DataEncoder.h
+++ lldb/include/lldb/Utility/DataEncoder.h
@@ -16,6 +16,9 @@
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-types.h"
 
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+
 #include <cstddef>
 #include <cstdint>
 
@@ -26,21 +29,34 @@
 /// An binary data encoding class.
 ///
 /// DataEncoder is a class that can encode binary data (swapping if needed) to
-/// a data buffer. The data buffer can be caller owned, or can be shared data
-/// that can be shared between multiple DataEncoder or DataEncoder instances.
+/// a data buffer. The DataEncoder can be constructed with data that will be
+/// copied into the internally owned buffer. This allows data to be modified
+/// in the internal buffer. The DataEncoder object can also be constructed with
+/// just a byte order and address size and data can be appended to the
+/// internally owned buffer.
+///
+/// Clients can get a shared pointer to the data buffer when done modifying or
+/// creating the data to keep the data around after the lifetime of a
+/// DataEncoder object. \see GetDataBuffer
 ///
-/// \see DataBuffer
+/// Client can get a reference to the object owned data as an array by calling
+/// the GetData method. \see GetData
 class DataEncoder {
 public:
   /// Default constructor.
   ///
-  /// Initialize all members to a default empty state.
+  /// Initialize all members to a default empty state and create a empty memory
+  /// buffer that can be appended to. The ByteOrder and address size will be set
+  /// to match the current host system.
   DataEncoder();
 
-  /// Construct with a buffer that is owned by the caller.
+  /// Construct an encoder that copies the specified data into the object owned
+  /// data buffer.
   ///
-  /// This constructor allows us to use data that is owned by the caller. The
-  /// data must stay around as long as this object is valid.
+  /// This constructor is designed to be used when you have a data buffer and
+  /// want to modify values within the buffer. A copy of the data will be made
+  /// in the internally owned buffer and that data can be fixed up and appended
+  /// to.
   ///
   /// \param[in] data
   ///     A pointer to caller owned data.
@@ -49,54 +65,37 @@
   ///     The length in bytes of \a data.
   ///
   /// \param[in] byte_order
-  ///     A byte order of the data that we are extracting from.
+  ///     A byte order for the data that will be encoded.
   ///
   /// \param[in] addr_size
-  ///     A new address byte size value.
-  DataEncoder(void *data, uint32_t data_length, lldb::ByteOrder byte_order,
-              uint8_t addr_size);
+  ///     A size of an address in bytes. \see PutAddress, AppendAddress
+  DataEncoder(const void *data, uint32_t data_length,
+              lldb::ByteOrder byte_order, uint8_t addr_size);
 
-  /// Construct with shared data.
+  /// Construct an encoder that owns a heap based memory buffer.
   ///
-  /// Copies the data shared pointer which adds a reference to the contained
-  /// in \a data_sp. The shared data reference is reference counted to ensure
-  /// the data lives as long as anyone still has a valid shared pointer to the
-  /// data in \a data_sp.
-  ///
-  /// \param[in] data_sp
-  ///     A shared pointer to data.
+  /// This allows clients to create binary data from scratch by appending values
+  /// with the methods that start with "Append".
   ///
   /// \param[in] byte_order
-  ///     A byte order of the data that we are extracting from.
+  ///     A byte order for the data that will be encoded.
   ///
   /// \param[in] addr_size
-  ///     A new address byte size value.
-  DataEncoder(const lldb::DataBufferSP &data_sp, lldb::ByteOrder byte_order,
-              uint8_t addr_size);
+  ///     A size of an address in bytes. \see PutAddress, AppendAddress
+  DataEncoder(lldb::ByteOrder byte_order, uint8_t addr_size);
 
-  /// Destructor
-  ///
-  /// If this object contains a valid shared data reference, the reference
-  /// count on the data will be decremented, and if zero, the data will be
-  /// freed.
   ~DataEncoder();
 
-  /// Clears the object state.
-  ///
-  /// Clears the object contents back to a default invalid state, and release
-  /// any references to shared data that this object may contain.
-  void Clear();
-
   /// Encode an unsigned integer of size \a byte_size to \a offset.
   ///
   /// Encode a single integer value at \a offset and return the offset that
   /// follows the newly encoded integer when the data is successfully encoded
-  /// into the existing data. There must be enough room in the data, else
-  /// UINT32_MAX will be returned to indicate that encoding failed.
+  /// into the existing data. There must be enough room in the existing data,
+  /// else UINT32_MAX will be returned to indicate that encoding failed.
   ///
   /// \param[in] offset
-  ///     The offset within the contained data at which to put the
-  ///     encoded integer.
+  ///     The offset within the contained data at which to put the encoded
+  ///     integer.
   ///
   /// \param[in] byte_size
   ///     The size in byte of the integer to encode.
@@ -111,6 +110,64 @@
   ///     was successfully encoded, UINT32_MAX if the encoding failed.
   uint32_t PutUnsigned(uint32_t offset, uint32_t byte_size, uint64_t value);
 
+  /// Encode an unsigned integer at offset \a offset.
+  ///
+  /// Encode a single unsigned integer value at \a offset and return the offset
+  /// that follows the newly encoded integer when the data is successfully
+  /// encoded into the existing data. There must be enough room in the data,
+  /// else UINT32_MAX will be returned to indicate that encoding failed.
+  ///
+  /// \param[in] offset
+  ///     The offset within the contained data at which to put the encoded
+  ///     integer.
+  ///
+  /// \param[in] value
+  ///     The integer value to write.
+  ///
+  /// \return
+  ///     The next offset in the bytes of this data if the integer was
+  ///     successfully encoded, UINT32_MAX if the encoding failed.
+  uint32_t PutU8(uint32_t offset, uint8_t value);
+  uint32_t PutU16(uint32_t offset, uint16_t value);
+  uint32_t PutU32(uint32_t offset, uint32_t value);
+  uint32_t PutU64(uint32_t offset, uint64_t value);
+
+  /// Append a unsigned integer to the end of the owned data.
+  ///
+  /// \param value
+  ///   A unsigned integer value to append.
+  void AppendU8(uint8_t value);
+  void AppendU16(uint16_t value);
+  void AppendU32(uint32_t value);
+  void AppendU64(uint64_t value);
+
+  /// Append an address sized integer to the end of the owned data.
+  ///
+  /// \param addr
+  ///    A unsigned integer address value to append. The size of the address
+  ///    will be determined by the address size specified in the constructor.
+  void AppendAddress(lldb::addr_t addr);
+
+  /// Append a bytes to the end of the owned data.
+  ///
+  /// Append the bytes contained in the string reference. This function will
+  /// not append a NULL termination character for a C string. Use the
+  /// AppendCString function for this purpose.
+  ///
+  /// \param data
+  ///     A string reference that contains bytes to append.
+  void AppendData(llvm::StringRef data);
+
+  /// Append a C string to the end of the owned data.
+  ///
+  /// Append the bytes contained in the string reference along with an extra
+  /// NULL termination character if the StringRef bytes doesn't include one as
+  /// the last byte.
+  ///
+  /// \param data
+  ///     A string reference that contains bytes to append.
+  void AppendCString(llvm::StringRef data);
+
   /// Encode an arbitrary number of bytes.
   ///
   /// \param[in] offset
@@ -131,11 +188,10 @@
   /// Encode an address in the existing buffer at \a offset bytes into the
   /// buffer.
   ///
-  /// Encode a single address (honoring the m_addr_size member) to the data
-  /// and return the next offset where subsequent data would go. pointed to by
-  /// \a offset_ptr. The size of the extracted address comes from the \a
-  /// m_addr_size member variable and should be set correctly prior to
-  /// extracting any address values.
+  /// Encode a single address to the data and return the next offset where
+  /// subsequent data would go. The size of the address comes from the \a
+  /// m_addr_size member variable and should be set correctly prior to encoding
+  /// any address values.
   ///
   /// \param[in] offset
   ///     The offset where to encode the address.
@@ -150,7 +206,10 @@
 
   /// Put a C string to \a offset.
   ///
-  /// Encodes a C string into the existing data including the terminating
+  /// Encodes a C string into the existing data including the terminating. If
+  /// there is not enough room in the buffer to fit the entire C string and the
+  /// NULL terminator in the existing buffer bounds, then this function will
+  /// fail.
   ///
   /// \param[in] offset
   ///     The offset where to encode the string.
@@ -159,18 +218,32 @@
   ///     The string to encode.
   ///
   /// \return
-  ///     A pointer to the C string value in the data. If the offset
-  ///     pointed to by \a offset_ptr is out of bounds, or if the
-  ///     offset plus the length of the C string is out of bounds,
-  ///     NULL will be returned.
+  ///     The next valid offset within data if the put operation was successful,
+  ///     else UINT32_MAX to indicate the put failed.
   uint32_t PutCString(uint32_t offset, const char *cstr);
 
-private:
-  uint32_t PutU8(uint32_t offset, uint8_t value);
-  uint32_t PutU16(uint32_t offset, uint16_t value);
-  uint32_t PutU32(uint32_t offset, uint32_t value);
-  uint32_t PutU64(uint32_t offset, uint64_t value);
+  /// Get a shared copy of the heap based memory buffer owned by this object.
+  ///
+  /// This allows a data encoder to be used to create a data buffer that can
+  /// be extracted and used elsewhere after this object is destroyed.
+  ///
+  /// \return
+  ///     A shared pointer to the DataBufferHeap that contains the data that was
+  ///     encoded into this object.
+  std::shared_ptr<lldb_private::DataBufferHeap> GetDataBuffer() {
+    return m_data_sp;
+  }
 
+  /// Get a access to the bytes that this references.
+  ///
+  /// This value will always return the data that this object references even if
+  /// the object was constructed with caller owned data.
+  ///
+  /// \return
+  ///     A array reference to the data that this object references.
+  llvm::ArrayRef<uint8_t> GetData() const;
+
+private:
   uint32_t BytesLeft(uint32_t offset) const {
     const uint32_t size = GetByteSize();
     if (size > offset)
@@ -187,31 +260,6 @@
     return length <= BytesLeft(offset);
   }
 
-  /// Adopt a subset of shared data in \a data_sp.
-  ///
-  /// Copies the data shared pointer which adds a reference to the contained
-  /// in \a data_sp. The shared data reference is reference counted to ensure
-  /// the data lives as long as anyone still has a valid shared pointer to the
-  /// data in \a data_sp. The byte order and address byte size settings remain
-  /// the same. If \a offset is not a valid offset in \a data_sp, then no
-  /// reference to the shared data will be added. If there are not \a length
-  /// bytes available in \a data starting at \a offset, the length will be
-  /// truncated to contains as many bytes as possible.
-  ///
-  /// \param[in] data_sp
-  ///     A shared pointer to data.
-  ///
-  /// \param[in] offset
-  ///     The offset into \a data_sp at which the subset starts.
-  ///
-  /// \param[in] length
-  ///     The length in bytes of the subset of \a data_sp.
-  ///
-  /// \return
-  ///     The number of bytes that this object now contains.
-  uint32_t SetData(const lldb::DataBufferSP &data_sp, uint32_t offset = 0,
-                   uint32_t length = UINT32_MAX);
-
   /// Test the validity of \a offset.
   ///
   /// \return
@@ -223,25 +271,17 @@
   ///
   /// \return
   ///     The total number of bytes of data this object refers to.
-  size_t GetByteSize() const { return m_end - m_start; }
-
-  /// A pointer to the first byte of data.
-  uint8_t *m_start = nullptr;
+  size_t GetByteSize() const;
 
-  /// A pointer to the byte that is past the end of the data.
-  uint8_t *m_end = nullptr;
+  /// The shared pointer to data that can grow as data is added
+  std::shared_ptr<lldb_private::DataBufferHeap> m_data_sp;
 
-  /// The byte order of the data we are extracting from.
+  /// The byte order of the data we are encoding to.
   lldb::ByteOrder m_byte_order;
 
-  /// The address size to use when extracting pointers or
-  /// addresses
+  /// The address size to use when encoding pointers or addresses.
   uint8_t m_addr_size;
 
-  /// The shared pointer to data that can
-  /// be shared among multiple instances
-  mutable lldb::DataBufferSP m_data_sp;
-
   DataEncoder(const DataEncoder &) = delete;
   const DataEncoder &operator=(const DataEncoder &) = delete;
 };
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to