From ac583610479c63056a64356a1d3bd3b40814f60d Mon Sep 17 00:00:00 2001 From: Greg Clayton Date: Thu, 31 Jul 2014 18:19:28 +0000 Subject: [PATCH] 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 llvm-svn: 214415 --- lldb/include/lldb/Core/Value.h | 5 +- lldb/source/Core/Value.cpp | 64 +++++++- lldb/source/Expression/DWARFExpression.cpp | 253 +++++++++++++++++------------ 3 files changed, 212 insertions(+), 110 deletions(-) diff --git a/lldb/include/lldb/Core/Value.h b/lldb/include/lldb/Core/Value.h index dda1f8d..957cede 100644 --- a/lldb/include/lldb/Core/Value.h +++ b/lldb/include/lldb/Core/Value.h @@ -238,8 +238,11 @@ public: return false; } - void + size_t ResizeData(size_t len); + + size_t + AppendDataToHostBuffer (const Value &rhs); DataBufferHeap & GetBuffer () diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp index 8049d95..db33fce 100644 --- a/lldb/source/Core/Value.cpp +++ b/lldb/source/Core/Value.cpp @@ -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 diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 7844e79..7f87635 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -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: + Value curr_piece; + + 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(); + + const Value::ValueType curr_piece_source_value_type = curr_piece_source_value.GetValueType(); + switch (curr_piece_source_value_type) { - uint32_t bit_size = piece_byte_size * 8; - uint32_t bit_offset = 0; - if (!stack.back().GetScalar().ExtractBitfield (bit_size, bit_offset)) + case Value::eValueTypeLoadAddress: + if (process) { - 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; + 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; - // Multiple pieces of a large value are assembled in a memory buffer value. - if (op_piece_offset) + case Value::eValueTypeScalar: { - Error error; - Scalar cur_piece = stack.back().GetScalar(); - stack.pop_back(); + 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; - switch (stack.back().GetValueType()) + case Value::eValueTypeVector: + { + if (curr_piece_source_value.GetVector().length >= piece_byte_size) + curr_piece_source_value.GetVector().length = piece_byte_size; + else { - 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; + 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; } - } - op_piece_offset += piece_byte_size; + break; + + default: + if (error_ptr) + error_ptr->SetErrorStringWithFormat ("unhandled value typpe for DW_OP_piece(%" PRIu64 ")", piece_byte_size); + return false; + } - break; - case Value::eValueTypeVector: + // Check if this is the first piece? + if (op_piece_offset == 0) { - if (stack.back().GetVector().length >= piece_byte_size) - stack.back().GetVector().length = piece_byte_size; - else + // 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; + // 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()) + { + result = pieces; + } + else + { + if (error_ptr) + error_ptr->SetErrorString ("Stack empty after evaluation."); + return false; + } } - else if (log && log->GetVerbose()) + else { - size_t count = stack.size(); - log->Printf("Stack after operation has %" PRIu64 " values:", (uint64_t)count); - for (size_t i=0; iGetVerbose()) { - StreamString new_value; - new_value.Printf("[%" PRIu64 "]", (uint64_t)i); - stack[i].Dump(&new_value); - log->Printf(" %s", new_value.GetData()); + size_t count = stack.size(); + log->Printf("Stack after operation has %" PRIu64 " values:", (uint64_t)count); + for (size_t i=0; iPrintf(" %s", new_value.GetData()); + } } + result = stack.back(); } - - result = stack.back(); return true; // Return true on success } -- 2.7.4