2 * TargetValue.cpp -- Access to target values using OMPD callbacks
5 //===----------------------------------------------------------------------===//
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
11 //===----------------------------------------------------------------------===//
13 #include "TargetValue.h"
20 const ompd_callbacks_t
*TValue::callbacks
= NULL
;
21 ompd_device_type_sizes_t
TValue::type_sizes
;
23 inline int ompd_sizeof(ompd_target_prim_types_t t
) {
24 assert(t
!= ompd_type_max
&& "ompd_type_max should not be used anywhere");
25 assert(t
!= ompd_type_invalid
&& "request size of invalid type");
27 return (((char *)&TValue::type_sizes
)[(int)t
]);
30 TType
&TTypeFactory::getType(ompd_address_space_context_t
*context
,
31 const char *typeName
, ompd_addr_t segment
) {
34 if (ttypes
.find(context
) == ttypes
.end()) {
35 std::map
<const char *, TType
> empty
;
36 ttypes
[context
] = empty
;
39 auto t
= ttypes
.find(context
);
40 auto i
= t
->second
.find(typeName
);
41 if (i
== t
->second
.end())
43 i
, std::make_pair(typeName
, TType(context
, typeName
, segment
)));
45 i
->second
.context
= context
;
50 TType::TType(ompd_address_space_context_t
*_context
, const char *_typeName
,
52 : typeSize(0), fieldOffsets(), descSegment(_segment
), typeName(_typeName
),
53 context(_context
), isvoid(false) {}
55 ompd_rc_t
TType::getSize(ompd_size_t
*size
) {
56 ompd_rc_t ret
= ompd_rc_ok
;
58 ompd_address_t symbolAddr
;
61 ss
<< "ompd_sizeof__" << typeName
;
63 ret
= TValue::callbacks
->symbol_addr_lookup(context
, NULL
, ss
.str().c_str(),
65 if (ret
!= ompd_rc_ok
) {
66 dout
<< "missing symbol " << ss
.str()
67 << " add this to ompd-specific.h:\nOMPD_SIZEOF(" << typeName
68 << ") \\" << std::endl
;
72 symbolAddr
.segment
= descSegment
;
74 ret
= TValue::callbacks
->read_memory(
75 context
, NULL
, &symbolAddr
, 1 * TValue::type_sizes
.sizeof_long_long
,
77 if (ret
!= ompd_rc_ok
)
79 ret
= TValue::callbacks
->device_to_host(
80 context
, &tmpSize
, TValue::type_sizes
.sizeof_long_long
, 1, &(typeSize
));
86 ompd_rc_t
TType::getBitfieldMask(const char *fieldName
,
87 uint64_t *bitfieldmask
) {
88 ompd_rc_t ret
= ompd_rc_ok
;
89 auto i
= bitfieldMasks
.find(fieldName
);
90 if (i
== bitfieldMasks
.end()) {
91 uint64_t tmpMask
, bitfieldMask
;
92 ompd_address_t symbolAddr
;
94 ss
<< "ompd_bitfield__" << typeName
<< "__" << fieldName
;
95 ret
= TValue::callbacks
->symbol_addr_lookup(context
, NULL
, ss
.str().c_str(),
97 if (ret
!= ompd_rc_ok
) {
98 dout
<< "missing symbol " << ss
.str()
99 << " add this to ompd-specific.h:\nOMPD_BITFIELD(" << typeName
<< ","
100 << fieldName
<< ") \\" << std::endl
;
103 symbolAddr
.segment
= descSegment
;
105 ret
= TValue::callbacks
->read_memory(
106 context
, NULL
, &symbolAddr
, 1 * TValue::type_sizes
.sizeof_long_long
,
108 if (ret
!= ompd_rc_ok
)
110 ret
= TValue::callbacks
->device_to_host(context
, &(tmpMask
),
111 TValue::type_sizes
.sizeof_long_long
,
113 if (ret
!= ompd_rc_ok
) {
116 i
= bitfieldMasks
.insert(i
, std::make_pair(fieldName
, bitfieldMask
));
118 *bitfieldmask
= i
->second
;
122 ompd_rc_t
TType::getElementOffset(const char *fieldName
, ompd_size_t
*offset
) {
123 ompd_rc_t ret
= ompd_rc_ok
;
124 auto i
= fieldOffsets
.find(fieldName
);
125 if (i
== fieldOffsets
.end()) {
126 ompd_size_t tmpOffset
, fieldOffset
;
127 ompd_address_t symbolAddr
;
128 std::stringstream ss
;
129 ss
<< "ompd_access__" << typeName
<< "__" << fieldName
;
131 ret
= TValue::callbacks
->symbol_addr_lookup(context
, NULL
, ss
.str().c_str(),
133 if (ret
!= ompd_rc_ok
) {
134 dout
<< "missing symbol " << ss
.str()
135 << " add this to ompd-specific.h:\nOMPD_ACCESS(" << typeName
<< ","
136 << fieldName
<< ") \\" << std::endl
;
139 symbolAddr
.segment
= descSegment
;
141 ret
= TValue::callbacks
->read_memory(
142 context
, NULL
, &symbolAddr
, 1 * TValue::type_sizes
.sizeof_long_long
,
144 if (ret
!= ompd_rc_ok
)
146 ret
= TValue::callbacks
->device_to_host(context
, &(tmpOffset
),
147 TValue::type_sizes
.sizeof_long_long
,
149 if (ret
!= ompd_rc_ok
) {
152 i
= fieldOffsets
.insert(i
, std::make_pair(fieldName
, fieldOffset
));
158 ompd_rc_t
TType::getElementSize(const char *fieldName
, ompd_size_t
*size
) {
159 ompd_rc_t ret
= ompd_rc_ok
;
160 auto i
= fieldSizes
.find(fieldName
);
161 if (i
== fieldSizes
.end()) {
162 ompd_size_t tmpOffset
, fieldSize
;
163 ompd_address_t symbolAddr
;
164 std::stringstream ss
;
165 ss
<< "ompd_sizeof__" << typeName
<< "__" << fieldName
;
167 ret
= TValue::callbacks
->symbol_addr_lookup(context
, NULL
, ss
.str().c_str(),
169 if (ret
!= ompd_rc_ok
) {
170 dout
<< "missing symbol " << ss
.str()
171 << " add this to ompd-specific.h:\nOMPD_ACCESS(" << typeName
<< ","
172 << fieldName
<< ") \\" << std::endl
;
175 symbolAddr
.segment
= descSegment
;
177 ret
= TValue::callbacks
->read_memory(
178 context
, NULL
, &symbolAddr
, 1 * TValue::type_sizes
.sizeof_long_long
,
180 if (ret
!= ompd_rc_ok
)
182 ret
= TValue::callbacks
->device_to_host(context
, &tmpOffset
,
183 TValue::type_sizes
.sizeof_long_long
,
185 if (ret
!= ompd_rc_ok
) {
188 i
= fieldSizes
.insert(i
, std::make_pair(fieldName
, fieldSize
));
194 TValue::TValue(ompd_address_space_context_t
*_context
,
195 ompd_thread_context_t
*_tcontext
, const char *_valueName
,
197 : errorState(ompd_rc_ok
), type(&nullType
), pointerLevel(0),
198 context(_context
), tcontext(_tcontext
), fieldSize(0) {
199 errorState
.errorCode
= callbacks
->symbol_addr_lookup(
200 context
, tcontext
, _valueName
, &symbolAddr
, NULL
);
201 symbolAddr
.segment
= segment
;
204 TValue::TValue(ompd_address_space_context_t
*_context
,
205 ompd_thread_context_t
*_tcontext
, ompd_address_t addr
)
206 : errorState(ompd_rc_ok
), type(&nullType
), pointerLevel(0),
207 context(_context
), tcontext(_tcontext
), symbolAddr(addr
), fieldSize(0) {
208 if (addr
.address
== 0)
209 errorState
.errorCode
= ompd_rc_bad_input
;
212 TValue
&TValue::cast(const char *typeName
) {
215 type
= &tf
.getType(context
, typeName
, symbolAddr
.segment
);
217 assert(!type
->isVoid() && "cast to invalid type failed");
221 TValue
&TValue::cast(const char *typeName
, int _pointerLevel
,
222 ompd_addr_t segment
) {
225 type
= &tf
.getType(context
, typeName
, symbolAddr
.segment
);
226 pointerLevel
= _pointerLevel
;
227 symbolAddr
.segment
= segment
;
228 assert(!type
->isVoid() && "cast to invalid type failed");
232 TValue
TValue::dereference() const {
235 ompd_address_t tmpAddr
;
236 assert(!type
->isVoid() && "cannot work with void");
237 assert(pointerLevel
> 0 && "cannot dereference non-pointer");
240 ret
.errorState
.errorCode
= callbacks
->read_memory(
241 context
, tcontext
, &symbolAddr
, 1 * TValue::type_sizes
.sizeof_pointer
,
243 if (ret
.errorState
.errorCode
!= ompd_rc_ok
)
246 ret
.errorState
.errorCode
= callbacks
->device_to_host(
247 context
, &(tmpAddr
.address
), TValue::type_sizes
.sizeof_pointer
, 1,
248 &(ret
.symbolAddr
.address
));
249 if (ret
.errorState
.errorCode
!= ompd_rc_ok
) {
252 if (ret
.symbolAddr
.address
== 0)
253 ret
.errorState
.errorCode
= ompd_rc_unsupported
;
257 ompd_rc_t
TValue::getAddress(ompd_address_t
*addr
) const {
259 if (symbolAddr
.address
== 0)
260 return ompd_rc_unsupported
;
261 return errorState
.errorCode
;
264 ompd_rc_t
TValue::getRawValue(void *buf
, int count
) {
265 if (errorState
.errorCode
!= ompd_rc_ok
)
266 return errorState
.errorCode
;
268 errorState
.errorCode
= type
->getSize(&size
);
269 if (errorState
.errorCode
!= ompd_rc_ok
)
270 return errorState
.errorCode
;
272 errorState
.errorCode
=
273 callbacks
->read_memory(context
, tcontext
, &symbolAddr
, size
, buf
);
274 return errorState
.errorCode
;
277 ompd_rc_t
TValue::getString(const char **buf
) {
282 TValue strValue
= dereference();
283 if (strValue
.gotError()) {
284 return strValue
.getError();
288 return ompd_rc_error
;
294 // Allocate an extra byte, but pass only BUF_LEN to the tool
295 // so that we can detect truncation later.
296 ret
= callbacks
->alloc_memory(BUF_LEN
+ 1, (void **)&string_buffer
);
297 if (ret
!= ompd_rc_ok
) {
300 string_buffer
[BUF_LEN
] = '\0';
302 // TODO: if we have not read in the complete string, we need to realloc
303 // 'string_buffer' and attempt reading again repeatedly till the entire string
305 ret
= callbacks
->read_string(context
, tcontext
, &strValue
.symbolAddr
, BUF_LEN
,
306 (void *)string_buffer
);
307 *buf
= string_buffer
;
308 // Check for truncation. The standard specifies that if a null byte is not
309 // among the first 'nbytes' bytes, the string placed in the buffer is not
310 // null-terminated. 'nbytes' is BUF_LEN in this case.
311 if (ret
== ompd_rc_ok
&& strlen(string_buffer
) == BUF_LEN
) {
312 return ompd_rc_error
;
317 TBaseValue
TValue::castBase(const char *varName
) {
319 errorState
.errorCode
=
320 tf
.getType(context
, varName
, symbolAddr
.segment
).getSize(&size
);
321 return TBaseValue(*this, size
);
324 TBaseValue
TValue::castBase() const {
325 if (pointerLevel
> 0)
326 return TBaseValue(*this, type_sizes
.sizeof_pointer
);
327 return TBaseValue(*this, fieldSize
);
330 TBaseValue
TValue::castBase(ompd_target_prim_types_t baseType
) const {
331 return TBaseValue(*this, baseType
);
334 TValue
TValue::access(const char *fieldName
) const {
338 assert(pointerLevel
< 2 && "access to field element of pointer array failed");
339 if (pointerLevel
== 1) // -> operator
340 ret
= ret
.dereference();
341 // we use *this for . operator
343 ret
.errorState
.errorCode
= type
->getElementOffset(fieldName
, &offset
);
344 ret
.errorState
.errorCode
= type
->getElementSize(fieldName
, &(ret
.fieldSize
));
345 ret
.symbolAddr
.address
+= offset
;
350 ompd_rc_t
TValue::check(const char *bitfieldName
, ompd_word_t
*isSet
) const {
354 uint64_t bitfieldmask
;
355 ompd_rc_t ret
= this->castBase(ompd_type_int
).getValue(&bitfield
, 1);
356 if (ret
!= ompd_rc_ok
)
358 ret
= type
->getBitfieldMask(bitfieldName
, &bitfieldmask
);
359 *isSet
= ((bitfield
& bitfieldmask
) != 0);
363 TValue
TValue::getArrayElement(int elemNumber
) const {
367 if (pointerLevel
> 0) {
372 if (ret
.pointerLevel
== 0) {
374 ret
.errorState
.errorCode
= type
->getSize(&size
);
375 ret
.symbolAddr
.address
+= elemNumber
* size
;
377 ret
.symbolAddr
.address
+= elemNumber
* type_sizes
.sizeof_pointer
;
382 TValue
TValue::getPtrArrayElement(int elemNumber
) const {
386 assert(pointerLevel
> 0 && "This only works on arrays of pointers");
388 ret
.symbolAddr
.address
+= elemNumber
* type_sizes
.sizeof_pointer
;
392 TBaseValue::TBaseValue(const TValue
&_tvalue
,
393 ompd_target_prim_types_t _baseType
)
394 : TValue(_tvalue
), baseTypeSize(ompd_sizeof(_baseType
)) {}
395 TBaseValue::TBaseValue(const TValue
&_tvalue
, ompd_size_t _baseTypeSize
)
396 : TValue(_tvalue
), baseTypeSize(_baseTypeSize
) {}
398 ompd_rc_t
TBaseValue::getValue(void *buf
, int count
) {
399 if (errorState
.errorCode
!= ompd_rc_ok
)
400 return errorState
.errorCode
;
401 errorState
.errorCode
= callbacks
->read_memory(context
, tcontext
, &symbolAddr
,
402 count
* baseTypeSize
, buf
);
403 if (errorState
.errorCode
!= ompd_rc_ok
)
404 return errorState
.errorCode
;
405 errorState
.errorCode
=
406 callbacks
->device_to_host(context
, buf
, baseTypeSize
, count
, buf
);
407 return errorState
.errorCode
;