xref: /llvm-project/openmp/libompd/src/TargetValue.cpp (revision b9a27908f9b3d90ef306dfb9296316943c203726)
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 
20 const ompd_callbacks_t *TValue::callbacks = NULL;
21 ompd_device_type_sizes_t TValue::type_sizes;
22 
ompd_sizeof(ompd_target_prim_types_t t)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");
26 
27   return (((char *)&TValue::type_sizes)[(int)t]);
28 }
29 
getType(ompd_address_space_context_t * context,const char * typeName,ompd_addr_t segment)30 TType &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(context) == ttypes.end()) {
35     std::map<const char *, TType> empty;
36     ttypes[context] = empty;
37   }
38 
39   auto t = ttypes.find(context);
40   auto i = t->second.find(typeName);
41   if (i == t->second.end())
42     i = t->second.insert(
43         i, std::make_pair(typeName, TType(context, typeName, segment)));
44   else
45     i->second.context = context;
46 
47   return i->second;
48 }
49 
TType(ompd_address_space_context_t * _context,const char * _typeName,ompd_addr_t _segment)50 TType::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 
getSize(ompd_size_t * size)55 ompd_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 
getBitfieldMask(const char * fieldName,uint64_t * bitfieldmask)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;
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(i, std::make_pair(fieldName, bitfieldMask));
117   }
118   *bitfieldmask = i->second;
119   return ret;
120 }
121 
getElementOffset(const char * fieldName,ompd_size_t * offset)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;
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(i, std::make_pair(fieldName, fieldOffset));
153   }
154   *offset = i->second;
155   return ret;
156 }
157 
getElementSize(const char * fieldName,ompd_size_t * size)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;
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(i, std::make_pair(fieldName, fieldSize));
189   }
190   *size = i->second;
191   return ret;
192 }
193 
TValue(ompd_address_space_context_t * _context,ompd_thread_context_t * _tcontext,const char * _valueName,ompd_addr_t segment)194 TValue::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 
TValue(ompd_address_space_context_t * _context,ompd_thread_context_t * _tcontext,ompd_address_t addr)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;
210 }
211 
cast(const char * typeName)212 TValue &TValue::cast(const char *typeName) {
213   if (gotError())
214     return *this;
215   type = &tf.getType(context, typeName, symbolAddr.segment);
216   pointerLevel = 0;
217   assert(!type->isVoid() && "cast to invalid type failed");
218   return *this;
219 }
220 
cast(const char * typeName,int _pointerLevel,ompd_addr_t segment)221 TValue &TValue::cast(const char *typeName, int _pointerLevel,
222                      ompd_addr_t segment) {
223   if (gotError())
224     return *this;
225   type = &tf.getType(context, typeName, symbolAddr.segment);
226   pointerLevel = _pointerLevel;
227   symbolAddr.segment = segment;
228   assert(!type->isVoid() && "cast to invalid type failed");
229   return *this;
230 }
231 
dereference() const232 TValue 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 
getAddress(ompd_address_t * addr) const257 ompd_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 
getRawValue(void * buf,int count)264 ompd_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);
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 
getString(const char ** buf)277 ompd_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(string_buffer) == BUF_LEN) {
312     return ompd_rc_error;
313   }
314   return ret;
315 }
316 
castBase(const char * varName)317 TBaseValue TValue::castBase(const char *varName) {
318   ompd_size_t size;
319   errorState.errorCode =
320       tf.getType(context, varName, symbolAddr.segment).getSize(&size);
321   return TBaseValue(*this, size);
322 }
323 
castBase() const324 TBaseValue TValue::castBase() const {
325   if (pointerLevel > 0)
326     return TBaseValue(*this, type_sizes.sizeof_pointer);
327   return TBaseValue(*this, fieldSize);
328 }
329 
castBase(ompd_target_prim_types_t baseType) const330 TBaseValue TValue::castBase(ompd_target_prim_types_t baseType) const {
331   return TBaseValue(*this, baseType);
332 }
333 
access(const char * fieldName) const334 TValue 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);
344   ret.errorState.errorCode = type->getElementSize(fieldName, &(ret.fieldSize));
345   ret.symbolAddr.address += offset;
346 
347   return ret;
348 }
349 
check(const char * bitfieldName,ompd_word_t * isSet) const350 ompd_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(ompd_type_int).getValue(&bitfield, 1);
356   if (ret != ompd_rc_ok)
357     return ret;
358   ret = type->getBitfieldMask(bitfieldName, &bitfieldmask);
359   *isSet = ((bitfield & bitfieldmask) != 0);
360   return ret;
361 }
362 
getArrayElement(int elemNumber) const363 TValue 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);
375     ret.symbolAddr.address += elemNumber * size;
376   } else {
377     ret.symbolAddr.address += elemNumber * type_sizes.sizeof_pointer;
378   }
379   return ret;
380 }
381 
getPtrArrayElement(int elemNumber) const382 TValue 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 
TBaseValue(const TValue & _tvalue,ompd_target_prim_types_t _baseType)392 TBaseValue::TBaseValue(const TValue &_tvalue,
393                        ompd_target_prim_types_t _baseType)
394     : TValue(_tvalue), baseTypeSize(ompd_sizeof(_baseType)) {}
TBaseValue(const TValue & _tvalue,ompd_size_t _baseTypeSize)395 TBaseValue::TBaseValue(const TValue &_tvalue, ompd_size_t _baseTypeSize)
396     : TValue(_tvalue), baseTypeSize(_baseTypeSize) {}
397 
getValue(void * buf,int count)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;
408 }
409