summaryrefslogtreecommitdiffstats
path: root/src/lib/kStuff/kDbg
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/kStuff/kDbg')
-rw-r--r--src/lib/kStuff/kDbg/Makefile.kmk73
-rw-r--r--src/lib/kStuff/kDbg/kDbgDump.cpp174
-rw-r--r--src/lib/kStuff/kDbg/kDbgHlp.h306
-rw-r--r--src/lib/kStuff/kDbg/kDbgHlpCrt.cpp239
-rw-r--r--src/lib/kStuff/kDbg/kDbgInternal.h137
-rw-r--r--src/lib/kStuff/kDbg/kDbgLine.cpp78
-rw-r--r--src/lib/kStuff/kDbg/kDbgModLdr.cpp109
-rw-r--r--src/lib/kStuff/kDbg/kDbgModPE.cpp384
-rw-r--r--src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp724
-rw-r--r--src/lib/kStuff/kDbg/kDbgModule.cpp440
-rw-r--r--src/lib/kStuff/kDbg/kDbgSpace.cpp192
-rw-r--r--src/lib/kStuff/kDbg/kDbgSymbol.cpp78
12 files changed, 2934 insertions, 0 deletions
diff --git a/src/lib/kStuff/kDbg/Makefile.kmk b/src/lib/kStuff/kDbg/Makefile.kmk
new file mode 100644
index 0000000..af8bed3
--- /dev/null
+++ b/src/lib/kStuff/kDbg/Makefile.kmk
@@ -0,0 +1,73 @@
+# $Id: Makefile.kmk 29 2009-07-01 20:30:29Z bird $
+## @file
+# kDbg - The Debug Info Reader, sub-makefile.
+#
+
+#
+# Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation
+# files (the "Software"), to deal in the Software without
+# restriction, including without limitation the rights to use,
+# copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following
+# conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+
+DEPTH ?= ..
+SUB_DEPTH = ..
+include $(PATH_KBUILD)/subheader.kmk
+
+#
+# kDbg - The profiler module.
+#
+#DLLS += kDbg - disabled for now.
+kDbg_TEMPLATE = kStuffDLL
+kDbg_DEFS = KDBG_BUILDING KDBG_RESIDES_IN_DLL
+kDbg_SOURCES := \
+ kDbgModule.cpp \
+ kDbgModLdr.cpp \
+ kDbgLine.cpp \
+ kDbgSymbol.cpp
+
+kDbg_SOURCES.win += \
+ kDbgModWinDbgHelp.cpp
+
+#
+# kDbgStatic - The profiler module.
+#
+LIBRARIES += kDbgStatic
+kDbgStatic_TEMPLATE = kStuffLIB
+kDbgStatic_DEFS = KDBG_BUILDING
+kDbgStatic_SOURCES = $(kDbg_SOURCES)
+kDbgStatic_SOURCES.win = $(kDbg_SOURCES.win)
+
+#
+# kDbgDump - Test program which dumps whatever is thrown at it.
+#
+PROGRAMS += kDbgDump
+kDbgDump_TEMPLATE = kStuffEXE
+kDbgDump_SOURCES = kDbgDump.cpp
+kDbgDump_LIBS = \
+ $(TARGET_kDbgStatic) \
+ $(subst kDbg,kLdr,$(TARGET_kDbgStatic)) \
+ $(subst kDbg,kRdr,$(TARGET_kDbgStatic)) \
+ $(subst kDbg,kHlpCRT,$(TARGET_kDbgStatic))
+
+# Generate the rules
+include $(PATH_KBUILD)/subfooter.kmk
+
diff --git a/src/lib/kStuff/kDbg/kDbgDump.cpp b/src/lib/kStuff/kDbg/kDbgDump.cpp
new file mode 100644
index 0000000..83cb36b
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgDump.cpp
@@ -0,0 +1,174 @@
+/* $Id: kDbgDump.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbgDump - Debug Info Dumper.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <k/kDbg.h>
+#include <string.h>
+#include <stdio.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** @name Options
+ * @{ */
+static int g_fGlobalSyms = 1;
+static int g_fPrivateSyms = 1;
+static int g_fLineNumbers = 0;
+/** @} */
+
+
+/**
+ * Dumps one file.
+ *
+ * @returns main exit status.
+ * @param pszFile The file to dump (path to it).
+ */
+static int DumpFile(const char *pszFile)
+{
+ PKDBGMOD pDbgMod;
+ int rc = kDbgModuleOpen(&pDbgMod, pszFile, NULL);
+ if (rc)
+ {
+ printf("kDbgDump: error: kDbgModuleOpen('%s',) failed with rc=%d.\n", pszFile, rc);
+ return 1;
+ }
+
+
+
+ return 0;
+}
+
+
+/**
+ * Prints the version number
+ * @return 0
+ */
+static int ShowVersion()
+{
+ printf("kDbgDump v0.0.1\n");
+ return 0;
+}
+
+
+/**
+ * Prints the program syntax.
+ *
+ * @returns 1
+ * @param argv0 The program name.
+ */
+static int ShowSyntax(const char *argv0)
+{
+ ShowVersion();
+ printf("syntax: %s [options] <files>\n"
+ "\n",
+ argv0);
+ return 1;
+}
+
+int main(int argc, char **argv)
+{
+ int rcRet = 0;
+
+ /*
+ * Parse arguments.
+ */
+ int fArgsDone = 0;
+ for (int i = 1; i < argc; i++)
+ {
+ const char *psz = argv[i];
+
+ if (!fArgsDone && psz[0] == '-' && psz[1])
+ {
+ /* convert long option to short. */
+ if (*++psz == '-')
+ {
+ psz++;
+ if (!*psz) /* -- */
+ {
+ fArgsDone = 1;
+ continue;
+ }
+ if (!strcmp(psz, "line-numbers"))
+ psz = "l";
+ else if (!strcmp(psz, "no-line-numbers"))
+ psz = "L";
+ else if (!strcmp(psz, "global-syms") || !strcmp(psz, "public-syms"))
+ psz = "g";
+ else if (!strcmp(psz, "no-global-syms") || !strcmp(psz, "no-public-syms"))
+ psz = "G";
+ else if (!strcmp(psz, "privat-syms") || !strcmp(psz, "local-syms"))
+ psz = "p";
+ else if (!strcmp(psz, "no-privat-syms") || !strcmp(psz, "no-local-syms"))
+ psz = "P";
+ else if (!strcmp(psz, "version"))
+ psz = "v";
+ else if (!strcmp(psz, "help"))
+ psz = "h";
+ else
+ {
+ fprintf(stderr, "%s: syntax error: unknown option '--%s'\n", argv[0], psz);
+ return 1;
+ }
+ }
+
+ /* eat short options. */
+ while (*psz)
+ switch (*psz++)
+ {
+ case 'l': g_fLineNumbers = 1; break;
+ case 'L': g_fLineNumbers = 0; break;
+ case 'p': g_fPrivateSyms = 1; break;
+ case 'P': g_fPrivateSyms = 0; break;
+ case 'g': g_fGlobalSyms = 1; break;
+ case 'G': g_fGlobalSyms = 0; break;
+ case '?':
+ case 'H':
+ case 'h': return ShowSyntax(argv[0]);
+ case 'v': return ShowVersion();
+ default:
+ fprintf(stderr, "%s: syntax error: unknown option '-%c'.\n", argv[0], psz[-1]);
+ return 1;
+ }
+ }
+ else
+ {
+ /* Dump does it's own bitching if something goes wrong. */
+ int rc = DumpFile(psz);
+ if (rc && !rcRet)
+ rc = rcRet;
+ }
+ }
+
+ return rcRet;
+}
+
diff --git a/src/lib/kStuff/kDbg/kDbgHlp.h b/src/lib/kStuff/kDbg/kDbgHlp.h
new file mode 100644
index 0000000..cd5116d
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgHlp.h
@@ -0,0 +1,306 @@
+/* $Id: kDbgHlp.h 78 2016-07-13 15:52:04Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, Internal Header.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ___kDbgHlp_h___
+#define ___kDbgHlp_h___
+
+#include <k/kDbgBase.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** @defgroup grp_kDbgHlpHeap kDbg Internal Heap APIs.
+ * @internal
+ * @{
+ */
+
+/**
+ * Allocates memory.
+ *
+ * @returns Pointer to the allocated memory.
+ * NULL on failure.
+ * @param cb The number of bytes to allocate.
+ */
+void *kDbgHlpAlloc(size_t cb);
+
+/**
+ * Allocates memory like kDbgHlpAlloc, except that it's zeroed.
+ *
+ * @returns Pointer to the allocated memory.
+ * NULL on failure.
+ * @param cb The number of bytes to allocate.
+ */
+void *kDbgHlpAllocZ(size_t cb);
+
+/**
+ * Combination of kDbgHlpAlloc and memcpy.
+ *
+ * @returns Pointer to the duplicate.
+ * NULL on failure.
+ *
+ * @param pv The memory to be duplicate.
+ * @param cb The size of the block.
+ */
+void *kDbgHlpAllocDup(const void *pv, size_t cb);
+
+/**
+ * Reallocates a memory block returned by kDbgHlpAlloc, kDbgHlpAllocZ
+ * kDbgHlpAllocDup or this function.
+ *
+ * The content of new memory added to the memory block is undefined.
+ *
+ * @returns Pointer to the allocated memory.
+ * NULL on failure, the old block remains intact.
+ * @param pv The memory block to reallocate.
+ * If NULL this function will work like kDbgHlpAlloc.
+ * @param cb The number of bytes to allocate.
+ * If 0 this function will work like kDbgHlpFree.
+ */
+void *kDbgHlpRealloc(void *pv, size_t cb);
+
+/**
+ * Frees memory allocated by kDbgHlpAlloc, kDbgHlpAllocZ
+ * kDbgHlpAllocDup, or kDbgHlpRealloc.
+ *
+ * @param pv
+ */
+void kDbgHlpFree(void *pv);
+
+/** @} */
+
+
+/** @defgroup grp_kDbgHlpFile kDbg Internal File Access APIs.
+ * @internal
+ * @{
+ */
+/**
+ * Opens the specified file as read-only, buffered if possible.
+ *
+ * @returns 0 on success, or the appropriate KDBG_ERR_* on failure.
+ *
+ * @param pszFilename The file to open.
+ * @param ppFile Where to store the handle to the open file.
+ */
+int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile);
+
+
+/**
+ * Closes a file opened by kDbgHlpOpenRO.
+ *
+ * @param pFile The file handle.
+ */
+void kDbgHlpClose(PKDBGHLPFILE pFile);
+
+/**
+ * Gets the native file handle.
+ *
+ * @return The native file handle.
+ * -1 on failure.
+ * @param pFile The file handle.
+ */
+uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile);
+
+/**
+ * Gets the size of an open file.
+ *
+ * @returns The file size in bytes on success.
+ * On failure -1 is returned.
+ * @param pFile The file handle.
+ */
+int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile);
+
+/**
+ * Reads a number of bytes at a specified file location.
+ *
+ * This will change the current file position to off + cb on success,
+ * while on failure the position will be undefined.
+ *
+ * @returns The file size in bytes on success.
+ * On failure -1 is returned.
+ * @param pFile The file handle.
+ * @param off Where to read.
+ * @param pv Where to store the data.
+ * @param cb How much to read.
+ */
+int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb);
+
+/**
+ * Reads a number of bytes at the current file position.
+ *
+ * This will advance the current file position by cb bytes on success
+ * while on failure the position will be undefined.
+ *
+ * @returns The file size in bytes on success.
+ * On failure -1 is returned.
+ * @param pFile The file handle.
+ * @param pv Where to store the data.
+ * @param cb How much to read.
+ * @param off Where to read.
+ */
+int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb);
+
+/**
+ * Sets the current file position.
+ *
+ * @returns 0 on success, and KDBG_ERR_* on failure.
+ * @param pFile The file handle.
+ * @param off The desired file position.
+ */
+int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off);
+
+/**
+ * Move the file position relative to the current one.
+ *
+ * @returns 0 on success, and KDBG_ERR_* on failure.
+ * @param pFile The file handle.
+ * @param off How much to move the file position by.
+ */
+int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off);
+
+/**
+ * Move the file position relative to the end of the file.
+ *
+ * @returns 0 on success, and KDBG_ERR_* on failure.
+ * @param pFile The file handle.
+ * @param off The offset relative to the end, positive number.
+ */
+int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off);
+
+/**
+ * Gets the current file position.
+ *
+ * @returns The current file position on success.
+ * -1 on failure.
+ * @param pFile The file handle.
+ */
+int64_t kDbgHlpTell(PKDBGHLPFILE pFile);
+
+/** @} */
+
+/** @defgroup grp_kDbgHlpAssert kDbg Internal Assertion Macros.
+ * @internal
+ * @{
+ */
+
+#ifdef _MSC_VER
+# define kDbgAssertBreakpoint() do { __debugbreak(); } while (0)
+#else
+# define kDbgAssertBreakpoint() do { __asm__ __volatile__ ("int3"); } while (0)
+#endif
+
+/**
+ * Helper function that displays the first part of the assertion message.
+ *
+ * @param pszExpr The expression.
+ * @param pszFile The file name.
+ * @param iLine The line number is the file.
+ * @param pszFunction The function name.
+ */
+void kDbgAssertMsg1(const char *pszExpr, const char *pszFile, unsigned iLine, const char *pszFunction);
+
+/**
+ * Helper function that displays custom assert message.
+ *
+ * @param pszFormat Format string that get passed to vprintf.
+ * @param ... Format arguments.
+ */
+void kDbgAssertMsg2(const char *pszFormat, ...);
+
+
+#ifdef KDBG_STRICT
+
+# define kDbgAssert(expr) \
+ do { \
+ if (!(expr)) \
+ { \
+ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \
+ kDbgAssertBreakpoint(); \
+ } \
+ } while (0)
+
+# define kDbgAssertReturn(expr, rcRet) \
+ do { \
+ if (!(expr)) \
+ { \
+ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \
+ kDbgAssertBreakpoint(); \
+ return (rcRet); \
+ } \
+ } while (0)
+
+# define kDbgAssertMsg(expr, msg) \
+ do { \
+ if (!(expr)) \
+ { \
+ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \
+ kDbgAssertMsg2 msg; \
+ kDbgAssertBreakpoint(); \
+ } \
+ } while (0)
+
+# define kDbgAssertMsgReturn(expr, msg, rcRet) \
+ do { \
+ if (!(expr)) \
+ { \
+ kDbgAssertMsg1(#expr, __FILE__, __LINE__, K_FUNCTION); \
+ kDbgAssertMsg2 msg; \
+ kDbgAssertBreakpoint(); \
+ return (rcRet); \
+ } \
+ } while (0)
+
+#else /* !KDBG_STRICT */
+# define kDbgAssert(expr) do { } while (0)
+# define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0)
+# define kDbgAssertMsg(expr, msg) do { } while (0)
+# define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0)
+#endif /* !KDBG_STRICT */
+
+#define kDbgAssertPtr(ptr) kDbgAssertMsg(KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || KDBG_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
+#define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
+#define kDbgAssertFailed() kDbgAssert(0)
+#define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet))
+#define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg)
+#define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet))
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp b/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp
new file mode 100644
index 0000000..a218404
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgHlpCrt.cpp
@@ -0,0 +1,239 @@
+/* $Id: kDbgHlpCrt.cpp 77 2016-06-22 17:03:55Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, Helpers, CRT Based Implementation.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "kDbgHlp.h"
+#include "kDbg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#ifdef _MSC_VER
+# include <io.h>
+#endif
+
+
+
+/**
+ * The stdio base implementation of KDBGHLPFILE.
+ */
+typedef struct KDBGHLPFILE
+{
+ /** Pointer to the stdio file stream. */
+ FILE *pStrm;
+} KDBGHLPFILE;
+
+/** @def HAVE_FSEEKO
+ * Define HAVE_FSEEKO to indicate that fseeko and ftello should be used. */
+#if !defined(_MSC_VER)
+# define HAVE_FSEEKO
+#endif
+
+
+void *kDbgHlpAlloc(size_t cb)
+{
+ return malloc(cb);
+}
+
+
+void *kDbgHlpAllocZ(size_t cb)
+{
+ return calloc(1, cb);
+}
+
+
+void *kDbgHlpAllocDup(const void *pv, size_t cb)
+{
+ void *pvNew = malloc(cb);
+ if (pvNew)
+ memcpy(pvNew, pv, cb);
+ return pvNew;
+}
+
+
+void *kDbgHlpReAlloc(void *pv, size_t cb)
+{
+ return realloc(pv, cb);
+}
+
+
+void kDbgHlpFree(void *pv)
+{
+ free(pv);
+}
+
+
+int kDbgHlpCrtConvErrno(int rc)
+{
+ switch (rc)
+ {
+ case 0: return 0;
+ case EINVAL: return KERR_INVALID_PARAMETER;
+ case ENOMEM: return KERR_NO_MEMORY;
+ case EISDIR:
+ case ENOENT: return KERR_FILE_NOT_FOUND;
+ default: return KERR_GENERAL_FAILURE;
+ }
+}
+
+
+int kDbgHlpOpenRO(const char *pszFilename, PKDBGHLPFILE *ppFile)
+{
+ PKDBGHLPFILE pFile = (PKDBGHLPFILE)kDbgHlpAlloc(sizeof(*pFile));
+ if (!pFile)
+ return KERR_NO_MEMORY;
+
+ pFile->pStrm = fopen(pszFilename, "rb");
+ if (pFile->pStrm)
+ {
+ *ppFile = pFile;
+ return 0;
+ }
+ return kDbgHlpCrtConvErrno(errno);
+}
+
+
+void kDbgHlpClose(PKDBGHLPFILE pFile)
+{
+ if (pFile)
+ {
+ fclose(pFile->pStrm);
+ pFile->pStrm = NULL;
+ kDbgHlpFree(pFile);
+ }
+}
+
+
+uintptr_t kDbgHlpNativeFileHandle(PKDBGHLPFILE pFile)
+{
+ int fd = fileno(pFile->pStrm);
+#ifdef _MSC_VER
+ return _get_osfhandle(fd);
+#else
+ return fd;
+#endif
+}
+
+
+int64_t kDbgHlpFileSize(PKDBGHLPFILE pFile)
+{
+ int64_t cbFile;
+ int64_t offCur = kDbgHlpTell(pFile);
+ if (offCur >= 0)
+ {
+ if (kDbgHlpSeekByEnd(pFile, 0) == 0)
+ cbFile = kDbgHlpTell(pFile);
+ else
+ cbFile = -1;
+ kDbgHlpSeek(pFile, offCur);
+ }
+ else
+ cbFile = -1;
+ return cbFile;
+}
+
+
+int kDbgHlpReadAt(PKDBGHLPFILE pFile, int64_t off, void *pv, size_t cb)
+{
+ int rc = kDbgHlpSeek(pFile, off);
+ if (!rc)
+ rc = kDbgHlpRead(pFile, pv, cb);
+ return rc;
+}
+
+
+int kDbgHlpRead(PKDBGHLPFILE pFile, void *pv, size_t cb)
+{
+ if (fread(pv, cb, 1, pFile->pStrm) == 1)
+ return 0;
+ return -1;
+}
+
+
+int kDbgHlpSeek(PKDBGHLPFILE pFile, int64_t off)
+{
+#ifdef HAVE_FSEEKO
+ if (!fseeko(pFile->pStrm, off, SEEK_SET))
+ return 0;
+#else
+ long l = (long)off;
+ if (l != off)
+ return KERR_OUT_OF_RANGE;
+ if (!fseek(pFile->pStrm, l, SEEK_SET))
+ return 0;
+#endif
+ return kDbgHlpCrtConvErrno(errno);
+}
+
+
+int kDbgHlpSeekByCur(PKDBGHLPFILE pFile, int64_t off)
+{
+#ifdef HAVE_FSEEKO
+ if (!fseeko(pFile->pStrm, off, SEEK_CUR))
+ return 0;
+#else
+ long l = (long)off;
+ if (l != off)
+ return KERR_OUT_OF_RANGE;
+ if (!fseek(pFile->pStrm, l, SEEK_CUR))
+ return 0;
+#endif
+ return kDbgHlpCrtConvErrno(errno);
+}
+
+
+int kDbgHlpSeekByEnd(PKDBGHLPFILE pFile, int64_t off)
+{
+#ifdef HAVE_FSEEKO
+ if (!fseeko(pFile->pStrm, -off, SEEK_END))
+ return 0;
+#else
+ long l = (long)off;
+ if (l != off)
+ return KERR_OUT_OF_RANGE;
+ if (!fseek(pFile->pStrm, -l, SEEK_END))
+ return 0;
+#endif
+ return kDbgHlpCrtConvErrno(errno);
+}
+
+
+int64_t kDbgHlpTell(PKDBGHLPFILE pFile)
+{
+#ifdef HAVE_FSEEKO
+ return ftello(pFile->pStrm);
+#else
+ return ftell(pFile->pStrm);
+#endif
+}
+
diff --git a/src/lib/kStuff/kDbg/kDbgInternal.h b/src/lib/kStuff/kDbg/kDbgInternal.h
new file mode 100644
index 0000000..fdb3fcd
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgInternal.h
@@ -0,0 +1,137 @@
+/* $Id: kDbgInternal.h 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, Internal Header.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef ___kDbgInternal_h___
+#define ___kDbgInternal_h___
+
+#include <k/kHlpAssert.h>
+#include <k/kMagics.h>
+#include <k/kErrors.h>
+#include <k/kDbgAll.h>
+
+
+/** @defgroup grp_kDbgInternal Internal
+ * @internal
+ * @addtogroup grp_kDbg
+ * @{
+ */
+
+/** @def KDBG_STRICT
+ * If defined the kDbg assertions and other runtime checks will be enabled. */
+#ifdef K_ALL_STRICT
+# undef KDBG_STRICT
+# define KDBG_STRICT
+#endif
+
+/** @name Our Assert macros
+ * @{ */
+#ifdef KDBG_STRICT
+# define kDbgAssert(expr) kHlpAssert(expr)
+# define kDbgAssertReturn(expr, rcRet) kHlpAssertReturn(expr, rcRet)
+# define kDbgAssertReturnVoid(expr) kHlpAssertReturnVoid(expr)
+# define kDbgAssertMsg(expr, msg) kHlpAssertMsg(expr, msg)
+# define kDbgAssertMsgReturn(expr, msg, rcRet) kHlpAssertMsgReturn(expr, msg, rcRet)
+# define kDbgAssertMsgReturnVoid(expr, msg) kHlpAssertMsgReturnVoid(expr, msg)
+#else /* !KDBG_STRICT */
+# define kDbgAssert(expr) do { } while (0)
+# define kDbgAssertReturn(expr, rcRet) do { if (!(expr)) return (rcRet); } while (0)
+# define kDbgAssertMsg(expr, msg) do { } while (0)
+# define kDbgAssertMsgReturn(expr, msg, rcRet) do { if (!(expr)) return (rcRet); } while (0)
+#endif /* !KDBG_STRICT */
+
+#define kDbgAssertPtr(ptr) kDbgAssertMsg(K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrReturn(ptr, rcRet) kDbgAssertMsgReturn(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertPtrReturnVoid(ptr) kDbgAssertMsgReturnVoid(K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)))
+#define kDbgAssertPtrNull(ptr) kDbgAssertMsg(!(ptr) || K_VALID_PTR(ptr), ("%s = %p\n", #ptr, (ptr)))
+#define kDbgAssertPtrNullReturn(ptr, rcRet) kDbgAssertMsgReturn(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)), (rcRet))
+#define kDbgAssertPtrNullReturnVoid(ptr) kDbgAssertMsgReturnVoid(!(ptr) || K_VALID_PTR(ptr), ("%s = %p -> %d\n", #ptr, (ptr), (rcRet)))
+#define kDbgAssertRC(rc) kDbgAssertMsg((rc) == 0, ("%s = %d\n", #rc, (rc)))
+#define kDbgAssertRCReturn(rc, rcRet) kDbgAssertMsgReturn((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)), (rcRet))
+#define kDbgAssertRCReturnVoid(rc) kDbgAssertMsgReturnVoid((rc) == 0, ("%s = %d -> %d\n", #rc, (rc), (rcRet)))
+#define kDbgAssertFailed() kDbgAssert(0)
+#define kDbgAssertFailedReturn(rcRet) kDbgAssertReturn(0, (rcRet))
+#define kDbgAssertFailedReturnVoid() kDbgAssertReturnVoid(0)
+#define kDbgAssertMsgFailed(msg) kDbgAssertMsg(0, msg)
+#define kDbgAssertMsgFailedReturn(msg, rcRet) kDbgAssertMsgReturn(0, msg, (rcRet))
+#define kDbgAssertMsgFailedReturnVoid(msg) kDbgAssertMsgReturnVoid(0, msg)
+/** @} */
+
+/** Return / crash validation of a reader argument. */
+#define KDBGMOD_VALIDATE_EX(pDbgMod, rc) \
+ do { \
+ kDbgAssertPtrReturn((pDbgMod), (rc)); \
+ kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, (rc)); \
+ kDbgAssertReturn((pDbgMod)->pOps != NULL, (rc)); \
+ } while (0)
+
+/** Return / crash validation of a reader argument. */
+#define KDBGMOD_VALIDATE(pDbgMod) \
+ do { \
+ kDbgAssertPtrReturn((pDbgMod), KERR_INVALID_POINTER); \
+ kDbgAssertReturn((pDbgMod)->u32Magic == KDBGMOD_MAGIC, KERR_INVALID_HANDLE); \
+ kDbgAssertReturn((pDbgMod)->pOps != NULL, KERR_INVALID_HANDLE); \
+ } while (0)
+
+/** Return / crash validation of a reader argument. */
+#define KDBGMOD_VALIDATE_VOID(pDbgMod) \
+ do { \
+ kDbgAssertPtrReturnVoid((pDbgMod)); \
+ kDbgAssertReturnVoid((pDbgMod)->u32Magic == KDBGMOD_MAGIC); \
+ kDbgAssertReturnVoid((pDbgMod)->pOps != NULL); \
+ } while (0)
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @name Built-in Debug Module Readers
+ * @{ */
+extern KDBGMODOPS const g_kDbgModWinDbgHelpOpen;
+extern KDBGMODOPS const g_kDbgModLdr;
+extern KDBGMODOPS const g_kDbgModCv8;
+extern KDBGMODOPS const g_kDbgModDwarf;
+extern KDBGMODOPS const g_kDbgModHll;
+extern KDBGMODOPS const g_kDbgModStabs;
+extern KDBGMODOPS const g_kDbgModSym;
+extern KDBGMODOPS const g_kDbgModMapILink;
+extern KDBGMODOPS const g_kDbgModMapMSLink;
+extern KDBGMODOPS const g_kDbgModMapNm;
+extern KDBGMODOPS const g_kDbgModMapWLink;
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
+
diff --git a/src/lib/kStuff/kDbg/kDbgLine.cpp b/src/lib/kStuff/kDbg/kDbgLine.cpp
new file mode 100644
index 0000000..52e573f
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgLine.cpp
@@ -0,0 +1,78 @@
+/* $Id: kDbgLine.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Read, Line Numbers.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+
+
+/**
+ * Duplicates a line number.
+ *
+ * To save heap space, the returned line number will not own more heap space
+ * than it strictly need to. So, it's not possible to append stuff to the symbol
+ * or anything of that kind.
+ *
+ * @returns Pointer to the duplicate.
+ * This must be freed using kDbgSymbolFree().
+ * @param pLine The line number to be duplicated.
+ */
+KDBG_DECL(PKDBGLINE) kDbgLineDup(PCKDBGLINE pLine)
+{
+ kDbgAssertPtrReturn(pLine, NULL);
+ KSIZE cb = K_OFFSETOF(KDBGLINE, szFile[pLine->cchFile + 1]);
+ PKDBGLINE pNewLine = (PKDBGLINE)kHlpDup(pLine, cb);
+ if (pNewLine)
+ pNewLine->cbSelf = cb;
+ return pNewLine;
+}
+
+
+/**
+ * Frees a line number obtained from the kDbg API.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pLine isn't a valid pointer.
+ *
+ * @param pLine The line number to be freed. The null pointer is ignored.
+ */
+KDBG_DECL(int) kDbgLineFree(PKDBGLINE pLine)
+{
+ if (pLine)
+ {
+ kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER);
+ pLine->cbSelf = 0;
+ kHlpFree(pLine);
+ }
+ return 0;
+}
+
diff --git a/src/lib/kStuff/kDbg/kDbgModLdr.cpp b/src/lib/kStuff/kDbg/kDbgModLdr.cpp
new file mode 100644
index 0000000..5e77095
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgModLdr.cpp
@@ -0,0 +1,109 @@
+/* $Id: kDbgModLdr.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, kLdr Based.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <k/kDbg.h>
+#include <k/kLdr.h>
+#include "kDbgInternal.h"
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * A kLdr based debug reader.
+ */
+typedef struct KDBGMODLDR
+{
+ /** The common module core. */
+ KDBGMOD Core;
+ /** Pointer to the loader module. */
+ PKLDRMOD pLdrMod;
+} KDBGMODLDR, *PKDBGMODLDR;
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQueryLine
+ */
+static int kDbgModLdrQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR uOffset, PKDBGLINE pLine)
+{
+ //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod;
+ return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQuerySymbol
+ */
+static int kDbgModLdrQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+ //PKDBGMODLDR pThis = (PKDBGMODLDR)pMod;
+ return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnClose
+ */
+static int kDbgModLdrClose(PKDBGMOD pMod)
+{
+ //PKDBGMODLDr pThis = (PKDBGMODLDR)pMod;
+ return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * @copydocs KDBGMODOPS::pfnOpen.
+ */
+static int kDbgModLdrOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
+{
+ return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Methods for a PE module.
+ */
+const KDBGMODOPS g_kDbgModLdr =
+{
+ "kLdr",
+ NULL,
+ kDbgModLdrOpen,
+ kDbgModLdrClose,
+ kDbgModLdrQuerySymbol,
+ kDbgModLdrQueryLine,
+ "kLdr"
+};
+
+
+
+
diff --git a/src/lib/kStuff/kDbg/kDbgModPE.cpp b/src/lib/kStuff/kDbg/kDbgModPE.cpp
new file mode 100644
index 0000000..85de91c
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgModPE.cpp
@@ -0,0 +1,384 @@
+/* $Id: kDbgModPE.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, PE Module (Generic).
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "kDbg.h"
+#include "kDbgInternal.h"
+#include <kLdrModPE.h>
+#include <string.h>
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * A dbghelp based PE debug reader.
+ */
+typedef struct KDBGMODPE
+{
+ /** The common module core. */
+ KDBGMOD Core;
+ /** The image size. */
+ uint32_t cbImage;
+ /** The number of sections. (We've added the implicit header section.) */
+ int32_t cSections;
+ /** The section headers (variable size). The first section is the
+ * implicit header section.*/
+ IMAGE_SECTION_HEADER aSections[1];
+} KDBGMODPE, *PKDBGMODPE;
+
+
+/**
+ * Calcs the RVA for a segment:offset address.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pModPe The PE debug module instance.
+ * @param iSegment The segment number. Special segments are dealt with as well.
+ * @param off The segment offset.
+ * @param puRVA Where to store the RVA on success.
+ */
+static int kDbgModPeSegOffToRVA(PKDBGMODPE pModPe, int32_t iSegment, KDBGADDR off, uint32_t *puRVA)
+{
+ if (iSegment >= 0)
+ {
+ kDbgAssertMsgReturn(iSegment < pModPe->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModPe->cSections),
+ KDBG_ERR_INVALID_ADDRESS);
+ kDbgAssertMsgReturn(off < pModPe->aSections[iSegment].Misc.VirtualSize,
+ ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModPe->aSections[iSegment].Misc.VirtualSize),
+ KDBG_ERR_INVALID_ADDRESS);
+ *puRVA = pModPe->aSections[iSegment].VirtualAddress + (uint32_t)off;
+ return 0;
+ }
+
+ if (iSegment == KDBGSEG_RVA)
+ {
+ kDbgAssertMsgReturn(off < pModPe->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModPe->cbImage),
+ KDBG_ERR_INVALID_ADDRESS);
+ *puRVA = (uint32_t)off;
+ return 0;
+ }
+ kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * Calcs the segment:offset address for a RVA.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pModPe The PE debug module instance.
+ * @param uRVA The RVA.
+ * @param piSegment Where to store the segment number.
+ * @param poff Where to store the segment offset.
+ */
+static int kDbgModPeRVAToSegOff(PKDBGMODPE pModPe, uint32_t uRVA, int32_t *piSegment, KDBGADDR *poff)
+{
+ kDbgAssertMsgReturn(uRVA < pModPe->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModPe->cbImage),
+ KDBG_ERR_INVALID_ADDRESS);
+ for (int32_t iSegment = 0; iSegment < pModPe->cSections; iSegment++)
+ {
+ /** @todo should probably be less strict about address in the alignment gaps. */
+ uint32_t off = uRVA - pModPe->aSections[iSegment].VirtualAddress;
+ if (off < pModPe->aSections[iSegment].Misc.VirtualSize)
+ {
+ *poff = off;
+ *piSegment = iSegment;
+ return 0;
+ }
+ }
+ kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQueryLine
+ */
+static int kDbgModPeQueryLine(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGLINE pLine)
+{
+ PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
+
+ /*
+ * Translate the address to an RVA.
+ */
+ uint32_t uRVA;
+ int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
+ if (!rc)
+ {
+#if 0
+ DWORD64 off;
+ IMAGEHLP_LINE64 Line;
+ Line.SizeOfStruct = sizeof(Line);
+ if (g_pfnSymGetLineFromAddr64(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Line))
+ {
+ pLine->RVA = (KDBGADDR)(Line.Address - pModPe->ImageBase);
+ rc = kDbgModPeRVAToSegOff(pModPe, pLine->RVA, &pLine->iSegment, &pLine->offSegment);
+ pLine->iLine = Line.LineNumber;
+ pLine->cchFile = strlen(Line.FileName);
+ if (pLine->cchFile >= sizeof(pLine->szFile))
+ pLine->cchFile = sizeof(pLine->szFile) - 1;
+ memcpy(pLine->szFile, Line.FileName, pLine->cchFile + 1);
+ }
+ else
+ {
+ DWORD Err = GetLastError();
+ rc = kDbgModPeConvWinError(Err);
+ }
+#endif
+ rc = KERR_NOT_IMPLEMENTED;
+ }
+ return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQuerySymbol
+ */
+static int kDbgModPeQuerySymbol(PKDBGMOD pMod, int32_t iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+ PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
+
+ /*
+ * Translate the address to an RVA.
+ */
+ uint32_t uRVA;
+ int rc = kDbgModPeSegOffToRVA(pModPe, iSegment, off, &uRVA);
+ if (!rc)
+ {
+#if 0
+ DWORD64 off;
+ union
+ {
+ SYMBOL_INFO Sym;
+ char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX];
+ } Buf;
+ Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
+ Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX;
+ if (g_pfnSymFromAddr(pModPe->hSymInst, pModPe->ImageBase + uRVA, &off, &Buf.Sym))
+ {
+ pSym->cb = Buf.Sym.Size;
+ pSym->fFlags = 0;
+ if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
+ pSym->fFlags |= KDBGSYM_FLAGS_CODE;
+ else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
+ pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
+ else
+ pSym->fFlags |= KDBGSYM_FLAGS_DATA;
+ if (Buf.Sym.Flags & SYMFLAG_EXPORT)
+ pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
+ if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
+ {
+ pSym->iSegment = KDBGSEG_ABS;
+ pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
+ pSym->RVA = (KDBGADDR)Buf.Sym.Value;
+ }
+ else
+ {
+ pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModPe->ImageBase);
+ rc = kDbgModPeRVAToSegOff(pModPe, pSym->RVA, &pSym->iSegment, &pSym->offSegment);
+ }
+ pSym->cchName = (uint16_t)Buf.Sym.NameLen;
+ if (pSym->cchName >= sizeof(pSym->szName))
+ pSym->cchName = sizeof(pSym->szName) - 1;
+ memcpy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
+ pSym->szName[Buf.Sym.NameLen] = '\0';
+ }
+ else
+ {
+ DWORD Err = GetLastError();
+ rc = kDbgModPeConvWinError(Err);
+ }
+#endif
+ rc = KERR_NOT_IMPLEMENTED;
+ }
+ return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnClose
+ */
+static int kDbgModPeClose(PKDBGMOD pMod)
+{
+ PKDBGMODPE pModPe = (PKDBGMODPE)pMod;
+
+ //if (g_pfnSymCleanup(pModPe->hSymInst))
+ // return 0;
+ //
+ //DWORD Err = GetLastError();
+ //int rc = kDbgModPeConvWinError(Err);
+ //kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
+ //return rc;
+ return KERR_NOT_IMPLEMENTED;
+}
+
+
+/**
+ * Opens the debug info for a PE image using the windows dbghelp library.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pFile The handle to the module.
+ * @param offHdr The offset of the PE header.
+ * @param pszModulePath The path to the module.
+ * @param ppDbgMod Where to store the module handle.
+ *
+ */
+int kdbgModPEOpen(PKDBGHLPFILE pFile, int64_t offHdr, const char *pszModulePath, PKDBGMOD *ppDbgMod)
+{
+ /*
+ * We need to read the section headers and get the image size.
+ */
+ IMAGE_FILE_HEADER FHdr;
+ int rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader), &FHdr, sizeof(FHdr));
+ kDbgAssertRCReturn(rc, rc);
+
+ uint32_t cbImage;
+ if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
+ rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage),
+ &cbImage, sizeof(cbImage));
+ else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
+ rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage),
+ &cbImage, sizeof(cbImage));
+ else
+ kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
+ kDbgAssertRCReturn(rc, rc);
+
+ /*
+ * Allocate the module and read/construct the section headers.
+ */
+ PKDBGMODPE pModPe = (PKDBGMODPE)kDbgHlpAlloc(KDBG_OFFSETOF(KDBGMODPE, aSections[FHdr.NumberOfSections + 2]));
+ kDbgAssertReturn(pModPe, KERR_NO_MEMORY);
+ pModPe->Core.u32Magic = KDBGMOD_MAGIC;
+ pModPe->Core.pOps = &g_kDbgModPeOps;
+ pModPe->Core.pFile = pFile;
+ pModPe->cbImage = cbImage;
+ pModPe->cSections = 1 + FHdr.NumberOfSections;
+ rc = kDbgHlpReadAt(pFile, offHdr + KDBG_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader,
+ &pModPe->aSections[1], sizeof(pModPe->aSections[0]) * FHdr.NumberOfSections);
+ if (!rc)
+ {
+ PIMAGE_SECTION_HEADER pSH = &pModPe->aSections[0];
+ memcpy(pSH->Name, "headers", sizeof(pSH->Name));
+ pSH->Misc.VirtualSize = pModPe->aSections[1].VirtualAddress;
+ pSH->VirtualAddress = 0;
+ pSH->SizeOfRawData = pSH->Misc.VirtualSize;
+ pSH->PointerToRawData = 0;
+ pSH->PointerToRelocations = 0;
+ pSH->PointerToLinenumbers = 0;
+ pSH->NumberOfRelocations = 0;
+ pSH->NumberOfLinenumbers = 0;
+ pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
+
+ uint32_t uTheEnd = pModPe->aSections[FHdr.NumberOfSections].VirtualAddress
+ + pModPe->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
+ if (uTheEnd < cbImage)
+ {
+ pSH = &pModPe->aSections[pModPe->cSections++];
+ memcpy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
+ pSH->Misc.VirtualSize = cbImage - uTheEnd;
+ pSH->VirtualAddress = uTheEnd;
+ pSH->SizeOfRawData = pSH->Misc.VirtualSize;
+ pSH->PointerToRawData = 0;
+ pSH->PointerToRelocations = 0;
+ pSH->PointerToLinenumbers = 0;
+ pSH->NumberOfRelocations = 0;
+ pSH->NumberOfLinenumbers = 0;
+ pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
+ }
+
+#if 0
+ /*
+ * Find a new dbghelp handle.
+ *
+ * We assume 4GB of handles outlast most debugging sessions, or in anyways that
+ * when we start reusing handles they are no longer in use. :-)
+ */
+ static volatile uint32_t s_u32LastHandle = 1;
+ HANDLE hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
+ while ( hSymInst == INVALID_HANDLE_VALUE
+ || hSymInst == (HANDLE)0
+ || hSymInst == GetCurrentProcess())
+ hSymInst = (HANDLE)ASMAtomicIncU32(&s_u32LastHandle);
+
+ /*
+ * Initialize dbghelp and try open the specified module.
+ */
+ if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
+ {
+ g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
+
+ kDbgHlpSeek(pFile, 0); /* don't know if this is required or not... */
+ DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, (HANDLE)File, pszModulePath, NULL, 0x00400000, 0);
+ if (ImageBase)
+ {
+ pModPe->hSymInst = hSymInst;
+ pModPe->ImageBase = ImageBase;
+ *ppDbgMod = &pModPe->Core;
+ return rc;
+ }
+
+ DWORD Err = GetLastError();
+ rc = kDbgModPeConvWinError(Err);
+ kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%Rrc\n", Err, rc));
+ g_pfnSymCleanup(hSymInst);
+ }
+ else
+ {
+ DWORD Err = GetLastError();
+ rc = kDbgModPeConvWinError(Err);
+ kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%Rrc\n", Err, rc));
+ }
+#endif
+ rc = KERR_NOT_IMPLEMENTED;
+ }
+ else
+ kDbgAssertRC(rc);
+
+ kDbgHlpFree(pModPe);
+ return rc;
+}
+
+
+/**
+ * Methods for a PE module.
+ */
+const KDBGMODOPS g_kDbgModPeOps =
+{
+ "PE",
+ kDbgModPeClose,
+ kDbgModPeQuerySymbol,
+ kDbgModPeQueryLine
+};
+
+
+
diff --git a/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp b/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp
new file mode 100644
index 0000000..3c30773
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgModWinDbgHelp.cpp
@@ -0,0 +1,724 @@
+/* $Id: kDbgModWinDbgHelp.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, DbgHelp Based Reader.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <Windows.h>
+#define _IMAGEHLP64
+#include <DbgHelp.h>
+
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** The dbghelp.dll module handle. */
+static HMODULE g_hDbgHelp = NULL;
+/** Pointer to the dbhelp.dll SymInitialize function. */
+static BOOL (WINAPI *g_pfnSymInitialize)(IN HANDLE,IN LPSTR,IN BOOL);
+/** Pointer to the dbhelp.dll SymCleanup function. */
+static BOOL (WINAPI *g_pfnSymCleanup)(IN HANDLE);
+/** Pointer to the dbhelp.dll SymSetOptions function. */
+static DWORD (WINAPI *g_pfnSymSetOptions)(IN DWORD);
+/** Pointer to the dbhelp.dll SymLoadModule64 function. */
+static DWORD64 (WINAPI *g_pfnSymLoadModule64)(IN HANDLE, IN HANDLE, IN PCSTR, IN PCSTR ModuleName, IN DWORD64, IN DWORD);
+/** Pointer to the dbhelp.dll SymFromAddr function. */
+static DWORD (WINAPI *g_pfnSymFromAddr)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PSYMBOL_INFO);
+/** Pointer to the dbhelp.dll SymGetLineFromAddr64 function. */
+static DWORD (WINAPI *g_pfnSymGetLineFromAddr64)(IN HANDLE, IN DWORD64, OUT PDWORD64, OUT PIMAGEHLP_LINE64);
+
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/**
+ * A dbghelp based PE debug reader.
+ */
+typedef struct KDBGMODDBGHELP
+{
+ /** The common module core. */
+ KDBGMOD Core;
+ /** The image base. */
+ DWORD64 ImageBase;
+ /** The "process" handle we present dbghelp. */
+ HANDLE hSymInst;
+ /** The image size. */
+ KU32 cbImage;
+ /** The number of sections. (We've added the implicit header section.) */
+ KI32 cSections;
+ /** The section headers (variable size). The first section is the
+ * implicit header section.*/
+ IMAGE_SECTION_HEADER aSections[1];
+} KDBGMODDBGHELP, *PKDBGMODDBGHELP;
+
+
+/**
+ * Convers a Windows error to kDbg error code.
+ *
+ * @returns kDbg status code.
+ * @param rc The Windows error.
+ */
+static int kdbgModDHConvWinError(DWORD rc)
+{
+ switch (rc)
+ {
+ case 0: return 0;
+ default: return KERR_GENERAL_FAILURE;
+ }
+}
+
+
+/**
+ * Calcs the RVA for a segment:offset address.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pModDH The PE debug module instance.
+ * @param iSegment The segment number. Special segments are dealt with as well.
+ * @param off The segment offset.
+ * @param puRVA Where to store the RVA on success.
+ */
+static int kdbgModDHSegOffToRVA(PKDBGMODDBGHELP pModDH, KI32 iSegment, KDBGADDR off, KU32 *puRVA)
+{
+ if (iSegment >= 0)
+ {
+ kDbgAssertMsgReturn(iSegment < pModDH->cSections, ("iSegment=%x cSections=%x\n", iSegment, pModDH->cSections),
+ KDBG_ERR_INVALID_ADDRESS);
+ kDbgAssertMsgReturn(off < pModDH->aSections[iSegment].Misc.VirtualSize,
+ ("off=" PRI_KDBGADDR " VirtualSize=%x\n", off, pModDH->aSections[iSegment].Misc.VirtualSize),
+ KDBG_ERR_INVALID_ADDRESS);
+ *puRVA = pModDH->aSections[iSegment].VirtualAddress + (KU32)off;
+ return 0;
+ }
+
+ if (iSegment == KDBGSEG_RVA)
+ {
+ kDbgAssertMsgReturn(off < pModDH->cbImage, ("off=" PRI_KDBGADDR ", cbImage=%x\n", off, pModDH->cbImage),
+ KDBG_ERR_INVALID_ADDRESS);
+ *puRVA = (KU32)off;
+ return 0;
+ }
+ kDbgAssertMsgFailedReturn(("iSegment=%d\n", iSegment), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * Calcs the segment:offset address for a RVA.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pModDH The PE debug module instance.
+ * @param uRVA The RVA.
+ * @param piSegment Where to store the segment number.
+ * @param poff Where to store the segment offset.
+ */
+static int kdbgModDHRVAToSegOff(PKDBGMODDBGHELP pModDH, KU32 uRVA, KI32 *piSegment, KDBGADDR *poff)
+{
+ kDbgAssertMsgReturn(uRVA < pModDH->cbImage, ("uRVA=%x, cbImage=%x\n", uRVA, pModDH->cbImage),
+ KDBG_ERR_INVALID_ADDRESS);
+ for (KI32 iSegment = 0; iSegment < pModDH->cSections; iSegment++)
+ {
+ /** @todo should probably be less strict about address in the alignment gaps. */
+ KU32 off = uRVA - pModDH->aSections[iSegment].VirtualAddress;
+ if (off < pModDH->aSections[iSegment].Misc.VirtualSize)
+ {
+ *poff = off;
+ *piSegment = iSegment;
+ return 0;
+ }
+ }
+ kDbgAssertMsgFailedReturn(("uRVA=%x\n", uRVA), KDBG_ERR_INVALID_ADDRESS);
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQueryLine
+ */
+static int kdbgModDHQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine)
+{
+ PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
+
+ /*
+ * Translate the address to an RVA.
+ */
+ KU32 uRVA;
+ int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA);
+ if (!rc)
+ {
+ DWORD64 off;
+ IMAGEHLP_LINE64 Line;
+ Line.SizeOfStruct = sizeof(Line);
+ if (g_pfnSymGetLineFromAddr64(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Line))
+ {
+ pLine->RVA = (KDBGADDR)(Line.Address - pModDH->ImageBase);
+ rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pLine->RVA, &pLine->iSegment, &pLine->offSegment);
+ pLine->iLine = Line.LineNumber;
+ KSIZE cchFile = kHlpStrLen(Line.FileName);
+ pLine->cchFile = cchFile < sizeof(pLine->szFile)
+ ? (KU16)cchFile
+ : (KU16)sizeof(pLine->szFile) - 1;
+ kHlpMemCopy(pLine->szFile, Line.FileName, pLine->cchFile);
+ pLine->szFile[pLine->cchFile] = '\0';
+ }
+ else
+ {
+ DWORD Err = GetLastError();
+ rc = kdbgModDHConvWinError(Err);
+ }
+ }
+ return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnQuerySymbol
+ */
+static int kdbgModDHQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+ PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
+
+ /*
+ * Translate the address to an RVA.
+ */
+ KU32 uRVA;
+ int rc = kdbgModDHSegOffToRVA(pModDH, iSegment, off, &uRVA);
+ if (!rc)
+ {
+ DWORD64 off;
+ union
+ {
+ SYMBOL_INFO Sym;
+ char achBuffer[sizeof(SYMBOL_INFO) + KDBG_SYMBOL_MAX];
+ } Buf;
+ Buf.Sym.SizeOfStruct = sizeof(SYMBOL_INFO);
+ Buf.Sym.MaxNameLen = KDBG_SYMBOL_MAX;
+ if (g_pfnSymFromAddr(pModDH->hSymInst, pModDH->ImageBase + uRVA, &off, &Buf.Sym))
+ {
+ pSym->cb = Buf.Sym.Size;
+ pSym->Address = NIL_KDBGADDR;
+ pSym->fFlags = 0;
+ if (Buf.Sym.Flags & SYMFLAG_FUNCTION)
+ pSym->fFlags |= KDBGSYM_FLAGS_CODE;
+ else if (Buf.Sym.Flags & SYMFLAG_CONSTANT)
+ pSym->fFlags |= KDBGSYM_FLAGS_ABS; /** @todo SYMFLAG_CONSTANT must be tested - documentation is too brief to say what is really meant here.*/
+ else
+ pSym->fFlags |= KDBGSYM_FLAGS_DATA;
+ if (Buf.Sym.Flags & SYMFLAG_EXPORT)
+ pSym->fFlags |= KDBGSYM_FLAGS_EXPORTED;
+ if ((Buf.Sym.Flags & (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT)) == (SYMFLAG_VALUEPRESENT | SYMFLAG_CONSTANT))
+ {
+ pSym->iSegment = KDBGSEG_ABS;
+ pSym->offSegment = (KDBGADDR)Buf.Sym.Value;
+ pSym->RVA = (KDBGADDR)Buf.Sym.Value;
+ }
+ else
+ {
+ pSym->RVA = (KDBGADDR)(Buf.Sym.Address - pModDH->ImageBase);
+ rc = kdbgModDHRVAToSegOff(pModDH, (KU32)pSym->RVA, &pSym->iSegment, &pSym->offSegment);
+ }
+ pSym->cchName = (KU16)Buf.Sym.NameLen;
+ if (pSym->cchName >= sizeof(pSym->szName))
+ pSym->cchName = sizeof(pSym->szName) - 1;
+ kHlpMemCopy(pSym->szName, Buf.Sym.Name, Buf.Sym.NameLen);
+ pSym->szName[Buf.Sym.NameLen] = '\0';
+ }
+ else
+ {
+ DWORD Err = GetLastError();
+ rc = kdbgModDHConvWinError(Err);
+ }
+ }
+ return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnClose
+ */
+static int kdbgModDHClose(PKDBGMOD pMod)
+{
+ PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)pMod;
+
+ if (g_pfnSymCleanup(pModDH->hSymInst))
+ return 0;
+
+ DWORD Err = GetLastError();
+ int rc = kdbgModDHConvWinError(Err);
+ kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
+ return rc;
+}
+
+
+/**
+ * Checks if the specified dbghelp.dll is usable.
+ *
+ * @returns IPRT status code.
+ *
+ * @param pszPath the path to the dbghelp.dll.
+ */
+static int kdbgModDHTryDbgHelp(const char *pszPath, KU32 *pu32FileVersionMS, KU32 *pu32FileVersionLS)
+{
+ int rc;
+ DWORD dwHandle = 0;
+ DWORD cb = GetFileVersionInfoSize(pszPath, &dwHandle);
+ if (cb > 0)
+ {
+ void *pvBuf = alloca(cb);
+ if (GetFileVersionInfo(pszPath, dwHandle, cb, pvBuf))
+ {
+ UINT cbValue = 0;
+ VS_FIXEDFILEINFO *pFileInfo;
+ if (VerQueryValue(pvBuf, "\\", (void **)&pFileInfo, &cbValue))
+ {
+ /** @todo somehow reject 64-bit .dlls when in 32-bit mode... dwFileOS is completely useless. */
+ if ( *pu32FileVersionMS < pFileInfo->dwFileVersionMS
+ || ( *pu32FileVersionMS == pFileInfo->dwFileVersionMS
+ && *pu32FileVersionLS > pFileInfo->dwFileVersionLS))
+ {
+ *pu32FileVersionMS = pFileInfo->dwFileVersionMS;
+ *pu32FileVersionLS = pFileInfo->dwFileVersionLS;
+ }
+ if (pFileInfo->dwFileVersionMS >= 0x60004)
+ rc = 0;
+ else
+ rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
+ }
+ else
+ rc = KERR_GENERAL_FAILURE;
+ }
+ else
+ rc = kdbgModDHConvWinError(GetLastError());
+ }
+ else
+ rc = kdbgModDHConvWinError(GetLastError());
+ return rc;
+}
+
+
+/**
+ * Find the dbghelp.dll
+ */
+static int kdbgModDHFindDbgHelp(char *pszPath, KSIZE cchPath)
+{
+ /*
+ * Try the current directory.
+ */
+ KU32 FileVersionMS = 0;
+ KU32 FileVersionLS = 0;
+ int rc = KERR_GENERAL_FAILURE;
+ static char s_szDbgHelp[] = "\\dbghelp.dll";
+ if (GetCurrentDirectory((DWORD)(cchPath - sizeof(s_szDbgHelp) + 1), pszPath))
+ {
+ strcat(pszPath, s_szDbgHelp);
+ int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+ if (!rc2)
+ return rc2;
+ if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+ rc = rc2;
+ }
+
+ /*
+ * Try the application directory.
+ */
+ if (GetModuleFileName(NULL, pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
+ {
+ kHlpStrCat(kHlpStrRChr(pszPath, '\\'), s_szDbgHelp);
+ int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+ if (!rc)
+ return rc2;
+ if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+ rc = rc2;
+ }
+
+ /*
+ * Try the windows directory.
+ */
+ if (GetSystemDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
+ {
+ kHlpStrCat(pszPath, s_szDbgHelp);
+ int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+ if (!rc2)
+ return rc2;
+ if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+ rc = rc2;
+ }
+
+ /*
+ * Try the windows directory.
+ */
+ if (GetWindowsDirectory(pszPath, (DWORD)(cchPath - sizeof(s_szDbgHelp) + 1)))
+ {
+ kHlpStrCat(pszPath, s_szDbgHelp);
+ int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+ if (!rc2)
+ return rc2;
+ if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+ rc = rc2;
+ }
+
+ /*
+ * Try the path.
+ */
+ /** @todo find the actual path specs, I'm probably not doing this 100% correctly here. */
+ DWORD cb = GetEnvironmentVariable("PATH", NULL, 0) + 64;
+ char *pszSearchPath = (char *) alloca(cb);
+ if (GetEnvironmentVariable("PATH", pszSearchPath, cb) < cb)
+ {
+ char *psz = pszSearchPath;
+ while (*psz)
+ {
+ /* find the end of the path. */
+ char *pszEnd = kHlpStrChr(psz, ';');
+ if (!pszEnd)
+ pszEnd = kHlpStrChr(psz, '\0');
+ if (pszEnd != psz)
+ {
+ /* construct filename and try it out */
+ kHlpMemCopy(pszPath, psz, pszEnd - psz);
+ kHlpMemCopy(&pszPath[pszEnd - psz], s_szDbgHelp, sizeof(s_szDbgHelp));
+ int rc2 = kdbgModDHTryDbgHelp(pszPath, &FileVersionMS, &FileVersionLS);
+ if (!rc2)
+ return rc2;
+ if (rc != KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+ rc = rc2;
+ }
+
+ /* next path */
+ if (!*pszEnd)
+ break;
+ psz = pszEnd + 1;
+ }
+ }
+
+ if (rc == KDBG_ERR_DBGHLP_VERSION_MISMATCH)
+ kDbgAssertMsgFailed(("dbghelp.dll found, but it was ancient! The highest file version found was 0x%08x'%08x.\n"
+ "This program require a file version of at least 0x00060004'00000000. Please download\n"
+ "the latest windbg and use the dbghelp.dll from that package. Just put it somewhere in\n"
+ "the PATH and we'll find it.\n", FileVersionMS, FileVersionLS));
+ else
+ kDbgAssertMsgFailed(("dbghelp.dll was not found! Download the latest windbg and use the dbghelp.dll\n"
+ "from that package - just put it somewhere in the PATH and we'll find it.\n"));
+ return rc;
+}
+
+
+/**
+ * Loads the dbghelp.dll, check that it's the right version, and
+ * resolves all the symbols we need.
+ *
+ * @returns IPRT status code.
+ */
+static int kdbgModDHLoadDbgHelp(void)
+{
+ if (g_hDbgHelp)
+ return 0;
+
+ /* primitive locking - make some useful API for this kind of spinning! */
+ static volatile long s_lLock = 0;
+ while (InterlockedCompareExchange(&s_lLock, 1, 0))
+ while (s_lLock)
+ Sleep(1);
+ if (g_hDbgHelp)
+ {
+ InterlockedExchange(&s_lLock, 0);
+ return 0;
+ }
+
+ /*
+ * Load it - try current dir first.
+ */
+ char szPath[260];
+ int rc = kdbgModDHFindDbgHelp(szPath, sizeof(szPath));
+ if (rc)
+ {
+ InterlockedExchange(&s_lLock, 0);
+ return rc;
+ }
+
+ HMODULE hmod = LoadLibraryEx(szPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hmod)
+ {
+ DWORD Err = GetLastError();
+ int rc = kdbgModDHConvWinError(Err);
+ InterlockedExchange(&s_lLock, 0);
+ kDbgAssertMsgFailedReturn(("Failed to load '%s', Err=%d rc=%d\n", szPath, Err, rc), rc);
+ }
+
+ /*
+ * Check the API version (too).
+ */
+ LPAPI_VERSION (WINAPI *pfnImagehlpApiVersion)(VOID);
+ FARPROC *ppfn = (FARPROC *)&pfnImagehlpApiVersion;
+ *ppfn = GetProcAddress(hmod, "ImagehlpApiVersion");
+ if (*ppfn)
+ {
+ LPAPI_VERSION pVersion = pfnImagehlpApiVersion();
+ if ( pVersion
+ && ( pVersion->MajorVersion > 4
+ || (pVersion->MajorVersion == 4 && pVersion->MinorVersion > 0)
+ || (pVersion->MajorVersion == 4 && pVersion->MinorVersion == 0 && pVersion->Revision >= 5)
+ )
+ )
+ {
+ /*
+ * Resolve the entrypoints we need.
+ */
+ static const struct
+ {
+ const char *pszName;
+ FARPROC *ppfn;
+ } s_aFunctions[] =
+ {
+ { "SymInitialize", (FARPROC *)&g_pfnSymInitialize },
+ { "SymCleanup", (FARPROC *)&g_pfnSymCleanup },
+ { "SymSetOptions", (FARPROC *)&g_pfnSymSetOptions },
+ { "SymLoadModule64", (FARPROC *)&g_pfnSymLoadModule64 },
+ { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
+ { "SymFromAddr", (FARPROC *)&g_pfnSymFromAddr },
+ { "SymGetLineFromAddr64", (FARPROC *)&g_pfnSymGetLineFromAddr64 },
+ };
+ for (unsigned i = 0; i < K_ELEMENTS(s_aFunctions); i++)
+ {
+ FARPROC pfn = GetProcAddress(hmod, s_aFunctions[i].pszName);
+ if (!pfn)
+ {
+ DWORD Err = GetLastError();
+ rc = kdbgModDHConvWinError(Err);
+ kDbgAssertMsgFailed(("Failed to resolve %s in dbghelp, Err=%d rc=%d\n",
+ s_aFunctions[i].pszName, Err, rc));
+ break;
+ }
+ *s_aFunctions[i].ppfn = pfn;
+ }
+ if (!rc)
+ {
+ g_hDbgHelp = hmod;
+ Sleep(1);
+ InterlockedExchange(&s_lLock, 0);
+ return 0;
+ }
+ }
+ else
+ {
+ rc = KDBG_ERR_DBGHLP_VERSION_MISMATCH;
+ kDbgAssertMsgFailed(("ImagehlpApiVersion -> %p and MajorVersion=%d.\n", pVersion, pVersion ? pVersion->MajorVersion : 0));
+ }
+ }
+ else
+ {
+ DWORD Err = GetLastError();
+ rc = kdbgModDHConvWinError(Err);
+ kDbgAssertMsgFailed(("Failed to resolve ImagehlpApiVersionEx in dbghelp, Err=%d rc=%d\n", Err, rc));
+ }
+ FreeLibrary(hmod);
+ InterlockedExchange(&s_lLock, 0);
+ return rc;
+}
+
+
+/**
+ * @copydoc KDBGMODOPS::pfnOpen
+ */
+static int kdbgModDHOpen(PKDBGMOD *ppMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
+{
+ /*
+ * This reader doesn't support partial files.
+ * Also weed out small files early on as they cannot be
+ * PE images and will only cause read errors
+ */
+ if ( off != 0
+ || cb != KFOFF_MAX)
+ return KDBG_ERR_UNKOWN_FORMAT;
+ if (kRdrSize(pRdr) < sizeof(IMAGE_NT_HEADERS32) + sizeof(IMAGE_SECTION_HEADER))
+ return KDBG_ERR_UNKOWN_FORMAT;
+
+ /*
+ * We need to read the section headers and get the image size.
+ */
+ /* Find the PE header magic. */
+ KU32 offHdr = 0;
+ KU32 u32Magic;
+ int rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), 0);
+ kDbgAssertRCReturn(rc, rc);
+ if ((KU16)u32Magic == IMAGE_DOS_SIGNATURE)
+ {
+ rc = kRdrRead(pRdr, &offHdr, sizeof(offHdr), K_OFFSETOF(IMAGE_DOS_HEADER, e_lfanew));
+ kDbgAssertRCReturn(rc, rc);
+ if (!offHdr)
+ return KDBG_ERR_FORMAT_NOT_SUPPORTED;
+ if ( offHdr < sizeof(IMAGE_DOS_SIGNATURE)
+ || offHdr >= kRdrSize(pRdr) - 4)
+ return KDBG_ERR_BAD_EXE_FORMAT;
+
+ rc = kRdrRead(pRdr, &u32Magic, sizeof(u32Magic), offHdr);
+ kDbgAssertRCReturn(rc, rc);
+ }
+ if (u32Magic != IMAGE_NT_SIGNATURE)
+ return KDBG_ERR_FORMAT_NOT_SUPPORTED;
+
+ /* read the file header and the image size in the optional header.. */
+ IMAGE_FILE_HEADER FHdr;
+ rc = kRdrRead(pRdr, &FHdr, sizeof(FHdr), offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, FileHeader));
+ kDbgAssertRCReturn(rc, rc);
+
+ KU32 cbImage;
+ if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER32))
+ rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
+ offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.SizeOfImage));
+ else if (FHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER64))
+ rc = kRdrRead(pRdr, &cbImage, sizeof(cbImage),
+ offHdr + K_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.SizeOfImage));
+ else
+ kDbgAssertFailedReturn(KDBG_ERR_BAD_EXE_FORMAT);
+ kDbgAssertRCReturn(rc, rc);
+
+ /*
+ * Load dbghelp.dll.
+ */
+ rc = kdbgModDHLoadDbgHelp();
+ if (rc)
+ return rc;
+
+ /*
+ * Allocate the module and read/construct the section headers.
+ */
+ PKDBGMODDBGHELP pModDH = (PKDBGMODDBGHELP)kHlpAlloc(K_OFFSETOF(KDBGMODDBGHELP, aSections[FHdr.NumberOfSections + 2]));
+ kDbgAssertReturn(pModDH, KERR_NO_MEMORY);
+ pModDH->Core.u32Magic = KDBGMOD_MAGIC;
+ pModDH->Core.pOps = &g_kDbgModWinDbgHelpOpen;
+ pModDH->Core.pRdr = pRdr;
+ pModDH->Core.fCloseRdr = fCloseRdr;
+ pModDH->Core.pLdrMod = pLdrMod;
+ pModDH->cbImage = cbImage;
+ pModDH->cSections = 1 + FHdr.NumberOfSections;
+
+ rc = kRdrRead(pRdr, &pModDH->aSections[1], sizeof(pModDH->aSections[0]) * FHdr.NumberOfSections,
+ offHdr + K_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader) + FHdr.SizeOfOptionalHeader);
+ if (!rc)
+ {
+ PIMAGE_SECTION_HEADER pSH = &pModDH->aSections[0];
+ kHlpMemCopy(pSH->Name, "headers", sizeof(pSH->Name));
+ pSH->Misc.VirtualSize = pModDH->aSections[1].VirtualAddress;
+ pSH->VirtualAddress = 0;
+ pSH->SizeOfRawData = pSH->Misc.VirtualSize;
+ pSH->PointerToRawData = 0;
+ pSH->PointerToRelocations = 0;
+ pSH->PointerToLinenumbers = 0;
+ pSH->NumberOfRelocations = 0;
+ pSH->NumberOfLinenumbers = 0;
+ pSH->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ;
+
+ KU32 uTheEnd = pModDH->aSections[FHdr.NumberOfSections].VirtualAddress
+ + pModDH->aSections[FHdr.NumberOfSections].Misc.VirtualSize;
+ if (uTheEnd < cbImage)
+ {
+ pSH = &pModDH->aSections[pModDH->cSections++];
+ kHlpMemCopy(pSH->Name, "tail\0\0\0", sizeof(pSH->Name));
+ pSH->Misc.VirtualSize = cbImage - uTheEnd;
+ pSH->VirtualAddress = uTheEnd;
+ pSH->SizeOfRawData = pSH->Misc.VirtualSize;
+ pSH->PointerToRawData = 0;
+ pSH->PointerToRelocations = 0;
+ pSH->PointerToLinenumbers = 0;
+ pSH->NumberOfRelocations = 0;
+ pSH->NumberOfLinenumbers = 0;
+ pSH->Characteristics = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_ALIGN_1BYTES | IMAGE_SCN_MEM_READ;
+ }
+
+ /*
+ * Find a new dbghelp handle.
+ *
+ * We assume 4GB of handles outlast most debugging sessions, or in anyways that
+ * when we start reusing handles they are no longer in use. :-)
+ */
+ static volatile long s_u32LastHandle = 1;
+ HANDLE hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
+ while ( hSymInst == INVALID_HANDLE_VALUE
+ || hSymInst == (HANDLE)0
+ || hSymInst == GetCurrentProcess())
+ hSymInst = (HANDLE)InterlockedIncrement(&s_u32LastHandle);
+
+ /*
+ * Initialize dbghelp and try open the specified module.
+ */
+ if (g_pfnSymInitialize(hSymInst, NULL, FALSE))
+ {
+ g_pfnSymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_AUTO_PUBLICS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS);
+
+ KIPTR NativeFH = kRdrNativeFH(pRdr);
+ DWORD64 ImageBase = g_pfnSymLoadModule64(hSymInst, NativeFH == -1 ? NULL : (HANDLE)NativeFH,
+ kRdrName(pRdr), NULL, 0x00400000, 0);
+ if (ImageBase)
+ {
+ pModDH->hSymInst = hSymInst;
+ pModDH->ImageBase = ImageBase;
+ *ppMod = &pModDH->Core;
+ return rc;
+ }
+
+ DWORD Err = GetLastError();
+ rc = kdbgModDHConvWinError(Err);
+ kDbgAssertMsgFailed(("SymLoadModule64 failed: Err=%d rc=%d\n", Err, rc));
+ g_pfnSymCleanup(hSymInst);
+ }
+ else
+ {
+ DWORD Err = GetLastError();
+ rc = kdbgModDHConvWinError(Err);
+ kDbgAssertMsgFailed(("SymInitialize failed: Err=%d rc=%d\n", Err, rc));
+ }
+ }
+ else
+ kDbgAssertRC(rc);
+
+ kHlpFree(pModDH);
+ return rc;
+}
+
+
+/**
+ * Methods for a PE module.
+ */
+KDBGMODOPS const g_kDbgModWinDbgHelpOpen =
+{
+ "Windows DbgHelp",
+ NULL,
+ kdbgModDHOpen,
+ kdbgModDHClose,
+ kdbgModDHQuerySymbol,
+ kdbgModDHQueryLine,
+ "Windows DbgHelp"
+};
+
diff --git a/src/lib/kStuff/kDbg/kDbgModule.cpp b/src/lib/kStuff/kDbg/kDbgModule.cpp
new file mode 100644
index 0000000..c43fb16
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgModule.cpp
@@ -0,0 +1,440 @@
+/* $Id: kDbgModule.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, Module API.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpString.h>
+#include <k/kHlpAlloc.h>
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * The built-in debug module readers.
+ */
+static PCKDBGMODOPS const g_aBuiltIns[] =
+{
+#if K_OS == K_OS_WINDOWS
+ &g_kDbgModWinDbgHelpOpen,
+#endif
+ &g_kDbgModLdr,
+// &g_kDbgModCv8,
+// &g_kDbgModDwarf,
+// &g_kDbgModHll,
+// &g_kDbgModStabs,
+// &g_kDbgModSym,
+// &g_kDbgModMapILink,
+// &g_kDbgModMapMSLink,
+// &g_kDbgModMapNm,
+// &g_kDbgModMapWLink
+};
+
+/**
+ * The debug module readers registered at runtime.
+ */
+static PKDBGMODOPS g_pHead = NULL;
+
+
+/**
+ * Register a debug module reader with the kDbgModule component.
+ *
+ * Dynamically registered readers are kept in FIFO order, and external
+ * readers will be tried after the builtin ones.
+ *
+ * Like all other kDbg APIs serializing is left to the caller.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pOps is missing bits.
+ * @returns KERR_INVALID_PARAMETER if pOps is already in the list.
+ * @param pOps The reader method table, kDbg takes owner ship of
+ * this. This must be writeable as the pNext pointer
+ * will be update. It must also stick around for as
+ * long as kDbg is in use.
+ */
+KDBG_DECL(int) kDbgModuleRegisterReader(PKDBGMODOPS pOps)
+{
+ /*
+ * Validate input.
+ */
+ kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pOps->pszName, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pOps->pfnOpen, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pOps->pfnClose, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pOps->pfnQuerySymbol, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pOps->pfnQueryLine, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pOps->pszName2, KERR_INVALID_POINTER);
+ if (kHlpStrComp(pOps->pszName, pOps->pszName2))
+ return KERR_INVALID_PARAMETER;
+ kDbgAssertReturn(pOps->pNext == NULL, KERR_INVALID_PARAMETER);
+
+ /*
+ * Link it into the list.
+ */
+ if (!g_pHead)
+ g_pHead = pOps;
+ else
+ {
+ PKDBGMODOPS pPrev = g_pHead;
+ while (pPrev->pNext)
+ pPrev = pPrev->pNext;
+ kDbgAssertReturn(pPrev != pOps, KERR_INVALID_PARAMETER);
+ pPrev->pNext = pOps;
+ }
+ return 0;
+}
+
+
+/**
+ * Deregister a debug module reader previously registered using
+ * the kDbgModuleRegisterReader API.
+ *
+ * Deregistering a reader does not mean that non of its functions
+ * will be called after successful return, it only means that it
+ * will no longer be subjected to new module.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pOps isn't a valid pointer.
+ * @returns KERR_INVALID_PARAMETER if pOps wasn't registered.
+ * @param pOps The debug module method table to deregister.
+ */
+KDBG_DECL(int) kDbgModuleDeregisterReader(PKDBGMODOPS pOps)
+{
+ /*
+ * Validate the pointer.
+ */
+ kDbgAssertPtrReturn(pOps, KERR_INVALID_POINTER);
+
+ /*
+ * Find it in the list and unlink it.
+ */
+ if (g_pHead == pOps)
+ g_pHead = pOps->pNext;
+ else
+ {
+ PKDBGMODOPS pPrev = g_pHead;
+ while (pPrev && pPrev->pNext != pOps)
+ pPrev = pPrev->pNext;
+ if (!pPrev)
+ return KERR_INVALID_PARAMETER;
+ pPrev->pNext = pOps->pNext;
+ }
+ pOps->pNext = NULL;
+ return 0;
+}
+
+
+
+/**
+ * Worker for the kDbgModuleOpen* APIs.
+ *
+ * This will make sure the reader is buffered. I will also take care of
+ * closing the reader opened by kDbgModuleOpen on failure.
+ *
+ * @returns 0 on success. An appropriate kErrors status code on failure.
+ * @param ppDbgMod Where to store the new debug module reader instance.
+ * @param pRdr The file provider.
+ * @param fCloseRdr Whether pRdr should be close or not. This applies both
+ * to the failure path and to the success path, where it'll
+ * be close when the module is closed by kDbgModuleClose().
+ * @param off The offset into the file where the debug info is supposed
+ * to be found.
+ * This is 0 if the entire file is the subject.
+ * @param cb The size of the debug info part of the file.
+ * This is KFOFF_MAX if the entire file is the subject.
+ * @param pLdrMod An optional kLdrMod association.
+ */
+static int kdbgModuleOpenWorker(PPKDBGMOD ppDbgMod, PKRDR pRdr, KBOOL fCloseRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
+{
+ /*
+ * If the reader isn't buffered create a buffered wrapper for it.
+ */
+ int rc;
+ PKRDR pRdrWrapped = NULL;
+ if (!kRdrBufIsBuffered(pRdr))
+ {
+ rc = kRdrBufWrap(&pRdrWrapped, pRdr, fCloseRdr);
+ if (rc)
+ {
+ if (fCloseRdr)
+ kRdrClose(pRdr);
+ return rc;
+ }
+ pRdr = pRdrWrapped;
+ }
+
+ /*
+ * Walk the built-in table and the list of registered readers
+ * and let each of them have a go at the file. Stop and return
+ * on the first one returning successfully.
+ */
+ rc = KDBG_ERR_UNKOWN_FORMAT;
+ for (KSIZE i = 0; i < K_ELEMENTS(g_aBuiltIns); i++)
+ if (g_aBuiltIns[i]->pfnOpen)
+ {
+ int rc2 = g_aBuiltIns[i]->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod);
+ if (!rc2)
+ return 0;
+ if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT)
+ rc = rc2;
+ }
+
+ for (PKDBGMODOPS pCur = g_pHead; pCur; pCur = pCur->pNext)
+ if (pCur->pfnOpen)
+ {
+ int rc2 = pCur->pfnOpen(ppDbgMod, pRdr, fCloseRdr, off, cb, pLdrMod);
+ if (!rc2)
+ return 0;
+ if (rc2 != KDBG_ERR_UNKOWN_FORMAT && rc == KDBG_ERR_UNKOWN_FORMAT)
+ rc = rc2;
+ }
+
+ if (pRdrWrapped)
+ kRdrClose(pRdrWrapped);
+ else if (fCloseRdr)
+ kRdrClose(pRdr);
+ return rc;
+}
+
+
+/**
+ * Opens a debug module reader for the specified file or file section
+ *
+ * @returns kStuff status code.
+ * @param ppDbgMod Where to store the debug module reader handle.
+ * @param pRdr The file reader.
+ * @param off The offset of the file section. If the entire file, pass 0.
+ * @param cb The size of the file section. If the entire file, pass KFOFF_MAX.
+ * @param pLdrMod Associated kLdr module that the kDbg component can use to
+ * verify and suplement the debug info found in the file specified
+ * by pszFilename. The module will be used by kDbg for as long as
+ * the returned kDbg module remains open.
+ * This is an optional parameter, pass NULL if no kLdr module at hand.
+ */
+KDBG_DECL(int) kDbgModuleOpenFilePart(PPKDBGMOD ppDbgMod, PKRDR pRdr, KFOFF off, KFOFF cb, struct KLDRMOD *pLdrMod)
+{
+ /*
+ * Validate input.
+ */
+ kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pRdr, KERR_INVALID_POINTER);
+ kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER);
+ kDbgAssertMsgReturn(off >= 0 && off < KFOFF_MAX, (KFOFF_PRI "\n", off), KERR_INVALID_OFFSET);
+ kDbgAssertMsgReturn(cb >= 0 && cb <= KFOFF_MAX, (KFOFF_PRI "\n", cb), KERR_INVALID_SIZE);
+ kDbgAssertMsgReturn(off + cb > off, ("off=" KFOFF_PRI " cb=" KFOFF_PRI "\n", off, cb), KERR_INVALID_RANGE);
+ *ppDbgMod = NULL;
+
+ /*
+ * Hand it over to the internal worker.
+ */
+ return kdbgModuleOpenWorker(ppDbgMod, pRdr, K_FALSE /* fCloseRdr */, off, cb, pLdrMod);
+}
+
+
+/**
+ * Opens a debug module reader for the specified file.
+ *
+ * @returns kStuff status code.
+ * @param ppDbgMod Where to store the debug module reader handle.
+ * @param pRdr The file reader.
+ * @param pLdrMod Associated kLdr module that the kDbg component can use to
+ * verify and suplement the debug info found in the file specified
+ * by pszFilename. The module will be used by kDbg for as long as
+ * the returned kDbg module remains open.
+ * This is an optional parameter, pass NULL if no kLdr module at hand.
+ */
+KDBG_DECL(int) kDbgModuleOpenFile(PPKDBGMOD ppDbgMod, PKRDR pRdr, struct KLDRMOD *pLdrMod)
+{
+ return kDbgModuleOpenFilePart(ppDbgMod, pRdr, 0, KFOFF_MAX, pLdrMod);
+}
+
+
+/**
+ * Opens the debug info for a specified executable module.
+ *
+ * @returns kStuff status code.
+ * @param ppDbgMod Where to store the debug module handle.
+ * @param pszFilename The name of the file containing debug info and/or which
+ * debug info is wanted.
+ * @param pLdrMod Associated kLdr module that the kDbg component can use to
+ * verify and suplement the debug info found in the file specified
+ * by pszFilename. The module will be used by kDbg for as long as
+ * the returned kDbg module remains open.
+ * This is an optional parameter, pass NULL if no kLdr module at hand.
+ */
+KDBG_DECL(int) kDbgModuleOpen(PPKDBGMOD ppDbgMod, const char *pszFilename, struct KLDRMOD *pLdrMod)
+{
+ /*
+ * Validate input.
+ */
+ kDbgAssertPtrReturn(ppDbgMod, KERR_INVALID_POINTER);
+ kDbgAssertPtrReturn(pszFilename, KERR_INVALID_POINTER);
+ kDbgAssertMsgReturn(*pszFilename, ("%p\n", pszFilename), KERR_INVALID_PARAMETER);
+ kDbgAssertPtrNullReturn(pLdrMod, KERR_INVALID_POINTER);
+ *ppDbgMod = NULL;
+
+ /*
+ * Open the file and see if we can read it.
+ */
+ PKRDR pRdr;
+ int rc = kRdrBufOpen(&pRdr, pszFilename);
+ if (rc)
+ return rc;
+ rc = kdbgModuleOpenWorker(ppDbgMod, pRdr, K_TRUE /* fCloseRdr */, 0, KFOFF_MAX, pLdrMod);
+ return rc;
+}
+
+
+/**
+ * Closes the module.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module handle.
+ */
+KDBG_DECL(int) kDbgModuleClose(PKDBGMOD pMod)
+{
+ KDBGMOD_VALIDATE(pMod);
+ int rc = pMod->pOps->pfnClose(pMod);
+ if (!rc)
+ {
+ pMod->u32Magic++;
+ kHlpFree(pMod);
+ }
+ return rc;
+}
+
+
+/**
+ * Gets a symbol by segment:offset.
+ * This will be approximated to the nearest symbol if there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module.
+ * @param iSegment The segment this offset is relative to.
+ * The -1 segment is special, it means that the addres is relative to
+ * the image base. The image base is where the first bit of the image
+ * is mapped during load.
+ * @param off The offset into the segment.
+ * @param pSym Where to store the symbol details.
+ */
+KDBG_DECL(int) kDbgModuleQuerySymbol(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGSYMBOL pSym)
+{
+ KDBGMOD_VALIDATE(pMod);
+ kDbgAssertPtrReturn(pSym, KERR_INVALID_POINTER);
+ return pMod->pOps->pfnQuerySymbol(pMod, iSegment, off, pSym);
+}
+
+
+/**
+ * Gets & allocates a symbol by segment:offset.
+ * This will be approximated to the nearest symbol if there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module.
+ * @param iSegment The segment this offset is relative to.
+ * The -1 segment is special, it means that the addres is relative to
+ * the image base. The image base is where the first bit of the image
+ * is mapped during load.
+ * @param off The offset into the segment.
+ * @param ppSym Where to store the pointer to the symbol info.
+ * Free the returned symbol using kDbgSymbolFree().
+ */
+KDBG_DECL(int) kDbgModuleQuerySymbolA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGSYMBOL ppSym)
+{
+ kDbgAssertPtrReturn(ppSym, KERR_INVALID_POINTER);
+
+ KDBGSYMBOL Sym;
+ int rc = kDbgModuleQuerySymbol(pMod, iSegment, off, &Sym);
+ if (!rc)
+ {
+ *ppSym = kDbgSymbolDup(&Sym);
+ if (!*ppSym)
+ rc = KERR_NO_MEMORY;
+ }
+ else
+ *ppSym = NULL;
+ return rc;
+}
+
+
+/**
+ * Gets a line number entry by segment:offset.
+ * This will be approximated to the nearest line number there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module.
+ * @param iSegment The segment this offset is relative to.
+ * The -1 segment is special, it means that the addres is relative to
+ * the image base. The image base is where the first bit of the image
+ * is mapped during load.
+ * @param off The offset into the segment.
+ * @param pLine Where to store the line number details.
+ */
+KDBG_DECL(int) kDbgModuleQueryLine(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PKDBGLINE pLine)
+{
+ KDBGMOD_VALIDATE(pMod);
+ kDbgAssertPtrReturn(pLine, KERR_INVALID_POINTER);
+ return pMod->pOps->pfnQueryLine(pMod, iSegment, off, pLine);
+}
+
+
+/**
+ * Gets & allocates a line number entry by segment:offset.
+ * This will be approximated to the nearest line number there is no exact match.
+ *
+ * @returns IPRT status code.
+ * @param pMod The module.
+ * @param iSegment The segment this offset is relative to.
+ * The -1 segment is special, it means that the addres is relative to
+ * the image base. The image base is where the first bit of the image
+ * is mapped during load.
+ * @param off The offset into the segment.
+ * @param ppLine Where to store the pointer to the line number info.
+ * Free the returned line number using kDbgLineFree().
+ */
+KDBG_DECL(int) kDbgModuleQueryLineA(PKDBGMOD pMod, KI32 iSegment, KDBGADDR off, PPKDBGLINE ppLine)
+{
+ kDbgAssertPtrReturn(ppLine, KERR_INVALID_POINTER);
+
+ KDBGLINE Line;
+ int rc = kDbgModuleQueryLine(pMod, iSegment, off, &Line);
+ if (!rc)
+ {
+ *ppLine = kDbgLineDup(&Line);
+ if (!*ppLine)
+ rc = KERR_NO_MEMORY;
+ }
+ else
+ *ppLine = NULL;
+ return rc;
+}
+
diff --git a/src/lib/kStuff/kDbg/kDbgSpace.cpp b/src/lib/kStuff/kDbg/kDbgSpace.cpp
new file mode 100644
index 0000000..2d6f1c0
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgSpace.cpp
@@ -0,0 +1,192 @@
+/* $Id: kDbgSpace.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, Address Space Manager.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+#include <k/kHlpString.h>
+#include <k/kAvl.h>
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** Pointer to a name space module. */
+typedef struct KDBGSPACEMOD *PKDBGSPACEMOD;
+
+/**
+ * Tracks a module segment in the address space.
+ *
+ * These segments are organized in two trees, by address in the
+ * KDBGSPACE::pSegRoot tree and by selector value in the
+ * KDBGSPACE::pSegSelRoot tree.
+ *
+ * While the debug module reader could easily provide us with
+ * segment names and it could perhaps be interesting to lookup
+ * a segment by its name in some situations, this has been
+ * considered too much bother for now. :-)
+ */
+typedef struct KDBGSPACESEG
+{
+ /** The module segment index. */
+ KI32 iSegment;
+ /** The address space module structure this segment belongs to. */
+ PKDBGSPACEMOD pSpaceMod;
+} KDBGSPACESEG;
+typedef KDBGSPACESEG *PKDBGSPACESEG;
+
+
+/**
+ * Track a module in the name space.
+ *
+ * Each module in the address space can be addressed efficiently
+ * by module name. The module name has to be unique.
+ */
+typedef struct KDBGSPACEMOD
+{
+ /** The module name hash. */
+ KU32 u32Hash;
+ /** The length of the module name. */
+ KU32 cchName;
+ /** The module name. */
+ char *pszName;
+ /** The next module in the same bucket. */
+ PKDBGSPACEMOD pNext;
+ /** Pointer to the debug module reader. */
+ PKDBGMOD pMod;
+ /** The number of segments. */
+ KU32 cSegs;
+ /** The segment array. (variable length) */
+ KDBGSPACESEG aSegs[1];
+} KDBGSPACEMOD;
+
+
+typedef struct KDBGCACHEDSYM *PKDBGCACHEDSYM;
+/**
+ * A cached symbol.
+ */
+typedef struct KDBGCACHEDSYM
+{
+ /** The symbol name hash. */
+ KU32 u32Hash;
+ /** The next symbol in the same bucket. */
+ PKDBGCACHEDSYM pNext;
+ /** The next symbol belonging to the same module as this. */
+ PKDBGCACHEDSYM pNextMod;
+ /** The cached symbol information. */
+ KDBGSYMBOL Sym;
+} KDBGCACHEDSYM;
+
+
+/**
+ * A symbol cache.
+ */
+typedef struct KDBGSYMCACHE
+{
+ /** The symbol cache magic. (KDBGSYMCACHE_MAGIC) */
+ KU32 u32Magic;
+ /** The maximum number of symbols.*/
+ KU32 cMax;
+ /** The current number of symbols.*/
+ KU32 cCur;
+ /** The number of hash buckets. */
+ KU32 cBuckets;
+ /** The address lookup tree. */
+ PKDBGADDRAVL pAddrTree;
+ /** Array of hash buckets.
+ * The size is selected according to the cache size. */
+ PKDBGCACHEDSYM *paBuckets[1];
+} KDBGSYMCACHE;
+typedef KDBGSYMCACHE *PKDBGSYMCACHE;
+
+
+/**
+ * A user symbol record.
+ *
+ * The user symbols are organized in the KDBGSPACE::pUserRoot tree
+ * and form an overlay that overrides the debug info retrieved from
+ * the KDBGSPACE::pSegRoot tree.
+ *
+ * In the current implementation the user symbols are unique and
+ * one would have to first delete a symbol in order to add another
+ * at the same address. This may be changed later, perhaps.
+ */
+typedef struct KDBGSPACEUSERSYM
+{
+
+} KDBGSPACEUSERSYM;
+typedef KDBGSPACEUSERSYM *PKDBGSPACEUSERSYM;
+
+
+
+/**
+ * Address space.
+ */
+typedef struct KDBGSPACE
+{
+ /** The addresspace magic. (KDBGSPACE_MAGIC) */
+ KU32 u32Magic;
+ /** User defined address space identifier or data pointer. */
+ KUPTR uUser;
+ /** The name of the address space. (Optional) */
+ const char *pszName;
+
+
+} KDBGSPACE;
+/** Pointer to an address space. */
+typedef struct KDBGSPACE *PKDBGSPACE;
+/** Pointer to an address space pointer. */
+typedef PKDBGSPACE *PPKDBGSPACE;
+
+
+KDBG_DECL(int) kDbgSpaceCreate(PPDBGSPACE ppSpace, KDBGADDR LowAddr, DBGADDR HighAddr,
+ KUPTR uUser, const char *pszName)
+{
+ /*
+ * Validate input.
+ */
+ kDbgAssertPtrReturn(ppSpace);
+ *ppSpace = NULL;
+ kDbgAssertPtrNullReturn(pszName);
+ kDbgAssertReturn(LowAddr < HighAddr);
+
+ /*
+ * Create and initialize the address space.
+ */
+ PKDBGSPACE pSpace = (PKDBGSPACE)kHlpAlloc(sizeof(*pSpace));
+ if (!pSpace)
+ return KERR_NO_MEMORY;
+ pSpace->u32Magic = KDBGSPACE_MAGIC;
+ pSpace->uUser = uUser;
+ pSpace->pszName = pszName;
+
+}
diff --git a/src/lib/kStuff/kDbg/kDbgSymbol.cpp b/src/lib/kStuff/kDbg/kDbgSymbol.cpp
new file mode 100644
index 0000000..d542807
--- /dev/null
+++ b/src/lib/kStuff/kDbg/kDbgSymbol.cpp
@@ -0,0 +1,78 @@
+/* $Id: kDbgSymbol.cpp 29 2009-07-01 20:30:29Z bird $ */
+/** @file
+ * kDbg - The Debug Info Reader, Symbols.
+ */
+
+/*
+ * Copyright (c) 2006-2007 Knut St. Osmundsen <bird-kStuff-spamix@anduin.net>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "kDbgInternal.h"
+#include <k/kHlpAlloc.h>
+
+
+/**
+ * Duplicates a symbol.
+ *
+ * To save heap space, the returned symbol will not own more heap space than
+ * it strictly need to. So, it's not possible to append stuff to the symbol
+ * or anything of that kind.
+ *
+ * @returns Pointer to the duplicate.
+ * This must be freed using kDbgSymbolFree().
+ * @param pSymbol The symbol to be duplicated.
+ */
+KDBG_DECL(PKDBGSYMBOL) kDbgSymbolDup(PCKDBGSYMBOL pSymbol)
+{
+ kDbgAssertPtrReturn(pSymbol, NULL);
+ KSIZE cb = K_OFFSETOF(KDBGSYMBOL, szName[pSymbol->cchName + 1]);
+ PKDBGSYMBOL pNewSymbol = (PKDBGSYMBOL)kHlpDup(pSymbol, cb);
+ if (pNewSymbol)
+ pNewSymbol->cbSelf = cb;
+ return pNewSymbol;
+}
+
+
+/**
+ * Frees a symbol obtained from the kDbg API.
+ *
+ * @returns 0 on success.
+ * @returns KERR_INVALID_POINTER if pSymbol isn't a valid pointer.
+ *
+ * @param pSymbol The symbol to be freed. The null pointer is ignored.
+ */
+KDBG_DECL(int) kDbgSymbolFree(PKDBGSYMBOL pSymbol)
+{
+ if (!pSymbol)
+ {
+ kDbgAssertPtrReturn(pSymbol, KERR_INVALID_POINTER);
+ pSymbol->cbSelf = 0;
+ kHlpFree(pSymbol);
+ }
+ return 0;
+}
+