409 lines · cpp
1/*2 * TargetValue.cpp -- Access to target values using OMPD callbacks3 */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-exception10//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(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 else45 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(" << typeName68 << ") \\" << 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(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 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(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 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(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 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, 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, 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);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 512292 char *string_buffer;293 294 // Allocate an extra byte, but pass only BUF_LEN to the tool295 // 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 realloc303 // 'string_buffer' and attempt reading again repeatedly till the entire string304 // 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 not309 // among the first 'nbytes' bytes, the string placed in the buffer is not310 // 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 317TBaseValue 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 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) // -> operator340 ret = ret.dereference();341 // we use *this for . operator342 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 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(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 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);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(_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