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 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 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 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 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 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 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 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 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 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 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 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 232 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 257 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 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 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 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 324 TBaseValue TValue::castBase() const { 325 if (pointerLevel > 0) 326 return TBaseValue(*this, type_sizes.sizeof_pointer); 327 return TBaseValue(*this, fieldSize); 328 } 329 330 TBaseValue TValue::castBase(ompd_target_prim_types_t baseType) const { 331 return TBaseValue(*this, baseType); 332 } 333 334 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 350 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 363 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 382 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 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) {} 397 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