//===--- ImageInspectionWin32.cpp - Win32 image inspection ----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#if !defined(__ELF__) && !defined(__MACH__)

#include "ImageInspection.h"

#if defined(__CYGWIN__)
#include <dlfcn.h>
#elif defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <DbgHelp.h>
#endif

using namespace swift;

int swift::lookupSymbol(const void *address, SymbolInfo *info) {
#if defined(__CYGWIN__)
  Dl_info dlinfo;
  if (dladdr(address, &dlinfo) == 0) {
    return 0;
  }

  info->fileName = dlinfo.dli_fname;
  info->baseAddress = dlinfo.dli_fbase;
  info->symbolName = dli_info.dli_sname;
  info->symbolAddress = dli_saddr;
  return 1;
#elif defined(_WIN32)
  static const constexpr size_t kSymbolMaxNameLen = 1024;
  static bool bInitialized = false;

  if (bInitialized == false) {
    if (SymInitialize(GetCurrentProcess(), /*UserSearchPath=*/NULL,
                      /*fInvadeProcess=*/TRUE) == FALSE)
      return 0;
    bInitialized = true;
  }

  char buffer[sizeof(SYMBOL_INFO) + kSymbolMaxNameLen];
  PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(buffer);
  pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
  pSymbol->MaxNameLen = kSymbolMaxNameLen;

  DWORD64 dwDisplacement = 0;

  if (SymFromAddr(GetCurrentProcess(), reinterpret_cast<const DWORD64>(address),
                  &dwDisplacement, pSymbol) == FALSE)
    return 0;

  info->fileName = NULL;
  info->baseAddress = reinterpret_cast<void *>(pSymbol->ModBase);
  info->symbolName.reset(_strdup(pSymbol->Name));
  info->symbolAddress = reinterpret_cast<void *>(pSymbol->Address);

  return 1;
#else
  return 0;
#endif // defined(__CYGWIN__) || defined(_WIN32)
}

#endif // !defined(__ELF__) && !defined(__MACH__)
