1/*
2 * TargetValue.cpp -- Access to target values using OMPD callbacks
3 */
4
5//===----------------------------------------------------------------------===//
6//
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
10//
11//===----------------------------------------------------------------------===//
12
13#include "TargetValue.h"
14#include "Debug.h"
15#include <cstring>
16#include <fstream>
17#include <iostream>
18#include <sstream>
19
20const ompd_callbacks_t *TValue::callbacks = NULL;
21ompd_device_type_sizes_t TValue::type_sizes;
22
23inline 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");
26
27 return (((char *)&TValue::type_sizes)[(int)t]);
28}
29
30TType &TTypeFactory::getType(ompd_address_space_context_t *context,
31 const char *typeName, ompd_addr_t segment) {
32 TType empty(true);
33
34 if (ttypes.find(x: context) == ttypes.end()) {
35 std::map<const char *, TType> empty;
36 ttypes[context] = empty;
37 }
38
39 auto t = ttypes.find(x: context);
40 auto i = t->second.find(x: typeName);
41 if (i == t->second.end())
42 i = t->second.insert(
43 position: i, x: std::make_pair(x&: typeName, y: TType(context, typeName, segment)));
44 else
45 i->second.context = context;
46
47 return i->second;
48}
49
50TType::TType(ompd_address_space_context_t *_context, const char *_typeName,
51 ompd_addr_t _segment)
52 : typeSize(0), fieldOffsets(), descSegment(_segment), typeName(_typeName),
53 context(_context), isvoid(false) {}
54
55ompd_rc_t TType::getSize(ompd_size_t *size) {
56 ompd_rc_t ret = ompd_rc_ok;
57 if (typeSize == 0) {
58 ompd_address_t symbolAddr;
59 ompd_size_t tmpSize;
60 std::stringstream ss;
61 ss << "ompd_sizeof__" << typeName;
62
63 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
64 &symbolAddr, NULL);
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;
69 return ret;
70 }
71
72 symbolAddr.segment = descSegment;
73
74 ret = TValue::callbacks->read_memory(
75 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
76 &(tmpSize));
77 if (ret != ompd_rc_ok)
78 return ret;
79 ret = TValue::callbacks->device_to_host(
80 context, &tmpSize, TValue::type_sizes.sizeof_long_long, 1, &(typeSize));
81 }
82 *size = typeSize;
83 return ret;
84}
85
86ompd_rc_t TType::getBitfieldMask(const char *fieldName,
87 uint64_t *bitfieldmask) {
88 ompd_rc_t ret = ompd_rc_ok;
89 auto i = bitfieldMasks.find(x: fieldName);
90 if (i == bitfieldMasks.end()) {
91 uint64_t tmpMask, bitfieldMask;
92 ompd_address_t symbolAddr;
93 std::stringstream ss;
94 ss << "ompd_bitfield__" << typeName << "__" << fieldName;
95 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
96 &symbolAddr, NULL);
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;
101 return ret;
102 }
103 symbolAddr.segment = descSegment;
104
105 ret = TValue::callbacks->read_memory(
106 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
107 &(tmpMask));
108 if (ret != ompd_rc_ok)
109 return ret;
110 ret = TValue::callbacks->device_to_host(context, &(tmpMask),
111 TValue::type_sizes.sizeof_long_long,
112 1, &(bitfieldMask));
113 if (ret != ompd_rc_ok) {
114 return ret;
115 }
116 i = bitfieldMasks.insert(position: i, x: std::make_pair(x&: fieldName, y&: bitfieldMask));
117 }
118 *bitfieldmask = i->second;
119 return ret;
120}
121
122ompd_rc_t TType::getElementOffset(const char *fieldName, ompd_size_t *offset) {
123 ompd_rc_t ret = ompd_rc_ok;
124 auto i = fieldOffsets.find(x: 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;
130
131 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
132 &symbolAddr, NULL);
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;
137 return ret;
138 }
139 symbolAddr.segment = descSegment;
140
141 ret = TValue::callbacks->read_memory(
142 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
143 &(tmpOffset));
144 if (ret != ompd_rc_ok)
145 return ret;
146 ret = TValue::callbacks->device_to_host(context, &(tmpOffset),
147 TValue::type_sizes.sizeof_long_long,
148 1, &fieldOffset);
149 if (ret != ompd_rc_ok) {
150 return ret;
151 }
152 i = fieldOffsets.insert(position: i, x: std::make_pair(x&: fieldName, y&: fieldOffset));
153 }
154 *offset = i->second;
155 return ret;
156}
157
158ompd_rc_t TType::getElementSize(const char *fieldName, ompd_size_t *size) {
159 ompd_rc_t ret = ompd_rc_ok;
160 auto i = fieldSizes.find(x: 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;
166
167 ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
168 &symbolAddr, NULL);
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;
173 return ret;
174 }
175 symbolAddr.segment = descSegment;
176
177 ret = TValue::callbacks->read_memory(
178 context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
179 &(tmpOffset));
180 if (ret != ompd_rc_ok)
181 return ret;
182 ret = TValue::callbacks->device_to_host(context, &tmpOffset,
183 TValue::type_sizes.sizeof_long_long,
184 1, &fieldSize);
185 if (ret != ompd_rc_ok) {
186 return ret;
187 }
188 i = fieldSizes.insert(position: i, x: std::make_pair(x&: fieldName, y&: fieldSize));
189 }
190 *size = i->second;
191 return ret;
192}
193
194TValue::TValue(ompd_address_space_context_t *_context,
195 ompd_thread_context_t *_tcontext, const char *_valueName,
196 ompd_addr_t segment)
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;
202}
203
204TValue::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;
210}
211
212TValue &TValue::cast(const char *typeName) {
213 if (gotError())
214 return *this;
215 type = &tf.getType(context, typeName, segment: symbolAddr.segment);
216 pointerLevel = 0;
217 assert(!type->isVoid() && "cast to invalid type failed");
218 return *this;
219}
220
221TValue &TValue::cast(const char *typeName, int _pointerLevel,
222 ompd_addr_t segment) {
223 if (gotError())
224 return *this;
225 type = &tf.getType(context, typeName, segment: symbolAddr.segment);
226 pointerLevel = _pointerLevel;
227 symbolAddr.segment = segment;
228 assert(!type->isVoid() && "cast to invalid type failed");
229 return *this;
230}
231
232TValue TValue::dereference() const {
233 if (gotError())
234 return *this;
235 ompd_address_t tmpAddr;
236 assert(!type->isVoid() && "cannot work with void");
237 assert(pointerLevel > 0 && "cannot dereference non-pointer");
238 TValue ret = *this;
239 ret.pointerLevel--;
240 ret.errorState.errorCode = callbacks->read_memory(
241 context, tcontext, &symbolAddr, 1 * TValue::type_sizes.sizeof_pointer,
242 &(tmpAddr.address));
243 if (ret.errorState.errorCode != ompd_rc_ok)
244 return ret;
245
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) {
250 return ret;
251 }
252 if (ret.symbolAddr.address == 0)
253 ret.errorState.errorCode = ompd_rc_unsupported;
254 return ret;
255}
256
257ompd_rc_t TValue::getAddress(ompd_address_t *addr) const {
258 *addr = symbolAddr;
259 if (symbolAddr.address == 0)
260 return ompd_rc_unsupported;
261 return errorState.errorCode;
262}
263
264ompd_rc_t TValue::getRawValue(void *buf, int count) {
265 if (errorState.errorCode != ompd_rc_ok)
266 return errorState.errorCode;
267 ompd_size_t size;
268 errorState.errorCode = type->getSize(size: &size);
269 if (errorState.errorCode != ompd_rc_ok)
270 return errorState.errorCode;
271
272 errorState.errorCode =
273 callbacks->read_memory(context, tcontext, &symbolAddr, size, buf);
274 return errorState.errorCode;
275}
276
277ompd_rc_t TValue::getString(const char **buf) {
278 *buf = 0;
279 if (gotError())
280 return getError();
281
282 TValue strValue = dereference();
283 if (strValue.gotError()) {
284 return strValue.getError();
285 }
286
287 if (!callbacks) {
288 return ompd_rc_error;
289 }
290 ompd_rc_t ret;
291#define BUF_LEN 512
292 char *string_buffer;
293
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) {
298 return ret;
299 }
300 string_buffer[BUF_LEN] = '\0';
301
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
304 // is read in.
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(s: string_buffer) == BUF_LEN) {
312 return ompd_rc_error;
313 }
314 return ret;
315}
316
317TBaseValue TValue::castBase(const char *varName) {
318 ompd_size_t size;
319 errorState.errorCode =
320 tf.getType(context, typeName: varName, segment: symbolAddr.segment).getSize(size: &size);
321 return TBaseValue(*this, size);
322}
323
324TBaseValue TValue::castBase() const {
325 if (pointerLevel > 0)
326 return TBaseValue(*this, type_sizes.sizeof_pointer);
327 return TBaseValue(*this, fieldSize);
328}
329
330TBaseValue TValue::castBase(ompd_target_prim_types_t baseType) const {
331 return TBaseValue(*this, baseType);
332}
333
334TValue TValue::access(const char *fieldName) const {
335 if (gotError())
336 return *this;
337 TValue ret = *this;
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
342 ompd_size_t offset;
343 ret.errorState.errorCode = type->getElementOffset(fieldName, offset: &offset);
344 ret.errorState.errorCode = type->getElementSize(fieldName, size: &(ret.fieldSize));
345 ret.symbolAddr.address += offset;
346
347 return ret;
348}
349
350ompd_rc_t TValue::check(const char *bitfieldName, ompd_word_t *isSet) const {
351 if (gotError())
352 return getError();
353 int bitfield;
354 uint64_t bitfieldmask;
355 ompd_rc_t ret = this->castBase(baseType: ompd_type_int).getValue(buf: &bitfield, count: 1);
356 if (ret != ompd_rc_ok)
357 return ret;
358 ret = type->getBitfieldMask(fieldName: bitfieldName, bitfieldmask: &bitfieldmask);
359 *isSet = ((bitfield & bitfieldmask) != 0);
360 return ret;
361}
362
363TValue TValue::getArrayElement(int elemNumber) const {
364 if (gotError())
365 return *this;
366 TValue ret;
367 if (pointerLevel > 0) {
368 ret = dereference();
369 } else {
370 ret = *this;
371 }
372 if (ret.pointerLevel == 0) {
373 ompd_size_t size;
374 ret.errorState.errorCode = type->getSize(size: &size);
375 ret.symbolAddr.address += elemNumber * size;
376 } else {
377 ret.symbolAddr.address += elemNumber * type_sizes.sizeof_pointer;
378 }
379 return ret;
380}
381
382TValue TValue::getPtrArrayElement(int elemNumber) const {
383 if (gotError()) {
384 return *this;
385 }
386 assert(pointerLevel > 0 && "This only works on arrays of pointers");
387 TValue ret = *this;
388 ret.symbolAddr.address += elemNumber * type_sizes.sizeof_pointer;
389 return ret;
390}
391
392TBaseValue::TBaseValue(const TValue &_tvalue,
393 ompd_target_prim_types_t _baseType)
394 : TValue(_tvalue), baseTypeSize(ompd_sizeof(t: _baseType)) {}
395TBaseValue::TBaseValue(const TValue &_tvalue, ompd_size_t _baseTypeSize)
396 : TValue(_tvalue), baseTypeSize(_baseTypeSize) {}
397
398ompd_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;
408}
409

source code of openmp/libompd/src/TargetValue.cpp