2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2013-2015, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
8 #include "ValueLoader.h"
10 #include "Architecture.h"
11 #include "BitBuffer.h"
14 #include "TeamMemory.h"
16 #include "ValueLocation.h"
19 ValueLoader::ValueLoader(Architecture
* architecture
, TeamMemory
* teamMemory
,
22 fArchitecture(architecture
),
23 fTeamMemory(teamMemory
),
26 fArchitecture
->AcquireReference();
27 fTeamMemory
->AcquireReference();
28 if (fCpuState
!= NULL
)
29 fCpuState
->AcquireReference();
33 ValueLoader::~ValueLoader()
35 fArchitecture
->ReleaseReference();
36 fTeamMemory
->ReleaseReference();
37 if (fCpuState
!= NULL
)
38 fCpuState
->ReleaseReference();
43 ValueLoader::LoadValue(ValueLocation
* location
, type_code valueType
,
44 bool shortValueIsFine
, BVariant
& _value
)
46 static const size_t kMaxPieceSize
= 16;
47 uint64 totalBitSize
= 0;
48 int32 count
= location
->CountPieces();
49 for (int32 i
= 0; i
< count
; i
++) {
50 ValuePieceLocation piece
= location
->PieceAt(i
);
52 case VALUE_PIECE_LOCATION_INVALID
:
53 case VALUE_PIECE_LOCATION_UNKNOWN
:
54 return B_ENTRY_NOT_FOUND
;
55 case VALUE_PIECE_LOCATION_MEMORY
:
56 case VALUE_PIECE_LOCATION_REGISTER
:
57 case VALUE_PIECE_LOCATION_IMPLICIT
:
61 if (piece
.size
> kMaxPieceSize
) {
62 TRACE_LOCALS(" -> overly long piece size (%" B_PRIu64
" bytes)\n",
67 totalBitSize
+= piece
.bitSize
;
70 TRACE_LOCALS(" -> totalBitSize: %" B_PRIu64
"\n", totalBitSize
);
72 if (totalBitSize
== 0) {
73 TRACE_LOCALS(" -> no size\n");
74 return B_ENTRY_NOT_FOUND
;
77 if (totalBitSize
> 64) {
78 TRACE_LOCALS(" -> longer than 64 bits: unsupported\n");
82 uint64 valueBitSize
= BVariant::SizeOfType(valueType
) * 8;
83 if (!shortValueIsFine
&& totalBitSize
< valueBitSize
) {
84 TRACE_LOCALS(" -> too short for value type (%" B_PRIu64
" vs. %"
85 B_PRIu64
" bits)\n", totalBitSize
, valueBitSize
);
89 // Load the data. Since the BitBuffer class we're using only supports big
90 // endian bit semantics, we convert all data to big endian before pushing
91 // them to the buffer. For later conversion to BVariant we need to make sure
92 // the final buffer has the size of the value type, so we pad the most
93 // significant bits with zeros.
94 BitBuffer valueBuffer
;
95 if (totalBitSize
< valueBitSize
)
96 valueBuffer
.AddZeroBits(valueBitSize
- totalBitSize
);
98 bool bigEndian
= fArchitecture
->IsBigEndian();
99 const Register
* registers
= fArchitecture
->Registers();
100 for (int32 i
= 0; i
< count
; i
++) {
101 ValuePieceLocation piece
= location
->PieceAt(
102 bigEndian
? i
: count
- i
- 1);
103 uint32 bytesToRead
= piece
.size
;
104 uint32 bitSize
= piece
.bitSize
;
105 uint8 bitOffset
= piece
.bitOffset
;
106 // TODO: the offset's ordinal position and direction aren't
107 // specified by DWARF, and simply follow the target language.
108 // To handle non C/C++ languages properly, the corresponding
109 // SourceLanguage will need to be passed in and extended to
110 // return the relevant information.
112 switch (piece
.type
) {
113 case VALUE_PIECE_LOCATION_INVALID
:
114 case VALUE_PIECE_LOCATION_UNKNOWN
:
115 return B_ENTRY_NOT_FOUND
;
116 case VALUE_PIECE_LOCATION_MEMORY
:
117 case VALUE_PIECE_LOCATION_IMPLICIT
:
119 target_addr_t address
= piece
.address
;
121 if (piece
.type
== VALUE_PIECE_LOCATION_MEMORY
) {
122 TRACE_LOCALS(" piece %" B_PRId32
": memory address: %#"
123 B_PRIx64
", bits: %" B_PRIu32
"\n", i
, address
,
126 TRACE_LOCALS(" piece %" B_PRId32
": implicit value, "
127 "bits: %" B_PRIu32
"\n", i
, bitSize
);
130 uint8 pieceBuffer
[kMaxPieceSize
];
132 if (piece
.type
== VALUE_PIECE_LOCATION_MEMORY
) {
133 bytesRead
= fTeamMemory
->ReadMemory(address
,
134 pieceBuffer
, bytesToRead
);
136 memcpy(pieceBuffer
, piece
.value
, piece
.size
);
137 bytesRead
= piece
.size
;
142 if ((uint32
)bytesRead
!= bytesToRead
)
143 return B_BAD_ADDRESS
;
146 TRACE_LOCALS(" -> read: ");
147 for (ssize_t k
= 0; k
< bytesRead
; k
++)
148 TRACE_LOCALS("%02x", pieceBuffer
[k
]);
152 // convert to big endian
154 for (int32 k
= bytesRead
/ 2 - 1; k
>= 0; k
--) {
155 std::swap(pieceBuffer
[k
],
156 pieceBuffer
[bytesRead
- k
- 1]);
160 valueBuffer
.AddBits(pieceBuffer
, bitSize
, bitOffset
);
163 case VALUE_PIECE_LOCATION_REGISTER
:
165 TRACE_LOCALS(" piece %" B_PRId32
": register: %" B_PRIu32
166 ", bits: %" B_PRIu32
"\n", i
, piece
.reg
, bitSize
);
168 if (fCpuState
== NULL
) {
169 WARNING("ValueLoader::LoadValue(): register piece, but no "
171 return B_UNSUPPORTED
;
174 BVariant registerValue
;
175 if (!fCpuState
->GetRegisterValue(registers
+ piece
.reg
,
177 return B_ENTRY_NOT_FOUND
;
179 if (registerValue
.Size() < bytesToRead
)
180 return B_ENTRY_NOT_FOUND
;
183 registerValue
.SwapEndianess();
184 bitOffset
= registerValue
.Size() * 8 - bitOffset
- bitSize
;
186 valueBuffer
.AddBits(registerValue
.Bytes(), bitSize
, bitOffset
);
192 // If we don't have enough bits in the buffer apparently adding some failed.
193 if (valueBuffer
.BitSize() < valueBitSize
)
196 // convert the bits into something we can work with
198 status_t error
= value
.SetToTypedData(valueBuffer
.Bytes(), valueType
);
200 TRACE_LOCALS(" -> failed to set typed data: %s\n", strerror(error
));
204 // convert to host endianess
205 #if B_HOST_IS_LENDIAN
206 value
.SwapEndianess();
215 ValueLoader::LoadRawValue(BVariant
& location
, size_t bytesToRead
, void* _value
)
217 ssize_t bytesRead
= fTeamMemory
->ReadMemory(location
.ToUInt64(),
218 _value
, bytesToRead
);
221 if ((uint32
)bytesRead
!= bytesToRead
)
222 return B_BAD_ADDRESS
;
228 ValueLoader::LoadStringValue(BVariant
& location
, size_t maxSize
, BString
& _value
)
230 static const size_t kMaxStringSize
= 255;
232 return fTeamMemory
->ReadMemoryString(location
.ToUInt64(),
233 std::min(maxSize
, kMaxStringSize
), _value
);