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

Fixed "DataEncoder::Append*" methods so they return false correctly when used 
on caller owned buffer objects.


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,630 @@
+//===-- 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 std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  offset = encoder.PutU8(offset, 11);
+  ASSERT_EQ(offset, 1U);
+  expected = {11, 2, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU8(offset, 12);
+  ASSERT_EQ(offset, 2U);
+  expected = {11, 12, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU8(offset, 13);
+  ASSERT_EQ(offset, 3U);
+  expected = {11, 12, 13, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU8(offset, 14);
+  ASSERT_EQ(offset, 4U);
+  expected = {11, 12, 13, 14, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer.size(), 15), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, TestAppendFailsOnCallerOwnedBuffer) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> buffer;
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  // Make sure all "Append" methods return false and don't modify the buffer 
+  // on a DataEncoder that has caller owned data.
+  ASSERT_EQ(encoder.AppendAddress(0x11223344), false);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>(init));
+  ASSERT_EQ(encoder.AppendData("\x11"), false);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>(init));
+  ASSERT_EQ(encoder.AppendCString("hello"), false);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>(init));
+  ASSERT_EQ(encoder.AppendU8(12), false);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>(init));
+  ASSERT_EQ(encoder.AppendU16(12), false);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>(init));
+  ASSERT_EQ(encoder.AppendU32(12), false);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>(init));
+  ASSERT_EQ(encoder.AppendU64(12), false);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>(init));
+}
+
+TEST(DataEncoderTest, AppendUnsignedLittle) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderLittle, addr_size);
+  ASSERT_EQ(encoder.AppendU8(0x11), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11}));
+  ASSERT_EQ(encoder.AppendU16(0x2233), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11, 0x33, 0x22}));
+  ASSERT_EQ(encoder.AppendU32(0x44556677), true);
+  ASSERT_EQ(encoder.GetData(), 
+            ArrayRef<uint8_t>({0x11, 0x33, 0x22, 0x77, 0x66, 0x55, 0x44}));
+  ASSERT_EQ(encoder.AppendU64(0x8899AABBCCDDEEFF), true);
+  ASSERT_EQ(encoder.GetData(), 
+            ArrayRef<uint8_t>({0x11, 0x33, 0x22, 0x77, 0x66, 0x55, 0x44,
+                               0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88}));
+  ASSERT_EQ(encoder.AppendU64(0x8899AABBCCDDEEFF), true);
+}
+
+TEST(DataEncoderTest, AppendUnsignedBig) {
+  const uint32_t addr_size = 4;
+  std::vector<uint8_t> expected;
+  DataEncoder encoder(lldb::eByteOrderBig, addr_size);
+  ASSERT_EQ(encoder.AppendU8(0x11), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11}));
+  ASSERT_EQ(encoder.AppendU16(0x2233), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11, 0x22, 0x33}));
+  ASSERT_EQ(encoder.AppendU32(0x44556677), true);
+  ASSERT_EQ(encoder.GetData(), 
+            ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77}));
+  ASSERT_EQ(encoder.AppendU64(0x8899AABBCCDDEEFF), true);
+  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);
+  ASSERT_EQ(encoder.AppendAddress(0x11223344), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11}));
+  ASSERT_EQ(encoder.AppendAddress(0x55), true);
+  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);
+  ASSERT_EQ(encoder.AppendAddress(0x11223344), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({0x11, 0x22, 0x33, 0x44}));
+  ASSERT_EQ(encoder.AppendAddress(0x55), true);
+  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);
+  ASSERT_EQ(encoder.AppendAddress(0x11223344), true);
+  ASSERT_EQ(encoder.GetData(), 
+            ArrayRef<uint8_t>({0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00}));
+  ASSERT_EQ(encoder.AppendAddress(0x5566778899AABBCC), true);
+  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);
+  ASSERT_EQ(encoder.AppendAddress(0x11223344), true);
+  ASSERT_EQ(encoder.GetData(), 
+            ArrayRef<uint8_t>({0x00, 0x00, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44}));
+  ASSERT_EQ(encoder.AppendAddress(0x5566778899AABBCC), true);
+  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
+  ASSERT_EQ(encoder.AppendData(StringRef()), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({}));
+  // Make sure empty StringRef appends nothing
+  ASSERT_EQ(encoder.AppendData(StringRef("")), true);
+  ASSERT_EQ(encoder.GetData(), ArrayRef<uint8_t>({}));
+  // Append some bytes that contains a NULL character
+  ASSERT_EQ(encoder.AppendData(StringRef("\x11\x00\x22", 3)), true);
+  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
+  ASSERT_EQ(encoder.AppendCString(StringRef()), true);
+  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.
+  ASSERT_EQ(encoder.AppendCString(StringRef("")), true);
+  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.
+  ASSERT_EQ(encoder.AppendCString(StringRef("\0", 1)), true);
+  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
+  ASSERT_EQ(encoder.AppendCString(StringRef("hello")), true);
+  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
+  ASSERT_EQ(encoder.AppendCString(StringRef("world", 6)), true);
+  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 std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  offset = encoder.PutU16(offset, 11);
+  ASSERT_EQ(offset, 2U);
+  expected = {11, 0, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU16(offset, 12);
+  ASSERT_EQ(offset, 4U);
+  expected = {11, 0, 12, 0, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU16(offset, 13);
+  ASSERT_EQ(offset, 6U);
+  expected = {11, 0, 12, 0, 13, 0, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU16(offset, 14);
+  ASSERT_EQ(offset, 8U);
+  expected = {11, 0, 12, 0, 13, 0, 14, 0};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer.size(), 15), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutU16Big) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderBig, 
+                      addr_size);
+  offset = encoder.PutU16(offset, 11);
+  ASSERT_EQ(offset, 2U);
+  expected = {0, 11, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU16(offset, 12);
+  ASSERT_EQ(offset, 4U);
+  expected = {0, 11, 0, 12, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU16(offset, 13);
+  ASSERT_EQ(offset, 6U);
+  expected = {0, 11, 0, 12, 0, 13, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU16(offset, 14);
+  ASSERT_EQ(offset, 8U);
+  expected = {0, 11, 0, 12, 0, 13, 0, 14};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer.size(), 15), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutU32Little) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  offset = encoder.PutU32(offset, 11);
+  ASSERT_EQ(offset, 4U);
+  expected = {11, 0, 0, 0, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU32(offset, 12);
+  ASSERT_EQ(offset, 8u);
+  expected = {11, 0, 0, 0, 12, 0, 0, 0};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer.size(), 15), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutU32Big) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderBig, 
+                      addr_size);
+  offset = encoder.PutU32(offset, 11);
+  ASSERT_EQ(offset, 4U);
+  expected = {0, 0, 0, 11, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutU32(offset, 12);
+  ASSERT_EQ(offset, 8U);
+  expected = {0, 0, 0, 11, 0, 0, 0, 12};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer.size(), 15), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutU64Little) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  offset = encoder.PutU64(offset, 11);
+  ASSERT_EQ(offset, 8U);
+  expected = {11, 0, 0, 0, 0, 0, 0, 0};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer.size(), 15), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutU64Big) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderBig, 
+                      addr_size);
+  offset = encoder.PutU64(offset, 11);
+  ASSERT_EQ(offset, 8U);
+  expected = {0, 0, 0, 0, 0, 0, 0, 11};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer.size(), 15), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutUnsignedLittle) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.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);
+  expected = {0x88, 2, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  // Put only the least significant 2 byte2 from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 2, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 2U);
+  expected = {0x88, 0x77, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  // Put only the least significant 4 bytes from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 4, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 4U);
+  expected = {0x88, 0x77, 0x66, 0x55, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  // Put the full uint64_t value into the encoder
+  offset = encoder.PutUnsigned(0, 8, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 8U);
+  expected = {0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11};
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutUnsignedBig) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  uint32_t offset = 0;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.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);
+  expected = {0x88, 2, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  // Put only the least significant 2 byte2 from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 2, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 2U);
+  expected = {0x77, 0x88, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  // Put only the least significant 4 bytes from the uint64_t into the encoder
+  offset = encoder.PutUnsigned(0, 4, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 4U);
+  expected = {0x55, 0x66, 0x77, 0x88, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  // Put the full uint64_t value into the encoder
+  offset = encoder.PutUnsigned(0, 8, 0x1122334455667788ULL);
+  ASSERT_EQ(offset, 8U);
+  expected = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutData) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  // Reset buffer
+  buffer = init;
+  char one_byte[] = {11};
+  char two_bytes[] = {12, 13};
+  char to_many_bytes[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+  DataEncoder encoder(buffer.data(), buffer.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(buffer, init);
+  // Test putting zero bytes from a valid array
+  offset = encoder.PutData(offset, one_byte, 0);
+  ASSERT_EQ(offset, 0U);
+  ASSERT_EQ(buffer, init);
+  // Test putting one byte from a valid array
+  offset = encoder.PutData(offset, one_byte, sizeof(one_byte));
+  ASSERT_EQ(offset, 1U);
+  expected = {11, 2, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  offset = encoder.PutData(offset, two_bytes, sizeof(two_bytes));
+  ASSERT_EQ(offset, 3U);
+  expected = {11, 12, 13, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+
+  offset = encoder.PutData(0, to_many_bytes, sizeof(to_many_bytes));
+  ASSERT_EQ(offset, UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutCString) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  // Test putting invalid string pointer
+  ASSERT_EQ(encoder.PutCString(0, nullptr), UINT32_MAX);
+  ASSERT_EQ(buffer, init);
+  // Test putting an empty string
+  uint32_t offset = 0;
+  offset = encoder.PutCString(offset, "");
+  ASSERT_EQ(offset, 1U);
+  expected = {'\0', 2, 3, 4, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  // Test putting valid C string
+  offset = encoder.PutCString(offset, "hello");
+  ASSERT_EQ(offset, 7U);
+  expected = {'\0', 'h', 'e', 'l', 'l', 'o', '\0', 8};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutAddressLittle4) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x11223344);
+  ASSERT_EQ(offset, addr_size);
+  expected = {0x44, 0x33, 0x22, 0x11, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutAddress(offset, 0x55667788);
+  ASSERT_EQ(offset, addr_size*2);
+  expected = {0x44, 0x33, 0x22, 0x11, 0x88, 0x77, 0x66, 0x55};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(addr_size+2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(addr_size+3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(addr_size+4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutAddressBig4) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 4;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderBig, 
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x11223344);
+  ASSERT_EQ(offset, addr_size);
+  expected = {0x11, 0x22, 0x33, 0x44, 5, 6, 7, 8};
+  ASSERT_EQ(buffer, expected);
+  offset = encoder.PutAddress(offset, 0x55667788);
+  ASSERT_EQ(offset, addr_size*2);
+  expected = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(addr_size+2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(addr_size+3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(addr_size+4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutAddressLittle8) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 8;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderLittle, 
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x11223344);
+  ASSERT_EQ(offset, addr_size);
+  expected = {0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(5, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(6, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(7, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(8, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
+
+TEST(DataEncoderTest, PutAddressBig8) {
+  const std::vector<uint8_t> init = {1, 2, 3, 4, 5, 6, 7, 8};
+  const uint32_t addr_size = 8;
+
+  std::vector<uint8_t> buffer;
+  std::vector<uint8_t> expected;
+  // Reset buffer
+  buffer = init;
+  DataEncoder encoder(buffer.data(), buffer.size(), lldb::eByteOrderBig, 
+                      addr_size);
+  uint32_t offset = 0;
+  offset = encoder.PutAddress(offset, 0x1122334455667788);
+  ASSERT_EQ(offset, addr_size);
+  expected = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88};
+  ASSERT_EQ(buffer, expected);
+  // 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(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(2, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(3, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(4, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(5, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(6, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(7, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+  ASSERT_EQ(encoder.PutAddress(8, 0x10203040), UINT32_MAX);
+  ASSERT_EQ(buffer, expected);
+}
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,15 +33,12 @@
 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);
   }
+  auto buffer_sp = encoder.GetDataBuffer();
   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"
@@ -35,71 +35,12 @@
       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)
+DataEncoder::DataEncoder(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_addr_size(addr_size), m_data_sp(new DataBufferHeap()) {}
 
 DataEncoder::~DataEncoder() = default;
 
-// 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();
-
-  return new_size;
-}
-
 // Extract a single unsigned char from the binary data and update the offset
 // pointed to by "offset_ptr".
 //
@@ -186,3 +127,85 @@
     return PutData(offset, cstr, strlen(cstr) + 1);
   return UINT32_MAX;
 }
+
+void DataEncoder::UpdateMemberVariables() {
+  m_start = m_data_sp->GetBytes();
+  m_end = m_start ? m_start + m_data_sp->GetByteSize() : nullptr;
+}
+
+bool DataEncoder::AppendU8(uint8_t value) {
+  if (!IsDynamic())
+    return false;
+  m_data_sp->AppendData(&value, sizeof(value));
+  UpdateMemberVariables();
+  return true;
+}
+
+bool DataEncoder::AppendU16(uint16_t value) {
+  if (!IsDynamic())
+    return false;
+  uint32_t offset = m_data_sp->GetByteSize();
+  m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+  UpdateMemberVariables();
+  PutU16(offset, value);
+  return true;
+}
+
+bool DataEncoder::AppendU32(uint32_t value) {
+  if (!IsDynamic())
+    return false;
+  uint32_t offset = m_data_sp->GetByteSize();
+  m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+  UpdateMemberVariables();
+  PutU32(offset, value);
+  return true;
+}
+
+bool DataEncoder::AppendU64(uint64_t value) {
+  if (!IsDynamic())
+    return false;
+  uint32_t offset = m_data_sp->GetByteSize();
+  m_data_sp->SetByteSize(m_data_sp->GetByteSize() + sizeof(value));
+  UpdateMemberVariables();
+  PutU64(offset, value);
+  return true;
+}
+
+bool DataEncoder::AppendAddress(lldb::addr_t addr) {
+  switch (m_addr_size) {
+  case 4:
+    return AppendU32(addr);
+  case 8:
+    return AppendU64(addr);
+  default:
+    llvm_unreachable("AppendAddress unhandled case!");
+  }
+  return false;
+}
+
+bool DataEncoder::AppendData(llvm::StringRef data) {
+  if (!IsDynamic())
+    return false;
+  const char *bytes = data.data();
+  const size_t length = data.size();
+  if (bytes && length > 0) {
+    m_data_sp->AppendData(bytes, length);
+    UpdateMemberVariables();
+  }
+  return true;
+}
+
+bool DataEncoder::AppendCString(llvm::StringRef data) {
+  if (!IsDynamic())
+    return false;
+  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')
+      return AppendU8(0);
+    UpdateMemberVariables();
+  }
+  return true;
+}
Index: lldb/source/Plugins/Platform/Android/AdbClient.cpp
===================================================================
--- lldb/source/Plugins/Platform/Android/AdbClient.cpp
+++ lldb/source/Plugins/Platform/Android/AdbClient.cpp
@@ -584,11 +584,10 @@
 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);
+  auto data_sp = encoder.GetDataBuffer();
   Status error;
   ConnectionStatus status;
   m_conn->Write(data_sp->GetBytes(), kSyncPacketLen, status, &error);
Index: lldb/source/Expression/DWARFExpression.cpp
===================================================================
--- lldb/source/Expression/DWARFExpression.cpp
+++ lldb/source/Expression/DWARFExpression.cpp
@@ -470,7 +470,7 @@
                           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
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,10 +29,26 @@
 /// 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. If the data buffer is caller owned, the data within that 
+/// buffer can be modified with the methods that start with "Put". This allows
+/// you to modify an existing buffer as long as the modification are within the
+/// buffer bounds. With caller owned data, none of the "Append" methods will 
+/// work and they will return false and not append anything to the buffer since
+/// the object doesn't own the data and can't grow the buffer. Caller owned data
+/// is created by calling the following constructor:
+///
+/// \see DataEncoder(void *data, uint32_t data_length, 
+///                  lldb::ByteOrder byte_order,
+///                  uint8_t addr_size)
+///
+/// DataEncoder objects can also be used to create binary data that is owned by
+/// this object using a DataBufferHeap. In this case the "Append" methods can
+/// append data and grow the buffer that is needed to contain the new data, and
+/// then the "Put" methods can be used to fixup any data within the owned data.
+/// Object owned data is created when you use the following constructor:
 ///
-/// \see DataBuffer
+/// \see DataEncoder(lldb::ByteOrder byte_order, uint8_t addr_size);
+
 class DataEncoder {
 public:
   /// Default constructor.
@@ -37,10 +56,14 @@
   /// Initialize all members to a default empty state.
   DataEncoder();
 
-  /// Construct with a buffer that is owned by the caller.
+  /// Construct an encoder that points to caller owned data.
   ///
-  /// 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 with methods that start with "Put".
+  /// Any "Put" methods must specify an offset that allows the data to be modified
+  /// within the existing buffer bounds. Calls to "Append" methods will return
+  /// false as appending is now allowed for caller owned buffers since we can't
+  /// dynamically size the buffer data.
   ///
   /// \param[in] data
   ///     A pointer to caller owned data.
@@ -49,30 +72,26 @@
   ///     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.
+  ///     A size of an address in bytes. \see PutAddress
   DataEncoder(void *data, uint32_t data_length, lldb::ByteOrder byte_order,
               uint8_t addr_size);
 
-  /// Construct with shared data.
-  ///
-  /// 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.
+  /// Construct an encoder that owns a heap based memory buffer.
   ///
-  /// \param[in] data_sp
-  ///     A shared pointer to data.
+  /// A dynamic memory buffer will be created that can grow as data is encoded.
+  /// Any of the member functions that start with "Append" can be used to append
+  /// data to the buffer. The member functions that start with "Put" can be
+  /// used to fixup any data that was previously appended to the buffer.
   ///
   /// \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
   ///
@@ -81,12 +100,6 @@
   /// 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
@@ -111,6 +124,84 @@
   ///     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.
+  ///
+  /// \return
+  ///   Return true if the data was successfully appended, false if the buffer
+  ///   is not dynamic.
+  bool AppendU8(uint8_t value);
+  bool AppendU16(uint16_t value);
+  bool AppendU32(uint32_t value);
+  bool 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.
+  ///
+  /// \return
+  ///   Return true if the data was successfully appended, false if the buffer
+  ///   is not dynamic.
+  bool 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.
+  ///
+  /// This function will only work if the object returns true to 
+  /// DataEncoder::IsDynamic(), otherwise UINT32_MAX will be returned to 
+  /// indicate failure.
+  /// 
+  /// \param data
+  ///   A string reference that contains bytes to append.
+  ///
+  /// \return
+  ///   Return true if the data was successfully appended, false if the buffer
+  ///   is not dynamic.
+  bool 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.
+  ///
+  /// \return
+  ///   Return true if the data was successfully appended, false if the buffer
+  ///   is not dynamic.
+  bool AppendCString(llvm::StringRef data);
+
   /// Encode an arbitrary number of bytes.
   ///
   /// \param[in] offset
@@ -165,11 +256,39 @@
   ///     NULL will be returned.
   uint32_t PutCString(uint32_t offset, const char *cstr);
 
+  /// Get a shared copy of the heap based memory buffer owned by this object.
+  ///
+  /// This value will be empty if the DataEncoder object was constructed with
+  /// caller owned data.
+  ///
+  /// \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() { 
+    return llvm::ArrayRef<uint8_t>(m_start, GetByteSize()); 
+  }
+
 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);
+  /// Return if this object has a dynamic buffer that can be appended to.
+  ///
+  /// The buffer is dynamic if the "m_data_sp" is valid. "m_data_sp" is only set
+  /// by constructors mentioned below.
+  ///
+  /// \see DataEncoder(lldb::ByteOrder byte_order, uint8_t addr_size);
+  bool IsDynamic() const {
+    return (bool)m_data_sp;
+  }
 
   uint32_t BytesLeft(uint32_t offset) const {
     const uint32_t size = GetByteSize();
@@ -187,30 +306,12 @@
     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.
+  /// Update the m_start and m_end after appending 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);
+  /// Any of the member functions that append data to the end of the owned 
+  /// data should call this function after appending data to update the required
+  /// member variables.
+  void UpdateMemberVariables();
 
   /// Test the validity of \a offset.
   ///
@@ -238,9 +339,8 @@
   /// addresses
   uint8_t m_addr_size;
 
-  /// The shared pointer to data that can
-  /// be shared among multiple instances
-  mutable lldb::DataBufferSP m_data_sp;
+  /// The shared pointer to data that can grow as data is added
+  mutable std::shared_ptr<lldb_private::DataBufferHeap> 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