forked from OSchip/llvm-project
Rewrote the initial DW_OP_piece support to be able to support opcodes like:
DW_OP_fbreg(N) DW_OP_piece(4) DW_OP_fbreg(M) DW_OP_piece(8) DW_OP_fbreg(N) DW_OP_piece(4) DW_OP_piece(8) The first grabs 4 bytes from FP+N followed by 8 bytes from FP+M, the second grabs 4 bytes from FP+N followed by zero filling 8 bytes which are unavailable. Of course regiters are stuff supported: DW_OP_reg3 DW_OP_piece(4) DW_OP_reg8 DW_OP_piece(8) The fix does the following: 1 - don't push the full piece value onto the stack, keep it on the side 2 - fill zeros for DW_OP_piece(N) opcodes that have nothing on the stack (instead of previously consuming the full piece that was pushed onto the stack) 3 - simplify the logic <rdar://problem/16930524> llvm-svn: 214415
This commit is contained in:
parent
0f4fbf17f5
commit
ac58361047
|
@ -238,8 +238,11 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
size_t
|
||||
ResizeData(size_t len);
|
||||
|
||||
size_t
|
||||
AppendDataToHostBuffer (const Value &rhs);
|
||||
|
||||
DataBufferHeap &
|
||||
GetBuffer ()
|
||||
|
|
|
@ -172,12 +172,74 @@ Value::GetType()
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
size_t
|
||||
Value::AppendDataToHostBuffer (const Value &rhs)
|
||||
{
|
||||
size_t curr_size = m_data_buffer.GetByteSize();
|
||||
Error error;
|
||||
switch (rhs.GetValueType())
|
||||
{
|
||||
case eValueTypeScalar:
|
||||
{
|
||||
const size_t scalar_size = rhs.m_value.GetByteSize();
|
||||
if (scalar_size > 0)
|
||||
{
|
||||
const size_t new_size = curr_size + scalar_size;
|
||||
if (ResizeData(new_size) == new_size)
|
||||
{
|
||||
rhs.m_value.GetAsMemoryData (m_data_buffer.GetBytes() + curr_size,
|
||||
scalar_size,
|
||||
lldb::endian::InlHostByteOrder(),
|
||||
error);
|
||||
return scalar_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case eValueTypeVector:
|
||||
{
|
||||
const size_t vector_size = rhs.m_vector.length;
|
||||
if (vector_size > 0)
|
||||
{
|
||||
const size_t new_size = curr_size + vector_size;
|
||||
if (ResizeData(new_size) == new_size)
|
||||
{
|
||||
::memcpy (m_data_buffer.GetBytes() + curr_size,
|
||||
rhs.m_vector.bytes,
|
||||
vector_size);
|
||||
return vector_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case eValueTypeFileAddress:
|
||||
case eValueTypeLoadAddress:
|
||||
case eValueTypeHostAddress:
|
||||
{
|
||||
const uint8_t *src = rhs.GetBuffer().GetBytes();
|
||||
const size_t src_len = rhs.GetBuffer().GetByteSize();
|
||||
if (src && src_len > 0)
|
||||
{
|
||||
const size_t new_size = curr_size + src_len;
|
||||
if (ResizeData(new_size) == new_size)
|
||||
{
|
||||
::memcpy (m_data_buffer.GetBytes() + curr_size, src, src_len);
|
||||
return src_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t
|
||||
Value::ResizeData(size_t len)
|
||||
{
|
||||
m_value_type = eValueTypeHostAddress;
|
||||
m_data_buffer.SetByteSize(len);
|
||||
m_value = (uintptr_t)m_data_buffer.GetBytes();
|
||||
return m_data_buffer.GetByteSize();
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -1347,6 +1347,7 @@ DWARFExpression::Evaluate
|
|||
|
||||
/// Insertion point for evaluating multi-piece expression.
|
||||
uint64_t op_piece_offset = 0;
|
||||
Value pieces; // Used for DW_OP_piece
|
||||
|
||||
// Make sure all of the data is available in opcodes.
|
||||
if (!opcodes.ValidOffsetForDataOfSize(opcodes_offset, opcodes_length))
|
||||
|
@ -2574,116 +2575,134 @@ DWARFExpression::Evaluate
|
|||
// variable a particular DWARF expression refers to.
|
||||
//----------------------------------------------------------------------
|
||||
case DW_OP_piece:
|
||||
if (stack.size() < 1 ||
|
||||
(op_piece_offset > 0 && stack.size() < 2))
|
||||
{
|
||||
// In a multi-piece expression, this means that the current piece is not available.
|
||||
// We don't have a way to signal partial availabilty.
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorString("Partially unavailable DW_OP_piece expressions are not yet supported.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint64_t piece_byte_size = opcodes.GetULEB128(&offset);
|
||||
switch (stack.back().GetValueType())
|
||||
|
||||
if (piece_byte_size > 0)
|
||||
{
|
||||
case Value::eValueTypeScalar:
|
||||
case Value::eValueTypeFileAddress:
|
||||
case Value::eValueTypeLoadAddress:
|
||||
case Value::eValueTypeHostAddress:
|
||||
{
|
||||
uint32_t bit_size = piece_byte_size * 8;
|
||||
uint32_t bit_offset = 0;
|
||||
if (!stack.back().GetScalar().ExtractBitfield (bit_size, bit_offset))
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte scalar value.", piece_byte_size, (uint64_t)stack.back().GetScalar().GetByteSize());
|
||||
return false;
|
||||
}
|
||||
Value curr_piece;
|
||||
|
||||
// Multiple pieces of a large value are assembled in a memory buffer value.
|
||||
if (op_piece_offset)
|
||||
{
|
||||
Error error;
|
||||
Scalar cur_piece = stack.back().GetScalar();
|
||||
stack.pop_back();
|
||||
|
||||
switch (stack.back().GetValueType())
|
||||
{
|
||||
case Value::eValueTypeScalar:
|
||||
{
|
||||
// We already have something on the stack that will becomes the first
|
||||
// bytes of our buffer, we need to populate these bytes into the buffer
|
||||
// and then we will add the current bytes to it.
|
||||
|
||||
// Promote top of stack to a memory buffer.
|
||||
Scalar prev_piece = stack.back().GetScalar();
|
||||
stack.pop_back();
|
||||
stack.push_back(Value());
|
||||
Value &piece_value = stack.back();
|
||||
piece_value.ResizeData(op_piece_offset);
|
||||
prev_piece.GetAsMemoryData(piece_value.GetBuffer().GetBytes(), op_piece_offset, lldb::endian::InlHostByteOrder(), error);
|
||||
if (error.Fail())
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorString(error.AsCString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Fall through to host address case...
|
||||
|
||||
case Value::eValueTypeHostAddress:
|
||||
{
|
||||
if (stack.back().GetBuffer().GetByteSize() != op_piece_offset)
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat ("DW_OP_piece for offset %" PRIu64 " but top of stack is of size %" PRIu64,
|
||||
op_piece_offset,
|
||||
stack.back().GetBuffer().GetByteSize());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Append the current piece to the buffer.
|
||||
size_t len = op_piece_offset + piece_byte_size;
|
||||
stack.back().ResizeData(len);
|
||||
cur_piece.GetAsMemoryData (stack.back().GetBuffer().GetBytes() + op_piece_offset,
|
||||
piece_byte_size,
|
||||
lldb::endian::InlHostByteOrder(),
|
||||
error);
|
||||
if (error.Fail())
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorString(error.AsCString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Expect top of stack to be a memory buffer.
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat("DW_OP_piece for offset %" PRIu64 ": top of stack is not a piece", op_piece_offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
op_piece_offset += piece_byte_size;
|
||||
}
|
||||
break;
|
||||
if (stack.empty())
|
||||
{
|
||||
// In a multi-piece expression, this means that the current piece is not available.
|
||||
// Fill with zeros for now by resizing the data and appending it
|
||||
curr_piece.ResizeData(piece_byte_size);
|
||||
::memset (curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
|
||||
pieces.AppendDataToHostBuffer(curr_piece);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error error;
|
||||
// Extract the current piece into "curr_piece"
|
||||
Value curr_piece_source_value(stack.back());
|
||||
stack.pop_back();
|
||||
|
||||
case Value::eValueTypeVector:
|
||||
const Value::ValueType curr_piece_source_value_type = curr_piece_source_value.GetValueType();
|
||||
switch (curr_piece_source_value_type)
|
||||
{
|
||||
if (stack.back().GetVector().length >= piece_byte_size)
|
||||
stack.back().GetVector().length = piece_byte_size;
|
||||
else
|
||||
case Value::eValueTypeLoadAddress:
|
||||
if (process)
|
||||
{
|
||||
if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size)
|
||||
{
|
||||
lldb::addr_t load_addr = curr_piece_source_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
|
||||
if (process->ReadMemory(load_addr, curr_piece.GetBuffer().GetBytes(), piece_byte_size, error) != piece_byte_size)
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat ("failed to read memory DW_OP_piece(%" PRIu64 ") from 0x%" PRIx64,
|
||||
piece_byte_size,
|
||||
load_addr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat ("failed to resize the piece memory buffer for DW_OP_piece(%" PRIu64 ")", piece_byte_size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Value::eValueTypeFileAddress:
|
||||
case Value::eValueTypeHostAddress:
|
||||
if (error_ptr)
|
||||
{
|
||||
lldb::addr_t addr = curr_piece_source_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
|
||||
error_ptr->SetErrorStringWithFormat ("failed to read memory DW_OP_piece(%" PRIu64 ") from %s address 0x%" PRIx64,
|
||||
piece_byte_size,
|
||||
curr_piece_source_value.GetValueType() == Value::eValueTypeFileAddress ? "file" : "host",
|
||||
addr);
|
||||
}
|
||||
return false;
|
||||
|
||||
case Value::eValueTypeScalar:
|
||||
{
|
||||
uint32_t bit_size = piece_byte_size * 8;
|
||||
uint32_t bit_offset = 0;
|
||||
if (!curr_piece_source_value.GetScalar().ExtractBitfield (bit_size, bit_offset))
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte scalar value.", piece_byte_size, (uint64_t)curr_piece_source_value.GetScalar().GetByteSize());
|
||||
return false;
|
||||
}
|
||||
curr_piece = curr_piece_source_value;
|
||||
}
|
||||
break;
|
||||
|
||||
case Value::eValueTypeVector:
|
||||
{
|
||||
if (curr_piece_source_value.GetVector().length >= piece_byte_size)
|
||||
curr_piece_source_value.GetVector().length = piece_byte_size;
|
||||
else
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte vector value.", piece_byte_size, (uint64_t)curr_piece_source_value.GetVector().length);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat ("unhandled value typpe for DW_OP_piece(%" PRIu64 ")", piece_byte_size);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Check if this is the first piece?
|
||||
if (op_piece_offset == 0)
|
||||
{
|
||||
// This is the first piece, we should push it back onto the stack so subsequent
|
||||
// pieces will be able to access this piece and add to it
|
||||
if (pieces.AppendDataToHostBuffer(curr_piece) == 0)
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat("unable to extract %" PRIu64 " bytes from a %" PRIu64 " byte vector value.", piece_byte_size, (uint64_t)stack.back().GetVector().length);
|
||||
error_ptr->SetErrorString("failed to append piece data");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
else if (!stack.empty())
|
||||
{
|
||||
// If this is the second or later piece there should be a value on the stack
|
||||
if (pieces.GetBuffer().GetByteSize() != op_piece_offset)
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorStringWithFormat ("DW_OP_piece for offset %" PRIu64 " but top of stack is of size %" PRIu64,
|
||||
op_piece_offset,
|
||||
pieces.GetBuffer().GetByteSize());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pieces.AppendDataToHostBuffer(curr_piece) == 0)
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorString("failed to append piece data");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
op_piece_offset += piece_byte_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -2702,9 +2721,6 @@ DWARFExpression::Evaluate
|
|||
switch (stack.back().GetValueType())
|
||||
{
|
||||
case Value::eValueTypeScalar:
|
||||
case Value::eValueTypeFileAddress:
|
||||
case Value::eValueTypeLoadAddress:
|
||||
case Value::eValueTypeHostAddress:
|
||||
{
|
||||
if (!stack.back().GetScalar().ExtractBitfield (piece_bit_size, piece_bit_offset))
|
||||
{
|
||||
|
@ -2717,11 +2733,22 @@ DWARFExpression::Evaluate
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case Value::eValueTypeFileAddress:
|
||||
case Value::eValueTypeLoadAddress:
|
||||
case Value::eValueTypeHostAddress:
|
||||
if (error_ptr)
|
||||
{
|
||||
error_ptr->SetErrorStringWithFormat ("unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 ", bit_offset = %" PRIu64 ") from an addresss value.",
|
||||
piece_bit_size,
|
||||
piece_bit_offset);
|
||||
}
|
||||
return false;
|
||||
|
||||
case Value::eValueTypeVector:
|
||||
if (error_ptr)
|
||||
{
|
||||
error_ptr->SetErrorStringWithFormat ("unable to extract %" PRIu64 " bit value with %" PRIu64 " bit offset from a vector value.",
|
||||
error_ptr->SetErrorStringWithFormat ("unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 ", bit_offset = %" PRIu64 ") from a vector value.",
|
||||
piece_bit_size,
|
||||
piece_bit_offset);
|
||||
}
|
||||
|
@ -2896,24 +2923,34 @@ DWARFExpression::Evaluate
|
|||
|
||||
if (stack.empty())
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorString ("Stack empty after evaluation.");
|
||||
return false;
|
||||
}
|
||||
else if (log && log->GetVerbose())
|
||||
{
|
||||
size_t count = stack.size();
|
||||
log->Printf("Stack after operation has %" PRIu64 " values:", (uint64_t)count);
|
||||
for (size_t i=0; i<count; ++i)
|
||||
// Nothing on the stack, check if we created a piece value from DW_OP_piece or DW_OP_bit_piece opcodes
|
||||
if (pieces.GetBuffer().GetByteSize())
|
||||
{
|
||||
StreamString new_value;
|
||||
new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
|
||||
stack[i].Dump(&new_value);
|
||||
log->Printf(" %s", new_value.GetData());
|
||||
result = pieces;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (error_ptr)
|
||||
error_ptr->SetErrorString ("Stack empty after evaluation.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
result = stack.back();
|
||||
else
|
||||
{
|
||||
if (log && log->GetVerbose())
|
||||
{
|
||||
size_t count = stack.size();
|
||||
log->Printf("Stack after operation has %" PRIu64 " values:", (uint64_t)count);
|
||||
for (size_t i=0; i<count; ++i)
|
||||
{
|
||||
StreamString new_value;
|
||||
new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
|
||||
stack[i].Dump(&new_value);
|
||||
log->Printf(" %s", new_value.GetData());
|
||||
}
|
||||
}
|
||||
result = stack.back();
|
||||
}
|
||||
return true; // Return true on success
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue