[OpenMP][OMPD] Implementation of OMPD debugging library - libompd.
authorVignesh Balasubramanian <Vignesh.Balasubrmanian@amd.com>
Wed, 1 Sep 2021 08:13:13 +0000 (13:43 +0530)
committerVignesh Balasubramanian <Vignesh.Balasubrmanian@amd.com>
Wed, 1 Sep 2021 09:20:16 +0000 (14:50 +0530)
This is a continuation of the review: https://reviews.llvm.org/D100181
Creates a new directory "libompd" under openmp.

"TargetValue" provides operational access to the OpenMP runtime memory
 for OMPD APIs.
With TargetValue, using "pointer" a user can do multiple operations
from casting, dereferencing to accessing an element for structure.
The member functions are designed to concatenate the operations that
are needed to access values from structures.

e.g., _a[6]->_b._c would read like :
TValue(ctx, "_a").cast("A",2)
.getArrayElement(6).access("_b").cast("B").access("_c")
For example:
If you have a pointer "ThreadHandle" of a running program then you can
access/retrieve "threadID" from the memory using TargetValue as below.

  TValue(context, thread_handle->th) /*__kmp_threads[t]->th*/
    .cast("kmp_base_info_t")
    .access("th_info") /*__kmp_threads[t]->th.th_info*/
    .cast("kmp_desc_t")
    .access("ds") /*__kmp_threads[t]->th.th_info.ds*/
    .cast("kmp_desc_base_t")
    .access("ds_thread") /*__kmp_threads[t]->th.th_info.ds.ds_thread*/
                .cast("kmp_thread_t")
.getRawValue(thread_id, 1);

Reviewed By: @hbae
Differential Revision: https://reviews.llvm.org/D100182

openmp/CMakeLists.txt
openmp/libompd/.clang-tidy [new file with mode: 0644]
openmp/libompd/CMakeLists.txt [new file with mode: 0644]
openmp/libompd/src/CMakeLists.txt [new file with mode: 0644]
openmp/libompd/src/Debug.h [new file with mode: 0644]
openmp/libompd/src/TargetValue.cpp [new file with mode: 0644]
openmp/libompd/src/TargetValue.h [new file with mode: 0644]
openmp/libompd/src/ompd-private.h [new file with mode: 0644]
openmp/libompd/src/ompd-types.h [new file with mode: 0644]

index 45c4003..b48c5d4 100644 (file)
@@ -71,6 +71,9 @@ option(OPENMP_ENABLE_LIBOMP_PROFILING "Enable time profiling for libomp." OFF)
 # to enable time profiling support in the OpenMP runtime.
 add_subdirectory(runtime)
 
+# Build libompd.so
+add_subdirectory(libompd)
+
 if (OPENMP_ENABLE_LIBOMPTARGET)
   # Check that the library can actually be built.
   if (APPLE OR WIN32)
diff --git a/openmp/libompd/.clang-tidy b/openmp/libompd/.clang-tidy
new file mode 100644 (file)
index 0000000..4bad5ef
--- /dev/null
@@ -0,0 +1,2 @@
+# Checks enabled in the top-level .clang-tidy minus readability-identifier-naming and llvm-header-guard.
+Checks: '-*,clang-diagnostic-*,llvm-*,-llvm-header-guard,misc-*,-misc-unused-parameters,-misc-non-private-member-variables-in-classes'
diff --git a/openmp/libompd/CMakeLists.txt b/openmp/libompd/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9e42092
--- /dev/null
@@ -0,0 +1,14 @@
+#
+#//===----------------------------------------------------------------------===//
+#//
+#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+#// See https://llvm.org/LICENSE.txt for license information.
+#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#//
+#//===----------------------------------------------------------------------===//
+#
+
+if(LIBOMP_OMPD_SUPPORT)
+    set(OMPD_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/)
+    add_subdirectory(src)
+endif()
diff --git a/openmp/libompd/src/CMakeLists.txt b/openmp/libompd/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..a835926
--- /dev/null
@@ -0,0 +1,50 @@
+#
+#//===----------------------------------------------------------------------===//
+#//
+#// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+#// See https://llvm.org/LICENSE.txt for license information.
+#// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#//
+#//===----------------------------------------------------------------------===//
+#
+
+project (libompd)
+cmake_minimum_required(VERSION 3.13.4)
+
+add_library (ompd SHARED TargetValue.cpp)
+
+add_dependencies(ompd omp) # ensure generated import library is created first
+
+set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+
+set(LIBOMPD_LD_STD_FLAGS FALSE CACHE BOOL
+  "Use -stdlibc++ instead of -libc++ library for C++ ")
+
+if(${LIBOMPD_LD_STD_FLAGS})
+#  Find and replace/add libstdc++ to compile flags     
+   STRING( FIND "${CMAKE_CXX_FLAGS}" "-stdlib=libc++" OUT )
+   if("${OUT}" STREQUAL "-1" )   
+      set (CMAKE_CXX_FLAGS "-stdlib=libstdc++ ${CMAKE_CXX_FLAGS}")
+   else()
+      STRING( REPLACE "-stdlib=libc++" "-stdlib=libstdc++" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} )
+   endif()         
+
+#  Find and replace/add libstdc++ to loader flags
+   STRING( FIND "${CMAKE_SHARED_LINKER_FLAGS}" "-stdlib=libc++" OUT )
+   if("${OUT}" STREQUAL "-1" )   
+      set (CMAKE_SHARED_LINKER_FLAGS "-stdlib=libstdc++ ${CMAKE_SHARED_LINKER_FLAGS}")         
+   else()
+      STRING( REPLACE "-stdlib=libc++" "-stdlib=libstdc++" CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} )
+   endif()
+endif()
+
+include_directories (
+        ${CMAKE_CURRENT_SOURCE_DIR}
+        ${LIBOMP_INCLUDE_DIR}
+        ${LIBOMP_SRC_DIR}
+)
+
+INSTALL( TARGETS ompd
+        LIBRARY DESTINATION lib 
+        ARCHIVE DESTINATION lib/static 
+        RUNTIME DESTINATION bin )
diff --git a/openmp/libompd/src/Debug.h b/openmp/libompd/src/Debug.h
new file mode 100644 (file)
index 0000000..18a3c7b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Debug.h -- OMP debug
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <iostream>
+#include <ostream>
+
+#ifndef GDB_DEBUG_H_
+#define GDB_DEBUG_H_
+
+namespace GdbColor {
+enum Code {
+  FG_RED = 31,
+  FG_GREEN = 32,
+  FG_BLUE = 34,
+  FG_DEFAULT = 39,
+  BG_RED = 41,
+  BG_GREEN = 42,
+  BG_BLUE = 44,
+  BG_DEFAULT = 49
+};
+inline std::ostream &operator<<(std::ostream &os, Code code) {
+  return os << "\033[" << static_cast<int>(code) << "m";
+}
+} // namespace GdbColor
+
+class ColorOut {
+private:
+  std::ostream &out;
+  GdbColor::Code color;
+
+public:
+  ColorOut(std::ostream &_out, GdbColor::Code _color)
+      : out(_out), color(_color) {}
+  template <typename T> const ColorOut &operator<<(const T &val) const {
+    out << color << val << GdbColor::FG_DEFAULT;
+    return *this;
+  }
+  const ColorOut &operator<<(std::ostream &(*pf)(std::ostream &)) const {
+    out << color << pf << GdbColor::FG_DEFAULT;
+    return *this;
+  }
+};
+
+static ColorOut dout(std::cout, GdbColor::FG_RED);
+static ColorOut sout(std::cout, GdbColor::FG_GREEN);
+static ColorOut hout(std::cout, GdbColor::FG_BLUE);
+
+#endif /*GDB_DEBUG_H_*/
diff --git a/openmp/libompd/src/TargetValue.cpp b/openmp/libompd/src/TargetValue.cpp
new file mode 100644 (file)
index 0000000..8818121
--- /dev/null
@@ -0,0 +1,408 @@
+/*
+ * TargetValue.cpp -- Access to target values using OMPD callbacks
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TargetValue.h"
+#include "Debug.h"
+#include <cstring>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+const ompd_callbacks_t *TValue::callbacks = NULL;
+ompd_device_type_sizes_t TValue::type_sizes;
+
+inline int ompd_sizeof(ompd_target_prim_types_t t) {
+  assert(t != ompd_type_max && "ompd_type_max should not be used anywhere");
+  assert(t != ompd_type_invalid && "request size of invalid type");
+
+  return (((char *)&TValue::type_sizes)[(int)t]);
+}
+
+TType &TTypeFactory::getType(ompd_address_space_context_t *context,
+                             const char *typeName, ompd_addr_t segment) {
+  TType empty(true);
+
+  if (ttypes.find(context) == ttypes.end()) {
+    std::map<const char *, TType> empty;
+    ttypes[context] = empty;
+  }
+
+  auto t = ttypes.find(context);
+  auto i = t->second.find(typeName);
+  if (i == t->second.end())
+    i = t->second.insert(
+        i, std::make_pair(typeName, TType(context, typeName, segment)));
+  else
+    i->second.context = context;
+
+  return i->second;
+}
+
+TType::TType(ompd_address_space_context_t *_context, const char *_typeName,
+             ompd_addr_t _segment)
+    : typeSize(0), fieldOffsets(), descSegment(_segment), typeName(_typeName),
+      context(_context), isvoid(false) {}
+
+ompd_rc_t TType::getSize(ompd_size_t *size) {
+  ompd_rc_t ret = ompd_rc_ok;
+  if (typeSize == 0) {
+    ompd_address_t symbolAddr;
+    ompd_size_t tmpSize;
+    std::stringstream ss;
+    ss << "ompd_sizeof__" << typeName;
+
+    ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
+                                                &symbolAddr, NULL);
+    if (ret != ompd_rc_ok) {
+      dout << "missing symbol " << ss.str()
+           << " add this to ompd-specific.h:\nOMPD_SIZEOF(" << typeName
+           << ") \\" << std::endl;
+      return ret;
+    }
+
+    symbolAddr.segment = descSegment;
+
+    ret = TValue::callbacks->read_memory(
+        context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
+        &(tmpSize));
+    if (ret != ompd_rc_ok)
+      return ret;
+    ret = TValue::callbacks->device_to_host(
+        context, &tmpSize, TValue::type_sizes.sizeof_long_long, 1, &(typeSize));
+  }
+  *size = typeSize;
+  return ret;
+}
+
+ompd_rc_t TType::getBitfieldMask(const char *fieldName,
+                                 uint64_t *bitfieldmask) {
+  ompd_rc_t ret = ompd_rc_ok;
+  auto i = bitfieldMasks.find(fieldName);
+  if (i == bitfieldMasks.end()) {
+    uint64_t tmpMask, bitfieldMask;
+    ompd_address_t symbolAddr;
+    std::stringstream ss;
+    ss << "ompd_bitfield__" << typeName << "__" << fieldName;
+    ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
+                                                &symbolAddr, NULL);
+    if (ret != ompd_rc_ok) {
+      dout << "missing symbol " << ss.str()
+           << " add this to ompd-specific.h:\nOMPD_BITFIELD(" << typeName << ","
+           << fieldName << ") \\" << std::endl;
+      return ret;
+    }
+    symbolAddr.segment = descSegment;
+
+    ret = TValue::callbacks->read_memory(
+        context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
+        &(tmpMask));
+    if (ret != ompd_rc_ok)
+      return ret;
+    ret = TValue::callbacks->device_to_host(context, &(tmpMask),
+                                            TValue::type_sizes.sizeof_long_long,
+                                            1, &(bitfieldMask));
+    if (ret != ompd_rc_ok) {
+      return ret;
+    }
+    i = bitfieldMasks.insert(i, std::make_pair(fieldName, bitfieldMask));
+  }
+  *bitfieldmask = i->second;
+  return ret;
+}
+
+ompd_rc_t TType::getElementOffset(const char *fieldName, ompd_size_t *offset) {
+  ompd_rc_t ret = ompd_rc_ok;
+  auto i = fieldOffsets.find(fieldName);
+  if (i == fieldOffsets.end()) {
+    ompd_size_t tmpOffset, fieldOffset;
+    ompd_address_t symbolAddr;
+    std::stringstream ss;
+    ss << "ompd_access__" << typeName << "__" << fieldName;
+
+    ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
+                                                &symbolAddr, NULL);
+    if (ret != ompd_rc_ok) {
+      dout << "missing symbol " << ss.str()
+           << " add this to ompd-specific.h:\nOMPD_ACCESS(" << typeName << ","
+           << fieldName << ") \\" << std::endl;
+      return ret;
+    }
+    symbolAddr.segment = descSegment;
+
+    ret = TValue::callbacks->read_memory(
+        context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
+        &(tmpOffset));
+    if (ret != ompd_rc_ok)
+      return ret;
+    ret = TValue::callbacks->device_to_host(context, &(tmpOffset),
+                                            TValue::type_sizes.sizeof_long_long,
+                                            1, &fieldOffset);
+    if (ret != ompd_rc_ok) {
+      return ret;
+    }
+    i = fieldOffsets.insert(i, std::make_pair(fieldName, fieldOffset));
+  }
+  *offset = i->second;
+  return ret;
+}
+
+ompd_rc_t TType::getElementSize(const char *fieldName, ompd_size_t *size) {
+  ompd_rc_t ret = ompd_rc_ok;
+  auto i = fieldSizes.find(fieldName);
+  if (i == fieldSizes.end()) {
+    ompd_size_t tmpOffset, fieldSize;
+    ompd_address_t symbolAddr;
+    std::stringstream ss;
+    ss << "ompd_sizeof__" << typeName << "__" << fieldName;
+
+    ret = TValue::callbacks->symbol_addr_lookup(context, NULL, ss.str().c_str(),
+                                                &symbolAddr, NULL);
+    if (ret != ompd_rc_ok) {
+      dout << "missing symbol " << ss.str()
+           << " add this to ompd-specific.h:\nOMPD_ACCESS(" << typeName << ","
+           << fieldName << ") \\" << std::endl;
+      return ret;
+    }
+    symbolAddr.segment = descSegment;
+
+    ret = TValue::callbacks->read_memory(
+        context, NULL, &symbolAddr, 1 * TValue::type_sizes.sizeof_long_long,
+        &(tmpOffset));
+    if (ret != ompd_rc_ok)
+      return ret;
+    ret = TValue::callbacks->device_to_host(context, &tmpOffset,
+                                            TValue::type_sizes.sizeof_long_long,
+                                            1, &fieldSize);
+    if (ret != ompd_rc_ok) {
+      return ret;
+    }
+    i = fieldSizes.insert(i, std::make_pair(fieldName, fieldSize));
+  }
+  *size = i->second;
+  return ret;
+}
+
+TValue::TValue(ompd_address_space_context_t *_context,
+               ompd_thread_context_t *_tcontext, const char *_valueName,
+               ompd_addr_t segment)
+    : errorState(ompd_rc_ok), type(&nullType), pointerLevel(0),
+      context(_context), tcontext(_tcontext), fieldSize(0) {
+  errorState.errorCode = callbacks->symbol_addr_lookup(
+      context, tcontext, _valueName, &symbolAddr, NULL);
+  symbolAddr.segment = segment;
+}
+
+TValue::TValue(ompd_address_space_context_t *_context,
+               ompd_thread_context_t *_tcontext, ompd_address_t addr)
+    : errorState(ompd_rc_ok), type(&nullType), pointerLevel(0),
+      context(_context), tcontext(_tcontext), symbolAddr(addr), fieldSize(0) {
+  if (addr.address == 0)
+    errorState.errorCode = ompd_rc_bad_input;
+}
+
+TValue &TValue::cast(const char *typeName) {
+  if (gotError())
+    return *this;
+  type = &tf.getType(context, typeName, symbolAddr.segment);
+  pointerLevel = 0;
+  assert(!type->isVoid() && "cast to invalid type failed");
+  return *this;
+}
+
+TValue &TValue::cast(const char *typeName, int _pointerLevel,
+                     ompd_addr_t segment) {
+  if (gotError())
+    return *this;
+  type = &tf.getType(context, typeName, symbolAddr.segment);
+  pointerLevel = _pointerLevel;
+  symbolAddr.segment = segment;
+  assert(!type->isVoid() && "cast to invalid type failed");
+  return *this;
+}
+
+TValue TValue::dereference() const {
+  if (gotError())
+    return *this;
+  ompd_address_t tmpAddr;
+  assert(!type->isVoid() && "cannot work with void");
+  assert(pointerLevel > 0 && "cannot dereference non-pointer");
+  TValue ret = *this;
+  ret.pointerLevel--;
+  ret.errorState.errorCode = callbacks->read_memory(
+      context, tcontext, &symbolAddr, 1 * TValue::type_sizes.sizeof_pointer,
+      &(tmpAddr.address));
+  if (ret.errorState.errorCode != ompd_rc_ok)
+    return ret;
+
+  ret.errorState.errorCode = callbacks->device_to_host(
+      context, &(tmpAddr.address), TValue::type_sizes.sizeof_pointer, 1,
+      &(ret.symbolAddr.address));
+  if (ret.errorState.errorCode != ompd_rc_ok) {
+    return ret;
+  }
+  if (ret.symbolAddr.address == 0)
+    ret.errorState.errorCode = ompd_rc_unsupported;
+  return ret;
+}
+
+ompd_rc_t TValue::getAddress(ompd_address_t *addr) const {
+  *addr = symbolAddr;
+  if (symbolAddr.address == 0)
+    return ompd_rc_unsupported;
+  return errorState.errorCode;
+}
+
+ompd_rc_t TValue::getRawValue(void *buf, int count) {
+  if (errorState.errorCode != ompd_rc_ok)
+    return errorState.errorCode;
+  ompd_size_t size;
+  errorState.errorCode = type->getSize(&size);
+  if (errorState.errorCode != ompd_rc_ok)
+    return errorState.errorCode;
+
+  errorState.errorCode =
+      callbacks->read_memory(context, tcontext, &symbolAddr, size, buf);
+  return errorState.errorCode;
+}
+
+ompd_rc_t TValue::getString(const char **buf) {
+  *buf = 0;
+  if (gotError())
+    return getError();
+
+  TValue strValue = dereference();
+  if (strValue.gotError()) {
+    return strValue.getError();
+  }
+
+  if (!callbacks) {
+    return ompd_rc_error;
+  }
+  ompd_rc_t ret;
+#define BUF_LEN 512
+  char *string_buffer;
+
+  // Allocate an extra byte, but pass only BUF_LEN to the tool
+  // so that we can detect truncation later.
+  ret = callbacks->alloc_memory(BUF_LEN + 1, (void **)&string_buffer);
+  if (ret != ompd_rc_ok) {
+    return ret;
+  }
+  string_buffer[BUF_LEN] = '\0';
+
+  // TODO: if we have not read in the complete string, we need to realloc
+  // 'string_buffer' and attempt reading again repeatedly till the entire string
+  // is read in.
+  ret = callbacks->read_string(context, tcontext, &strValue.symbolAddr, BUF_LEN,
+                               (void *)string_buffer);
+  *buf = string_buffer;
+  // Check for truncation. The standard specifies that if a null byte is not
+  // among the first 'nbytes' bytes, the string placed in the buffer is not
+  // null-terminated. 'nbytes' is BUF_LEN in this case.
+  if (ret == ompd_rc_ok && strlen(string_buffer) == BUF_LEN) {
+    return ompd_rc_error;
+  }
+  return ret;
+}
+
+TBaseValue TValue::castBase(const char *varName) {
+  ompd_size_t size;
+  errorState.errorCode =
+      tf.getType(context, varName, symbolAddr.segment).getSize(&size);
+  return TBaseValue(*this, size);
+}
+
+TBaseValue TValue::castBase() const {
+  if (pointerLevel > 0)
+    return TBaseValue(*this, type_sizes.sizeof_pointer);
+  return TBaseValue(*this, fieldSize);
+}
+
+TBaseValue TValue::castBase(ompd_target_prim_types_t baseType) const {
+  return TBaseValue(*this, baseType);
+}
+
+TValue TValue::access(const char *fieldName) const {
+  if (gotError())
+    return *this;
+  TValue ret = *this;
+  assert(pointerLevel < 2 && "access to field element of pointer array failed");
+  if (pointerLevel == 1) // -> operator
+    ret = ret.dereference();
+  // we use *this for . operator
+  ompd_size_t offset;
+  ret.errorState.errorCode = type->getElementOffset(fieldName, &offset);
+  ret.errorState.errorCode = type->getElementSize(fieldName, &(ret.fieldSize));
+  ret.symbolAddr.address += offset;
+
+  return ret;
+}
+
+ompd_rc_t TValue::check(const char *bitfieldName, ompd_word_t *isSet) const {
+  if (gotError())
+    return getError();
+  int bitfield;
+  uint64_t bitfieldmask;
+  ompd_rc_t ret = this->castBase(ompd_type_int).getValue(&bitfield, 1);
+  if (ret != ompd_rc_ok)
+    return ret;
+  ret = type->getBitfieldMask(bitfieldName, &bitfieldmask);
+  *isSet = ((bitfield & bitfieldmask) != 0);
+  return ret;
+}
+
+TValue TValue::getArrayElement(int elemNumber) const {
+  if (gotError())
+    return *this;
+  TValue ret;
+  if (pointerLevel > 0) {
+    ret = dereference();
+  } else {
+    ret = *this;
+  }
+  if (ret.pointerLevel == 0) {
+    ompd_size_t size;
+    ret.errorState.errorCode = type->getSize(&size);
+    ret.symbolAddr.address += elemNumber * size;
+  } else {
+    ret.symbolAddr.address += elemNumber * type_sizes.sizeof_pointer;
+  }
+  return ret;
+}
+
+TValue TValue::getPtrArrayElement(int elemNumber) const {
+  if (gotError()) {
+    return *this;
+  }
+  assert(pointerLevel > 0 && "This only works on arrays of pointers");
+  TValue ret = *this;
+  ret.symbolAddr.address += elemNumber * type_sizes.sizeof_pointer;
+  return ret;
+}
+
+TBaseValue::TBaseValue(const TValue &_tvalue,
+                       ompd_target_prim_types_t _baseType)
+    : TValue(_tvalue), baseTypeSize(ompd_sizeof(_baseType)) {}
+TBaseValue::TBaseValue(const TValue &_tvalue, ompd_size_t _baseTypeSize)
+    : TValue(_tvalue), baseTypeSize(_baseTypeSize) {}
+
+ompd_rc_t TBaseValue::getValue(void *buf, int count) {
+  if (errorState.errorCode != ompd_rc_ok)
+    return errorState.errorCode;
+  errorState.errorCode = callbacks->read_memory(context, tcontext, &symbolAddr,
+                                                count * baseTypeSize, buf);
+  if (errorState.errorCode != ompd_rc_ok)
+    return errorState.errorCode;
+  errorState.errorCode =
+      callbacks->device_to_host(context, buf, baseTypeSize, count, buf);
+  return errorState.errorCode;
+}
diff --git a/openmp/libompd/src/TargetValue.h b/openmp/libompd/src/TargetValue.h
new file mode 100644 (file)
index 0000000..87e4575
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * TargetValue.h -- Access to target values using OMPD callbacks
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "omp-tools.h"
+#include "ompd-private.h"
+#include <stdlib.h>
+
+#ifndef SRC_TARGET_VALUE_H_
+#define SRC_TARGET_VALUE_H_
+
+#ifdef __cplusplus
+
+#include <cassert>
+#include <map>
+#include <string>
+
+class TType;
+class TValue;
+class TBaseValue;
+
+class TTypeFactory {
+protected:
+  std::map<ompd_address_space_context_t *, std::map<const char *, TType>>
+      ttypes;
+
+public:
+  TTypeFactory() : ttypes() {}
+  TType &getType(ompd_address_space_context_t *context, const char *typName,
+                 ompd_addr_t segment = OMPD_SEGMENT_UNSPECIFIED);
+};
+
+static thread_local TTypeFactory tf = TTypeFactory();
+
+class TType {
+protected:
+  ompd_size_t typeSize;
+  std::map<const char *, ompd_size_t> fieldOffsets;
+  std::map<const char *, ompd_size_t> fieldSizes;
+  std::map<const char *, uint64_t> bitfieldMasks;
+  ompd_addr_t descSegment;
+  const char *typeName;
+  ompd_address_space_context_t *context;
+  bool isvoid;
+  TType(ompd_address_space_context_t *context, const char *typeName,
+        ompd_addr_t _segment = OMPD_SEGMENT_UNSPECIFIED);
+
+public:
+  TType(bool, ompd_addr_t _segment = OMPD_SEGMENT_UNSPECIFIED)
+      : descSegment(_segment), isvoid(true) {}
+  bool isVoid() const { return isvoid; }
+  ompd_rc_t getElementOffset(const char *fieldName, ompd_size_t *offset);
+  ompd_rc_t getElementSize(const char *fieldName, ompd_size_t *size);
+  ompd_rc_t getBitfieldMask(const char *fieldName, uint64_t *bitfieldmask);
+  ompd_rc_t getSize(ompd_size_t *size);
+  friend TValue;
+  friend TTypeFactory;
+};
+
+static TType nullType(true);
+
+/**
+ * class TError
+ * As TValue is designed to concatenate operations, we use TError
+ * to catch errors that might happen on each operation and provide
+ * the according error code and which operation raised the error.
+ */
+
+class TError {
+protected:
+  ompd_rc_t errorCode;
+  TError() : errorCode(ompd_rc_ok) {}
+  TError(const ompd_rc_t &error) : errorCode(error) {}
+
+public:
+  std::string toString() {
+    return std::string("TError messages not implemented yet");
+  }
+  friend TValue;
+  friend TBaseValue;
+};
+
+/**
+ * class TValue
+ * This class encapsules the access to target values by using OMPD
+ * callback functions. The member functions are designed to concatenate
+ * the operations that are needed to access values from structures
+ * e.g., _a[6]->_b._c would read like :
+ * TValue(ctx,
+ * "_a").cast("A",2).getArrayElement(6).access("_b").cast("B").access("_c")
+ */
+
+class TValue {
+protected:
+  TError errorState;
+  TType *type;
+  int pointerLevel;
+  ompd_address_space_context_t *context;
+  ompd_thread_context_t *tcontext;
+  ompd_address_t symbolAddr;
+  ompd_size_t fieldSize;
+
+public:
+  static const ompd_callbacks_t *callbacks;
+  static ompd_device_type_sizes_t type_sizes;
+
+  TValue() : errorState(ompd_rc_error) {}
+  /**
+   * Create a target value object from symbol name
+   */
+  TValue(ompd_address_space_context_t *_context, const char *_valueName,
+         ompd_addr_t segment = OMPD_SEGMENT_UNSPECIFIED)
+      : TValue(_context, NULL, _valueName, segment) {}
+
+  TValue(ompd_address_space_context_t *context, ompd_thread_context_t *tcontext,
+         const char *valueName, ompd_addr_t segment = OMPD_SEGMENT_UNSPECIFIED);
+  /**
+   * Create a target value object from target value address
+   */
+  TValue(ompd_address_space_context_t *_context, ompd_address_t _addr)
+      : TValue(_context, NULL, _addr) {}
+  TValue(ompd_address_space_context_t *context, ompd_thread_context_t *tcontext,
+         ompd_address_t addr);
+  /**
+   * Cast the target value object to some type of typeName
+   *
+   * This call modifies the object and returns a reference to the modified
+   * object
+   */
+  TValue &cast(const char *typeName);
+
+  /**
+   * Cast the target value object to some pointer of type typename
+   * pointerlevel gives the number of *
+   * e.g., char** would be: cast("char",2)
+   *
+   * This call modifies the object and returns a reference to the modified
+   * object
+   */
+  TValue &cast(const char *typeName, int pointerLevel,
+               ompd_addr_t segment = OMPD_SEGMENT_UNSPECIFIED);
+
+  /**
+   * Get the target address of the target value
+   */
+  ompd_rc_t getAddress(ompd_address_t *addr) const;
+  /**
+   * Get the raw memory copy of the target value
+   */
+  ompd_rc_t getRawValue(void *buf, int count);
+  /**
+   * Fetch a string copy from the target. "this" represents the pointer
+   * that holds the value of a null terminated character string. "buf"
+   * points to the destination string to be allocated and copied to.
+   * Returns 'ompd_rc_error' to signify a truncated string or a target
+   * read error.
+   */
+  ompd_rc_t getString(const char **buf);
+  /**
+   * Get a new target value object for the dereferenced target value
+   * reduces the pointer level, uses the target value as new target address,
+   * keeps the target type
+   */
+  TValue dereference() const;
+  /**
+   * Cast to a base type
+   * Only values of base type may be read from target
+   */
+  TBaseValue castBase(ompd_target_prim_types_t baseType) const;
+  /**
+   * Cast to a base type
+   * Get the size by fieldsize from runtime
+   */
+  TBaseValue castBase() const;
+  /**
+   * Cast to a base type
+   * Get the size by name from the rtl
+   */
+  TBaseValue castBase(const char *varName);
+  /**
+   * Resolve field access for structs/unions
+   * this supports both "->" and "." operator.
+   */
+  TValue access(const char *fieldName) const;
+  /**
+   * Tests for a field bit in a bitfield
+   */
+  ompd_rc_t check(const char *bitfieldName, ompd_word_t *isSet) const;
+  /**
+   * Get an array element
+   */
+  TValue getArrayElement(int elemNumber) const;
+  /**
+   * Get an element of a pointer array
+   */
+  TValue getPtrArrayElement(int elemNumber) const;
+  /**
+   * Did we raise some error yet?
+   */
+  bool gotError() const { return errorState.errorCode != ompd_rc_ok; }
+  /**
+   * Get the error code
+   */
+  ompd_rc_t getError() const { return errorState.errorCode; }
+  /**
+   * Did we raise some error yet?
+   */
+  std::string getErrorMessage() { return errorState.toString(); }
+};
+
+class TBaseValue : public TValue {
+protected:
+  ompd_size_t baseTypeSize = 0;
+  TBaseValue(const TValue &, ompd_target_prim_types_t baseType);
+  TBaseValue(const TValue &, ompd_size_t baseTypeSize);
+
+public:
+  ompd_rc_t getValue(void *buf, int count);
+  template <typename T> ompd_rc_t getValue(T &buf);
+
+  friend TValue;
+};
+
+template <typename T> ompd_rc_t TBaseValue::getValue(T &buf) {
+  assert(sizeof(T) >= baseTypeSize);
+  ompd_rc_t ret = getValue(&buf, 1);
+  if (sizeof(T) > baseTypeSize) {
+    switch (baseTypeSize) {
+    case 1:
+      buf = (T) * ((int8_t *)&buf);
+      break;
+    case 2:
+      buf = (T) * ((int16_t *)&buf);
+      break;
+    case 4:
+      buf = (T) * ((int32_t *)&buf);
+      break;
+    case 8:
+      buf = (T) * ((int64_t *)&buf);
+      break;
+    }
+  }
+  return ret;
+}
+
+#define EXTERN_C extern "C"
+#else
+#define EXTERN_C
+#endif
+
+#endif /*SRC_TARGET_VALUE_H_*/
diff --git a/openmp/libompd/src/ompd-private.h b/openmp/libompd/src/ompd-private.h
new file mode 100644 (file)
index 0000000..191183b
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * ompd-private.h
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SRC_OMPD_PRIVATE_H_
+#define SRC_OMPD_PRIVATE_H_
+
+/*
+ * Definition of OMPD states, taken from OMPT
+ */
+#define FOREACH_OMPD_STATE(macro)                                              \
+                                                                               \
+  /* first available state */                                                  \
+  macro(ompt_state_undefined, 0x102) /* undefined thread state */              \
+                                                                               \
+      /* work states (0..15) */                                                \
+      macro(ompt_state_work_serial, 0x000)    /* working outside parallel */   \
+      macro(ompt_state_work_parallel, 0x001)  /* working within parallel */    \
+      macro(ompt_state_work_reduction, 0x002) /* performing a reduction */     \
+                                                                               \
+      /* barrier wait states (16..31) */                                       \
+      macro(ompt_state_wait_barrier, 0x010) /* waiting at a barrier */         \
+      macro(ompt_state_wait_barrier_implicit_parallel,                         \
+            0x011) /* implicit barrier at the end of parallel region */        \
+      macro(ompt_state_wait_barrier_implicit_workshare,                        \
+            0x012) /* implicit barrier at the end of worksharing */            \
+      macro(ompt_state_wait_barrier_implicit, 0x013) /* implicit barrier */    \
+      macro(ompt_state_wait_barrier_explicit, 0x014) /* explicit barrier */    \
+                                                                               \
+      /* task wait states (32..63) */                                          \
+      macro(ompt_state_wait_taskwait, 0x020)  /* waiting at a taskwait */      \
+      macro(ompt_state_wait_taskgroup, 0x021) /* waiting at a taskgroup */     \
+                                                                               \
+      /* mutex wait states (64..127) */                                        \
+      macro(ompt_state_wait_mutex, 0x040)                                      \
+          macro(ompt_state_wait_lock, 0x041) /* waiting for lock */            \
+      macro(ompt_state_wait_critical, 0x042) /* waiting for critical */        \
+      macro(ompt_state_wait_atomic, 0x043)   /* waiting for atomic */          \
+      macro(ompt_state_wait_ordered, 0x044)  /* waiting for ordered */         \
+                                                                               \
+      /* target wait states (128..255) */                                      \
+      macro(ompt_state_wait_target, 0x080) /* waiting for target region */     \
+      macro(ompt_state_wait_target_map,                                        \
+            0x081) /* waiting for target data mapping operation */             \
+      macro(ompt_state_wait_target_update,                                     \
+            0x082) /* waiting for target update operation */                   \
+                                                                               \
+      /* misc (256..511) */                                                    \
+      macro(ompt_state_idle, 0x100)     /* waiting for work */                 \
+      macro(ompt_state_overhead, 0x101) /* overhead excluding wait states */   \
+                                                                               \
+      /* implementation-specific states (512..) */
+
+#define OMPD_LAST_OMP_STATE ompt_state_overhead
+
+/**
+ * Primitive types.
+ */
+typedef enum ompd_target_prim_types_t {
+  ompd_type_invalid = -1,
+  ompd_type_char = 0,
+  ompd_type_short = 1,
+  ompd_type_int = 2,
+  ompd_type_long = 3,
+  ompd_type_long_long = 4,
+  ompd_type_pointer = 5,
+  ompd_type_max
+} ompd_target_prim_types_t;
+
+#include "ompd-types.h"
+#endif /*SRC_OMPD_PRIVATE_H*/
diff --git a/openmp/libompd/src/ompd-types.h b/openmp/libompd/src/ompd-types.h
new file mode 100644 (file)
index 0000000..86b1cb1
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * @@name:   ompd-types.h
+ */
+
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __OMPD_TYPES_H
+#define __OMPD_TYPES_H
+
+extern "C" {
+#include "omp-tools.h"
+}
+
+#define OMPD_TYPES_VERSION 20180906 /* YYYYMMDD Format */
+
+/* Kinds of device threads  */
+#define OMPD_THREAD_ID_PTHREAD ((ompd_thread_id_t)0)
+#define OMPD_THREAD_ID_LWP ((ompd_thread_id_t)1)
+#define OMPD_THREAD_ID_WINTHREAD ((ompd_thread_id_t)2)
+/* The range of non-standard implementation defined values */
+#define OMPD_THREAD_ID_LO ((ompd_thread_id_t)1000000)
+#define OMPD_THREAD_ID_HI ((ompd_thread_id_t)1100000)
+
+/* Memory Access Segment definitions for Host and Target Devices */
+#define OMPD_SEGMENT_UNSPECIFIED ((ompd_seg_t)0)
+
+/* Kinds of device device address spaces */
+#define OMPD_DEVICE_KIND_HOST ((ompd_device_t)1)
+/* The range of non-standard implementation defined values */
+#define OMPD_DEVICE_IMPL_LO ((ompd_device_t)1000000)
+#define OMPD_DEVICE_IMPL_HI ((ompd_device_t)1100000)
+#endif