CVS: winex/dlls/dbghelp coff.c, NONE, 1.1 dbghelp.c, 1.4, 1.5 dbghelp.spec, 1.4, 1.5 dbghelp_private.h, NONE, 1.1 dwarf.c, NONE, 1.1 dwarf.h, NONE, 1.1 elf_module.c, NONE, 1.1 image.c, NONE, 1.1 Makefile.in, 1.1, 1.2 memory.c, NONE, 1.1 minidump.c, NONE, 1.1 module.c, NONE, 1.1 msc.c, NONE, 1.1 path.c, NONE, 1.1 pe_module.c, NONE, 1.1 source.c, NONE, 1.1 stabs.c, NONE, 1.1 stack.c, NONE, 1.1 storage.c, NONE, 1.1 symbol.c, NONE, 1.1 type.c, NONE, 1.1 wdbgexts.h, NONE, 1.1

[email protected] 30 Aug 2007 14:16:01 -0000
Newsgroups gmane.comp.emulators.winex.cvs
Message-ID <[email protected]>
Subject: winex/dlls/dbghelp coff.c,NONE,1.1 dbghelp.c,1.4,1.5 dbghelp.spec,1.4,1.5 dbghelp_private.h,NONE,1.1 dwarf.c,NONE,1.1 dwarf.h,NONE,1.1 elf_module.c,NONE,1.1 image.c,NONE,1.1 Makefile.in,1.1,1.2 memory.c,NONE,1.1 minidump.c,NONE,1.1 module.c,NONE,1.1 msc.c,NONE,1.1 path.c,NONE,1.1 pe_module.c,NONE,1.1 source.c,NONE,1.1 stabs.c,NONE,1.1 stack.c,NONE,1.1 storage.c,NONE,1.1 symbol.c,NONE,1.1 type.c,NONE,1.1 wdbgexts.h,NONE,1.1Update of /var/lib/cvsd/cvsroot/winex/dlls/dbghelp
In directory agravaine:/tmp/cvs-serv18353/dlls/dbghelp

Modified Files:
	dbghelp.c dbghelp.spec Makefile.in 
Added Files:
	coff.c dbghelp_private.h dwarf.c dwarf.h elf_module.c image.c 
	memory.c minidump.c module.c msc.c path.c pe_module.c source.c 
	stabs.c stack.c storage.c symbol.c type.c wdbgexts.h 
Log Message:

- importing the initial version of dbghelp from winehq 0.9.41.  This version will not build at the moment... build fixes coming in a few moments.


--- NEW FILE: coff.c ---
/*
 * Read VC++ debug information from COFF and eventually
 * from PDB files.
 *
 * Copyright (C) 1996,      Eric Youngdale.
 * Copyright (C) 1999-2000, Ulrich Weigand.
 * Copyright (C) 2004,      Eric Pouech.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

/*
 * Note - this handles reading debug information for 32 bit applications
 * that run under Windows-NT for example.  I doubt that this would work well
 * for 16 bit applications, but I don't think it really matters since the
 * file format is different, and we should never get in here in such cases.
 *
 * TODO:
 *	Get 16 bit CV stuff working.
 *	Add symbol size to internal symbol table.
 */

#include "config.h"
#include "wine/port.h"

#include <assert.h>
#include <stdlib.h>

#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winternl.h"

#include "wine/exception.h"
#include "wine/debug.h"
#include "dbghelp_private.h"
#include "wine/mscvpdb.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_coff);

/*========================================================================
 * Process COFF debug information.
 */

struct CoffFile
{
    unsigned int                startaddr;
    unsigned int                endaddr;
    struct symt_compiland*      compiland;
    int                         linetab_offset;
    int                         linecnt;
    struct symt**               entries;
    int		                neps;
    int		                neps_alloc;
};

struct CoffFileSet
{
    struct CoffFile*    files;
    int		        nfiles;
    int		        nfiles_alloc;
};

static const char*	coff_get_name(const IMAGE_SYMBOL* coff_sym, 
                                      const char* coff_strtab)
{
    static	char	namebuff[9];
    const char*		nampnt;

    if (coff_sym->N.Name.Short)
    {
        memcpy(namebuff, coff_sym->N.ShortName, 8);
        namebuff[8] = '\0';
        nampnt = &namebuff[0];
    }
    else
    {
        nampnt = coff_strtab + coff_sym->N.Name.Long;
    }

    if (nampnt[0] == '_') nampnt++;
    return nampnt;
}

static int coff_add_file(struct CoffFileSet* coff_files, struct module* module,
                         const char* filename)
{
    struct CoffFile* file;

    if (coff_files->nfiles + 1 >= coff_files->nfiles_alloc)
    {
	coff_files->nfiles_alloc += 10;
        coff_files->files = (coff_files->files) ?
            HeapReAlloc(GetProcessHeap(), 0, coff_files->files,
                        coff_files->nfiles_alloc * sizeof(struct CoffFile)) :
            HeapAlloc(GetProcessHeap(), 0,
                      coff_files->nfiles_alloc * sizeof(struct CoffFile));
    }
    file = coff_files->files + coff_files->nfiles;
    file->startaddr = 0xffffffff;
    file->endaddr   = 0;
    file->compiland = symt_new_compiland(module, 0,
                                         source_new(module, NULL, filename));
    file->linetab_offset = -1;
    file->linecnt = 0;
    file->entries = NULL;
    file->neps = file->neps_alloc = 0;

    return coff_files->nfiles++;
}

static void coff_add_symbol(struct CoffFile* coff_file, struct symt* sym)
{
    if (coff_file->neps + 1 >= coff_file->neps_alloc)
    {
        coff_file->neps_alloc += 10;
        coff_file->entries = (coff_file->entries) ?
            HeapReAlloc(GetProcessHeap(), 0, coff_file->entries,
                        coff_file->neps_alloc * sizeof(struct symt*)) :
            HeapAlloc(GetProcessHeap(), 0, 
                      coff_file->neps_alloc * sizeof(struct symt*));
    }
    coff_file->entries[coff_file->neps++] = sym;
}

BOOL coff_process_info(const struct msc_debug_info* msc_dbg)
{
    const IMAGE_AUX_SYMBOL*		aux;
    const IMAGE_COFF_SYMBOLS_HEADER*	coff;
    const IMAGE_LINENUMBER*		coff_linetab;
    const IMAGE_LINENUMBER*		linepnt;
    const char*                         coff_strtab;
    const IMAGE_SYMBOL* 		coff_sym;
    const IMAGE_SYMBOL* 		coff_symbols;
    struct CoffFileSet	                coff_files;
    int				        curr_file_idx = -1;
    unsigned int		        i;
    int			       	        j;
    int			       	        k;
    int			       	        l;
    int		       		        linetab_indx;
    const char*                         nampnt;
    int		       		        naux;
    BOOL                                ret = FALSE;
    DWORD                               addr;

    TRACE("Processing COFF symbols...\n");

    assert(sizeof(IMAGE_SYMBOL) == IMAGE_SIZEOF_SYMBOL);
    assert(sizeof(IMAGE_LINENUMBER) == IMAGE_SIZEOF_LINENUMBER);

    coff_files.files = NULL;
    coff_files.nfiles = coff_files.nfiles_alloc = 0;

    coff = (const IMAGE_COFF_SYMBOLS_HEADER*)msc_dbg->root;

    coff_symbols = (const IMAGE_SYMBOL*)((const char *)coff + coff->LvaToFirstSymbol);
    coff_linetab = (const IMAGE_LINENUMBER*)((const char *)coff + coff->LvaToFirstLinenumber);
    coff_strtab = (const char*)(coff_symbols + coff->NumberOfSymbols);

    linetab_indx = 0;

    for (i = 0; i < coff->NumberOfSymbols; i++)
    {
        coff_sym = coff_symbols + i;
        naux = coff_sym->NumberOfAuxSymbols;

        if (coff_sym->StorageClass == IMAGE_SYM_CLASS_FILE)
	{
            curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, 
                                          (const char*)(coff_sym + 1));
            TRACE("New file %s\n", (const char*)(coff_sym + 1));
            i += naux;
            continue;
	}

        if (curr_file_idx < 0)
        {
            assert(coff_files.nfiles == 0 && coff_files.nfiles_alloc == 0);
            curr_file_idx = coff_add_file(&coff_files, msc_dbg->module, "<none>");
            TRACE("New file <none>\n");
        }

        /*
         * This guy marks the size and location of the text section
         * for the current file.  We need to keep track of this so
         * we can figure out what file the different global functions
         * go with.
         */
        if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC &&
            naux != 0 && coff_sym->Type == 0 && coff_sym->SectionNumber == 1)
	{
            aux = (const IMAGE_AUX_SYMBOL*) (coff_sym + 1);

            if (coff_files.files[curr_file_idx].linetab_offset != -1)
	    {
                /*
                 * Save this so we can still get the old name.
                 */
                const char* fn;

                fn = source_get(msc_dbg->module,
                                coff_files.files[curr_file_idx].compiland->source);

                TRACE("Duplicating sect from %s: %x %x %x %d %d\n",
                      fn, aux->Section.Length,
                      aux->Section.NumberOfRelocations,
                      aux->Section.NumberOfLinenumbers,
                      aux->Section.Number, aux->Section.Selection);
                TRACE("More sect %d %s %08x %d %d %d\n",
                      coff_sym->SectionNumber,
                      coff_get_name(coff_sym, coff_strtab),
                      coff_sym->Value, coff_sym->Type,
                      coff_sym->StorageClass, coff_sym->NumberOfAuxSymbols);

                /*
                 * Duplicate the file entry.  We have no way to describe
                 * multiple text sections in our current way of handling things.
                 */
                coff_add_file(&coff_files, msc_dbg->module, fn);
	    }
            else
	    {
                TRACE("New text sect from %s: %x %x %x %d %d\n",
                      source_get(msc_dbg->module, coff_files.files[curr_file_idx].compiland->source),
                      aux->Section.Length,
                      aux->Section.NumberOfRelocations,
                      aux->Section.NumberOfLinenumbers,
                      aux->Section.Number, aux->Section.Selection);
	    }

            if (coff_files.files[curr_file_idx].startaddr > coff_sym->Value)
	    {
                coff_files.files[curr_file_idx].startaddr = coff_sym->Value;
	    }

            if (coff_files.files[curr_file_idx].endaddr < coff_sym->Value + aux->Section.Length)
	    {
                coff_files.files[curr_file_idx].endaddr = coff_sym->Value + aux->Section.Length;
	    }

            coff_files.files[curr_file_idx].linetab_offset = linetab_indx;
            coff_files.files[curr_file_idx].linecnt = aux->Section.NumberOfLinenumbers;
            linetab_indx += aux->Section.NumberOfLinenumbers;
            i += naux;
            continue;
	}

        if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0 && 
            coff_sym->SectionNumber == 1)
	{
            DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
            /*
             * This is a normal static function when naux == 0.
             * Just register it.  The current file is the correct
             * one in this instance.
             */
            nampnt = coff_get_name(coff_sym, coff_strtab);

            TRACE("\tAdding static symbol %s\n", nampnt);

            /* FIXME: was adding symbol to this_file ??? */
            coff_add_symbol(&coff_files.files[curr_file_idx],
                            &symt_new_function(msc_dbg->module, 
                                               coff_files.files[curr_file_idx].compiland, 
                                               nampnt,
                                               msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
                                               0 /* FIXME */,
                                               NULL /* FIXME */)->symt);
            i += naux;
            continue;
	}

        if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
            ISFCN(coff_sym->Type) && coff_sym->SectionNumber > 0)
	{
            struct symt_compiland* compiland = NULL;
            DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
            nampnt = coff_get_name(coff_sym, coff_strtab);

            TRACE("%d: %s %s\n",
                  i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
                  nampnt);
            TRACE("\tAdding global symbol %s (sect=%s)\n",
                  nampnt, msc_dbg->sectp[coff_sym->SectionNumber - 1].Name);

            /*
             * Now we need to figure out which file this guy belongs to.
             */
            for (j = 0; j < coff_files.nfiles; j++)
	    {
                if (coff_files.files[j].startaddr <= base + coff_sym->Value
                     && coff_files.files[j].endaddr > base + coff_sym->Value)
		{
                    compiland = coff_files.files[j].compiland;
                    break;
		}
	    }
            if (j < coff_files.nfiles)
            {
                coff_add_symbol(&coff_files.files[j],
                                &symt_new_function(msc_dbg->module, compiland, nampnt, 
                                                   msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
                                                   0 /* FIXME */, NULL /* FIXME */)->symt);
            } 
            else 
            {
                symt_new_function(msc_dbg->module, NULL, nampnt, 
                                  msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
                                  0 /* FIXME */, NULL /* FIXME */);
            }
            i += naux;
            continue;
	}

        if (coff_sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL &&
            coff_sym->SectionNumber > 0)
	{
            DWORD base = msc_dbg->sectp[coff_sym->SectionNumber - 1].VirtualAddress;
            /*
             * Similar to above, but for the case of data symbols.
             * These aren't treated as entrypoints.
             */
            nampnt = coff_get_name(coff_sym, coff_strtab);

            TRACE("%d: %s %s\n",
                  i, wine_dbgstr_longlong(msc_dbg->module->module.BaseOfImage + base + coff_sym->Value),
                  nampnt);
            TRACE("\tAdding global data symbol %s\n", nampnt);

            /*
             * Now we need to figure out which file this guy belongs to.
             */
            symt_new_global_variable(msc_dbg->module, NULL, nampnt, TRUE /* FIXME */,
                                     msc_dbg->module->module.BaseOfImage + base + coff_sym->Value,
                                     0 /* FIXME */, NULL /* FIXME */);
            i += naux;
            continue;
	}

        if (coff_sym->StorageClass == IMAGE_SYM_CLASS_STATIC && naux == 0)
	{
            /*
             * Ignore these.  They don't have anything to do with
             * reality.
             */
            i += naux;
            continue;
	}

        TRACE("Skipping unknown entry '%s' %d %d %d\n",
              coff_get_name(coff_sym, coff_strtab),
              coff_sym->StorageClass, coff_sym->SectionNumber, naux);
        
        /*
         * For now, skip past the aux entries.
         */
        i += naux;
    }

    if (coff_files.files != NULL)
    {
        /*
         * OK, we now should have a list of files, and we should have a list
         * of entrypoints.  We need to sort the entrypoints so that we are
         * able to tie the line numbers with the given functions within the
         * file.
         */
        for (j = 0; j < coff_files.nfiles; j++)
        {
            if (coff_files.files[j].entries != NULL)
            {
                qsort(coff_files.files[j].entries, coff_files.files[j].neps,
                      sizeof(struct symt*), symt_cmp_addr);
            }
        }

        /*
         * Now pick apart the line number tables, and attach the entries
         * to the given functions.
         */
        for (j = 0; j < coff_files.nfiles; j++)
        {
            l = 0;
            if (coff_files.files[j].neps != 0)
            {
                for (k = 0; k < coff_files.files[j].linecnt; k++)
                {
                    linepnt = coff_linetab + coff_files.files[j].linetab_offset + k;
                    /*
                     * If we have spilled onto the next entrypoint, then
                     * bump the counter..
                     */
                    for (;;)
                    {
                        if (l+1 >= coff_files.files[j].neps) break;
                        symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
                        if (((msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress) < addr))
                            break;
                        l++;
                    }

                    if (coff_files.files[j].entries[l+1]->tag == SymTagFunction)
                    {
                        /*
                         * Add the line number.  This is always relative to the
                         * start of the function, so we need to subtract that offset
                         * first.
                         */
                        symt_get_info(coff_files.files[j].entries[l+1], TI_GET_ADDRESS, &addr);
                        symt_add_func_line(msc_dbg->module, (struct symt_function*)coff_files.files[j].entries[l+1], 
                                           coff_files.files[j].compiland->source, linepnt->Linenumber,
                                           msc_dbg->module->module.BaseOfImage + linepnt->Type.VirtualAddress - addr);
                    }
                }
            }
        }

        for (j = 0; j < coff_files.nfiles; j++)
	{
            HeapFree(GetProcessHeap(), 0, coff_files.files[j].entries);
	}
        HeapFree(GetProcessHeap(), 0, coff_files.files);
        msc_dbg->module->module.SymType = SymCoff;
        /* FIXME: we could have a finer grain here */
        msc_dbg->module->module.LineNumbers = TRUE;
        msc_dbg->module->module.GlobalSymbols = TRUE;
        msc_dbg->module->module.TypeInfo = FALSE;
        msc_dbg->module->module.SourceIndexed = TRUE;
        msc_dbg->module->module.Publics = TRUE;
        ret = TRUE;
    }

    return ret;
}

Index: dbghelp.c
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/dbghelp/dbghelp.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbghelp.c	31 Jul 2007 19:50:48 -0000	1.4
+++ dbghelp.c	30 Aug 2007 14:15:59 -0000	1.5
@@ -1,44 +1,636 @@
+/*
+ * File dbghelp.c - generic routines (process) for dbghelp DLL
+ *
+ * Copyright (C) 2004, Eric Pouech
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
 #include "config.h"
+
+#include "dbghelp_private.h"
+#include "winerror.h"
+#include "psapi.h"
 #include "wine/debug.h"
-#include "winternl.h"
+#include "wdbgexts.h"
+#include "winnls.h"
 
+WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
 
-WINE_DEFAULT_DEBUG_CHANNEL (dbghelp);
+/* TODO
+ *  - support for symbols' types is still partly missing
+ *      + C++ support
+ *      + we should store the underlying type for an enum in the symt_enum struct
+ *      + for enums, we store the names & values (associated to the enum type), 
+ *        but those values are not directly usable from a debugger (that's why, I
+ *        assume, that we have also to define constants for enum values, as 
+ *        Codeview does BTW.
+ *      + SymEnumTypes should only return *user* defined types (UDT, typedefs...) not
+ *        all the types stored/used in the modules (like char*)
+ *  - SymGetLine{Next|Prev} don't work as expected (they don't seem to work across
+ *    functions, and even across function blocks...). Basically, for *Next* to work
+ *    it requires an address after the prolog of the func (the base address of the 
+ *    func doesn't work)
+ *  - most options (dbghelp_options) are not used (loading lines...)
+ *  - in symbol lookup by name, we don't use RE everywhere we should. Moreover, when
+ *    we're supposed to use RE, it doesn't make use of our hash tables. Therefore,
+ *    we could use hash if name isn't a RE, and fall back to a full search when we
+ *    get a full RE
+ *  - msc:
+ *      + we should add parameters' types to the function's signature
+ *        while processing a function's parameters
+ *      + add support for function-less labels (as MSC seems to define them)
+ *      + C++ management
+ *  - stabs: 
+ *      + when, in a same module, the same definition is used in several compilation
+ *        units, we get several definitions of the same object (especially 
+ *        struct/union). we should find a way not to duplicate them
+ *      + in some cases (dlls/user/dialog16.c DIALOG_GetControl16), the same static
+ *        global variable is defined several times (at different scopes). We are
+ *        getting several of those while looking for a unique symbol. Part of the 
+ *        issue is that we don't give a scope to a static variable inside a function
+ *      + C++ management
+ */
 
+unsigned   dbghelp_options = SYMOPT_UNDNAME;
+HANDLE     hMsvcrt = NULL;
 
-typedef BOOL (CALLBACK *PENUMLOADED_MODULES_CALLBACK) (PSTR, ULONG, ULONG,
-                                                       PVOID);
+/***********************************************************************
+ *           DllMain (DEBUGHLP.@)
+ */
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+    switch (fdwReason)
+    {
+    case DLL_PROCESS_ATTACH:    break;
+    case DLL_PROCESS_DETACH:
+        if (hMsvcrt) FreeLibrary(hMsvcrt);
+        break;
+    case DLL_THREAD_ATTACH:     break;
+    case DLL_THREAD_DETACH:     break;
+    default:                    break;
+    }
+    return TRUE;
+}
 
+static struct process* process_first /* = NULL */;
 
-BOOL WINAPI EnumerateLoadedModules (HANDLE hProcess,
-                                    PENUMLOADED_MODULES_CALLBACK pFunc,
-                                    PVOID pData)
+/******************************************************************
+ *		process_find_by_handle
+ *
+ */
+struct process*    process_find_by_handle(HANDLE hProcess)
 {
-   FIXME ("(%p, %p, %p): stub!\n", (void *)hProcess, pFunc, pData);
-   return FALSE;
+    struct process* p;
+
+    for (p = process_first; p && p->handle != hProcess; p = p->next);
+    if (!p) SetLastError(ERROR_INVALID_HANDLE);
+    return p;
 }
 
-BOOL WINAPI SymInitialize(HANDLE hProcess,
-                          LPCSTR UserSearchPath,
-                          BOOL fInvadeProcess)
+/******************************************************************
+ *             validate_addr64 (internal)
+ *
+ */
+BOOL validate_addr64(DWORD64 addr)
 {
-    FIXME("stub! {hProcess = %p, UserSearchPath = %p, fInvadeProcess = %s}\n", (void *)hProcess, UserSearchPath, fInvadeProcess ? "TRUE" : "FALSE");
+    if (addr >> 32)
+    {
+        FIXME("Unsupported address %s\n", wine_dbgstr_longlong(addr));
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
     return TRUE;
 }
 
-BOOL WINAPI SymCleanup(HANDLE hProcess){
-    FIXME("stub! {hProcess = %p}\n", (void *)hProcess);
+/******************************************************************
+ *		fetch_buffer
+ *
+ * Ensures process' internal buffer is large enough.
+ */
+void* fetch_buffer(struct process* pcs, unsigned size)
+{
+    if (size > pcs->buffer_size)
+    {
+        if (pcs->buffer)
+            pcs->buffer = HeapReAlloc(GetProcessHeap(), 0, pcs->buffer, size);
+        else
+            pcs->buffer = HeapAlloc(GetProcessHeap(), 0, size);
+        pcs->buffer_size = (pcs->buffer) ? size : 0;
+    }
+    return pcs->buffer;
+}
+
+/******************************************************************
+ *		SymSetSearchPathW (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymSetSearchPathW(HANDLE hProcess, PCWSTR searchPath)
+{
+    struct process* pcs = process_find_by_handle(hProcess);
+
+    if (!pcs) return FALSE;
+    if (!searchPath) return FALSE;
+
+    HeapFree(GetProcessHeap(), 0, pcs->search_path);
+    pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0, 
+                                          (lstrlenW(searchPath) + 1) * sizeof(WCHAR)),
+                                searchPath);
+    return TRUE;
+}
+
+/******************************************************************
+ *		SymSetSearchPath (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymSetSearchPath(HANDLE hProcess, PCSTR searchPath)
+{
+    BOOL        ret = FALSE;
+    unsigned    len;
+    WCHAR*      sp;
+
+    len = MultiByteToWideChar(CP_ACP, 0, searchPath, -1, NULL, 0);
+    if ((sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
+    {
+        MultiByteToWideChar(CP_ACP, 0, searchPath, -1, sp, len);
+
+        ret = SymSetSearchPathW(hProcess, sp);
+        HeapFree(GetProcessHeap(), 0, sp);
+    }
+    return ret;
+}
+
+/***********************************************************************
+ *		SymGetSearchPathW (DBGHELP.@)
+ */
+BOOL WINAPI SymGetSearchPathW(HANDLE hProcess, LPWSTR szSearchPath, 
+                              DWORD SearchPathLength)
+{
+    struct process* pcs = process_find_by_handle(hProcess);
+    if (!pcs) return FALSE;
+
+    lstrcpynW(szSearchPath, pcs->search_path, SearchPathLength);
+    return TRUE;
+}
+
+/***********************************************************************
+ *		SymGetSearchPath (DBGHELP.@)
+ */
+BOOL WINAPI SymGetSearchPath(HANDLE hProcess, LPSTR szSearchPath, 
+                             DWORD SearchPathLength)
+{
+    WCHAR*      buffer = HeapAlloc(GetProcessHeap(), 0, SearchPathLength * sizeof(WCHAR));
+    BOOL        ret = FALSE;
+
+    if (buffer)
+    {
+        ret = SymGetSearchPathW(hProcess, buffer, SearchPathLength);
+        if (ret)
+            WideCharToMultiByte(CP_ACP, 0, buffer, SearchPathLength,
+                                szSearchPath, SearchPathLength, NULL, NULL);
+        HeapFree(GetProcessHeap(), 0, buffer);
+    }
+    return ret;
+}
+
+/******************************************************************
+ *		invade_process
+ *
+ * SymInitialize helper: loads in dbghelp all known (and loaded modules)
+ * this assumes that hProcess is a handle on a valid process
+ */
+static BOOL WINAPI process_invade_cb(char* name, DWORD base, DWORD size, void* user)
+{
+    char        tmp[MAX_PATH];
+    HANDLE      hProcess = (HANDLE)user;
+
+    if (!GetModuleFileNameExA(hProcess, (HMODULE)base, 
+                              tmp, sizeof(tmp)))
+        lstrcpynA(tmp, name, sizeof(tmp));
+
+    SymLoadModule(hProcess, 0, tmp, name, base, size);
+    return TRUE;
+}
+
+/******************************************************************
+ *		check_live_target
+ *
+ */
+static BOOL check_live_target(struct process* pcs)
+{
+    if (!GetProcessId(pcs->handle)) return FALSE;
+    if (GetEnvironmentVariableA("DBGHELP_NOLIVE", NULL, 0)) return FALSE;
+    elf_read_wine_loader_dbg_info(pcs);
+    return TRUE;
+}
+
+/******************************************************************
+ *		SymInitializeW (DBGHELP.@)
+ *
+ * The initialisation of a dbghelp's context.
+ * Note that hProcess doesn't need to be a valid process handle (except
+ * when fInvadeProcess is TRUE).
+ * Since, we're also allow to load ELF (pure) libraries and Wine ELF libraries 
+ * containing PE (and NE) module(s), here's how we handle it:
+ * - we load every module (ELF, NE, PE) passed in SymLoadModule
+ * - in fInvadeProcess (in SymInitialize) is TRUE, we set up what is called ELF
+ *   synchronization: hProcess should be a valid process handle, and we hook
+ *   ourselves on hProcess's loaded ELF-modules, and keep this list in sync with
+ *   our internal ELF modules representation (loading / unloading). This way,
+ *   we'll pair every loaded builtin PE module with its ELF counterpart (and
+ *   access its debug information).
+ * - if fInvadeProcess (in SymInitialize) is FALSE, we check anyway if the 
+ *   hProcess refers to a running process. We use some heuristics here, so YMMV.
+ *   If we detect a live target, then we get the same handling as if
+ *   fInvadeProcess is TRUE (except that the modules are not loaded). Otherwise,
+ *   we won't be able to make the peering between a builtin PE module and its ELF
+ *   counterpart. Hence we won't be able to provide the requested debug
+ *   information. We'll however be able to load native PE modules (and their
+ *   debug information) without any trouble.
+ * Note also that this scheme can be intertwined with the deferred loading 
+ * mechanism (ie only load the debug information when we actually need it).
+ */
+BOOL WINAPI SymInitializeW(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess)
+{
+    struct process*     pcs;
+
+    TRACE("(%p %s %u)\n", hProcess, debugstr_w(UserSearchPath), fInvadeProcess);
+
+    if (process_find_by_handle(hProcess))
+        FIXME("what to do ??\n");
+
+    pcs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pcs));
+    if (!pcs) return FALSE;
+
+    pcs->handle = hProcess;
+
+    if (UserSearchPath)
+    {
+        pcs->search_path = lstrcpyW(HeapAlloc(GetProcessHeap(), 0,      
+                                              (lstrlenW(UserSearchPath) + 1) * sizeof(WCHAR)),
+                                    UserSearchPath);
+    }
+    else
+    {
+        unsigned        size;
+        unsigned        len;
+        static const WCHAR      sym_path[] = {'_','N','T','_','S','Y','M','B','O','L','_','P','A','T','H',0};
+        static const WCHAR      alt_sym_path[] = {'_','N','T','_','A','L','T','E','R','N','A','T','E','_','S','Y','M','B','O','L','_','P','A','T','H',0};
+
+        pcs->search_path = HeapAlloc(GetProcessHeap(), 0, (len = MAX_PATH) * sizeof(WCHAR));
+        while ((size = GetCurrentDirectoryW(len, pcs->search_path)) >= len)
+            pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (len *= 2) * sizeof(WCHAR));
+        pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1) * sizeof(WCHAR));
+
+        len = GetEnvironmentVariableW(sym_path, NULL, 0);
+        if (len)
+        {
+            pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
+            pcs->search_path[size] = ';';
+            GetEnvironmentVariableW(sym_path, pcs->search_path + size + 1, len);
+            size += 1 + len;
+        }
+        len = GetEnvironmentVariableW(alt_sym_path, NULL, 0);
+        if (len)
+        {
+            pcs->search_path = HeapReAlloc(GetProcessHeap(), 0, pcs->search_path, (size + 1 + len + 1) * sizeof(WCHAR));
+            pcs->search_path[size] = ';';
+            GetEnvironmentVariableW(alt_sym_path, pcs->search_path + size + 1, len);
+            size += 1 + len;
+        }
+    }
+
+    pcs->lmodules = NULL;
+    pcs->dbg_hdr_addr = 0;
+    pcs->next = process_first;
+    process_first = pcs;
+    
+    if (check_live_target(pcs))
+    {
+        if (fInvadeProcess)
+            EnumerateLoadedModules(hProcess, process_invade_cb, (void*)hProcess);
+        elf_synchronize_module_list(pcs);
+    }
+    else if (fInvadeProcess)
+    {
+        SymCleanup(hProcess);
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
     return TRUE;
 }
 
+/******************************************************************
+ *		SymInitialize (DBGHELP.@)
+ *
+ *
+ */
+BOOL WINAPI SymInitialize(HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess)
+{
+    WCHAR*              sp = NULL;
+    BOOL                ret;
+
+    if (UserSearchPath)
+    {
+        unsigned len;
+
+        len = MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, NULL, 0);
+        sp = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP, 0, UserSearchPath, -1, sp, len);
+    }
+
+    ret = SymInitializeW(hProcess, sp, fInvadeProcess);
+    HeapFree(GetProcessHeap(), 0, sp);
+    return ret;
+}
+
+/******************************************************************
+ *		SymCleanup (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymCleanup(HANDLE hProcess)
+{
+    struct process**    ppcs;
+    struct process*     next;
+
+    for (ppcs = &process_first; *ppcs; ppcs = &(*ppcs)->next)
+    {
+        if ((*ppcs)->handle == hProcess)
+        {
+            while ((*ppcs)->lmodules) module_remove(*ppcs, (*ppcs)->lmodules);
+
+            HeapFree(GetProcessHeap(), 0, (*ppcs)->search_path);
+            next = (*ppcs)->next;
+            HeapFree(GetProcessHeap(), 0, *ppcs);
+            *ppcs = next;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/******************************************************************
+ *		SymSetOptions (DBGHELP.@)
+ *
+ */
+DWORD WINAPI SymSetOptions(DWORD opts)
+{
+    struct process* pcs;
+
+    for (pcs = process_first; pcs; pcs = pcs->next)
+    {
+        pcs_callback(pcs, CBA_SET_OPTIONS, &opts);
+    }
+    return dbghelp_options = opts;
+}
+
+/******************************************************************
+ *		SymGetOptions (DBGHELP.@)
+ *
+ */
 DWORD WINAPI SymGetOptions(void)
 {
-   FIXME ("stub!\n");
-   return 0;
+    return dbghelp_options;
 }
 
-DWORD WINAPI SymSetOptions (DWORD SymOptions)
+/******************************************************************
+ *		SymSetParentWindow (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymSetParentWindow(HWND hwnd)
+{
+    /* Save hwnd so it can be used as parent window */
+    FIXME("(%p): stub\n", hwnd);
+    return TRUE;
+}
+
+/******************************************************************
+ *		SymSetContext (DBGHELP.@)
+ *
+ */
+BOOL WINAPI SymSetContext(HANDLE hProcess, PIMAGEHLP_STACK_FRAME StackFrame,
+                          PIMAGEHLP_CONTEXT Context)
+{
+    struct process* pcs = process_find_by_handle(hProcess);
+    if (!pcs) return FALSE;
+
+    if (pcs->ctx_frame.ReturnOffset == StackFrame->ReturnOffset &&
+        pcs->ctx_frame.FrameOffset  == StackFrame->FrameOffset  &&
+        pcs->ctx_frame.StackOffset  == StackFrame->StackOffset)
+    {
+        TRACE("Setting same frame {rtn=%s frm=%s stk=%s}\n",
+              wine_dbgstr_longlong(pcs->ctx_frame.ReturnOffset),
+              wine_dbgstr_longlong(pcs->ctx_frame.FrameOffset),
+              wine_dbgstr_longlong(pcs->ctx_frame.StackOffset));
+        pcs->ctx_frame.InstructionOffset = StackFrame->InstructionOffset;
+        SetLastError(ERROR_ACCESS_DENIED); /* latest MSDN says ERROR_SUCCESS */
+        return FALSE;
+    }
+
+    pcs->ctx_frame = *StackFrame;
+    /* MSDN states that Context is not (no longer?) used */
+    return TRUE;
+}
+
+/******************************************************************
+ *		reg_cb64to32 (internal)
+ *
+ * Registered callback for converting information from 64 bit to 32 bit
+ */
+static BOOL CALLBACK reg_cb64to32(HANDLE hProcess, ULONG action, ULONG64 data, ULONG64 user)
+{
+    PSYMBOL_REGISTERED_CALLBACK         cb32 = (PSYMBOL_REGISTERED_CALLBACK)(DWORD)(user >> 32);
+    DWORD                               user32 = (DWORD)user;
+    void*                               data32;
+    IMAGEHLP_DEFERRED_SYMBOL_LOAD64*    idsl64;
+    IMAGEHLP_DEFERRED_SYMBOL_LOAD       idsl;
+
+    switch (action)
+    {
+    case CBA_DEBUG_INFO:
+    case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
+    case CBA_SET_OPTIONS:
+    case CBA_SYMBOLS_UNLOADED:
+        data32 = (void*)(DWORD)data;
+        break;
+    case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
+    case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
+    case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
+    case CBA_DEFERRED_SYMBOL_LOAD_START:
+        idsl64 = (IMAGEHLP_DEFERRED_SYMBOL_LOAD64*)(DWORD)data;
+        if (!validate_addr64(idsl64->BaseOfImage))
+            return FALSE;
+        idsl.SizeOfStruct = sizeof(idsl);
+        idsl.BaseOfImage = (DWORD)idsl64->BaseOfImage;
+        idsl.CheckSum = idsl64->CheckSum;
+        idsl.TimeDateStamp = idsl64->TimeDateStamp;
+        memcpy(idsl.FileName, idsl64->FileName, sizeof(idsl.FileName));
+        idsl.Reparse = idsl64->Reparse;
+        data32 = &idsl;
+        break;
+    case CBA_DUPLICATE_SYMBOL:
+    case CBA_EVENT:
+    case CBA_READ_MEMORY:
+    default:
+        FIXME("No mapping for action %u\n", action);
+        return FALSE;
+    }
+    return cb32(hProcess, action, (PVOID)data32, (PVOID)user32);
+}
+
+/******************************************************************
+ *		pcs_callback (internal)
+ */
+BOOL pcs_callback(const struct process* pcs, ULONG action, void* data)
+{
+    TRACE("%p %u %p\n", pcs, action, data);
+
+    if (!pcs->reg_cb) return FALSE;
+    if (!pcs->reg_is_unicode)
+    {
+        IMAGEHLP_DEFERRED_SYMBOL_LOAD64     idsl;
+        IMAGEHLP_DEFERRED_SYMBOL_LOADW64*   idslW;
+
+        switch (action)
+        {
+        case CBA_DEBUG_INFO:
+        case CBA_DEFERRED_SYMBOL_LOAD_CANCEL:
+        case CBA_SET_OPTIONS:
+        case CBA_SYMBOLS_UNLOADED:
+            break;
+        case CBA_DEFERRED_SYMBOL_LOAD_COMPLETE:
+        case CBA_DEFERRED_SYMBOL_LOAD_FAILURE:
+        case CBA_DEFERRED_SYMBOL_LOAD_PARTIAL:
+        case CBA_DEFERRED_SYMBOL_LOAD_START:
+            idslW = (IMAGEHLP_DEFERRED_SYMBOL_LOADW64*)(DWORD)data;
+            idsl.SizeOfStruct = sizeof(idsl);
+            idsl.BaseOfImage = idslW->BaseOfImage;
+            idsl.CheckSum = idslW->CheckSum;
+            idsl.TimeDateStamp = idslW->TimeDateStamp;
+            WideCharToMultiByte(CP_ACP, 0, idslW->FileName, -1,
+                                idsl.FileName, sizeof(idsl.FileName), NULL, NULL);
+            idsl.Reparse = idslW->Reparse;
+            data = &idsl;
+            break;
+        case CBA_DUPLICATE_SYMBOL:
+        case CBA_EVENT:
+        case CBA_READ_MEMORY:
+        default:
+            FIXME("No mapping for action %u\n", action);
+            return FALSE;
+        }
+    }
+    return pcs->reg_cb(pcs->handle, action, (ULONG64)(DWORD_PTR)data, pcs->reg_user);
+}
+
+/******************************************************************
+ *		sym_register_cb
+ *
+ * Helper for registering a callback.
+ */
+static BOOL sym_register_cb(HANDLE hProcess, 
+                            PSYMBOL_REGISTERED_CALLBACK64 cb,
+                            DWORD64 user, BOOL unicode)
+{
+    struct process* pcs = process_find_by_handle(hProcess);
+
+    if (!pcs) return FALSE;
+    pcs->reg_cb = cb;
+    pcs->reg_is_unicode = unicode;
+    pcs->reg_user = user;
+
+    return TRUE;
+}
+
+/***********************************************************************
+ *		SymRegisterCallback (DBGHELP.@)
+ */
+BOOL WINAPI SymRegisterCallback(HANDLE hProcess, 
+                                PSYMBOL_REGISTERED_CALLBACK CallbackFunction,
+                                PVOID UserContext)
+{
+    DWORD64 tmp = ((ULONGLONG)(DWORD)CallbackFunction << 32) | (DWORD)UserContext;
+    TRACE("(%p, %p, %p)\n", 
+          hProcess, CallbackFunction, UserContext);
+    return sym_register_cb(hProcess, reg_cb64to32, tmp, FALSE);
+}
+
+/***********************************************************************
+ *		SymRegisterCallback64 (DBGHELP.@)
+ */
+BOOL WINAPI SymRegisterCallback64(HANDLE hProcess, 
+                                  PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
+                                  ULONG64 UserContext)
+{
+    TRACE("(%p, %p, %s)\n", 
+          hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
+    return sym_register_cb(hProcess, CallbackFunction, UserContext, FALSE);
+}
+
+/***********************************************************************
+ *		SymRegisterCallbackW64 (DBGHELP.@)
+ */
+BOOL WINAPI SymRegisterCallbackW64(HANDLE hProcess, 
+                                   PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction,
+                                   ULONG64 UserContext)
+{
+    TRACE("(%p, %p, %s)\n", 
+          hProcess, CallbackFunction, wine_dbgstr_longlong(UserContext));
+    return sym_register_cb(hProcess, CallbackFunction, UserContext, TRUE);
+}
+
+/* This is imagehlp version not dbghelp !! */
+static API_VERSION api_version = { 4, 0, 2, 0 };
+
+/***********************************************************************
+ *           ImagehlpApiVersion (DBGHELP.@)
+ */
+LPAPI_VERSION WINAPI ImagehlpApiVersion(VOID)
+{
+    return &api_version;
+}
+
+/***********************************************************************
+ *           ImagehlpApiVersionEx (DBGHELP.@)
+ */
+LPAPI_VERSION WINAPI ImagehlpApiVersionEx(LPAPI_VERSION AppVersion)
+{
+    if (!AppVersion) return NULL;
+
+    AppVersion->MajorVersion = api_version.MajorVersion;
+    AppVersion->MinorVersion = api_version.MinorVersion;
+    AppVersion->Revision = api_version.Revision;
+    AppVersion->Reserved = api_version.Reserved;
+
+    return AppVersion;
+}
+
+/******************************************************************
+ *		ExtensionApiVersion (DBGHELP.@)
+ */
+LPEXT_API_VERSION WINAPI ExtensionApiVersion(void)
+{
+    static EXT_API_VERSION      eav = {5, 5, 5, 0};
+    return &eav;
+}
+
+/******************************************************************
+ *		WinDbgExtensionDllInit (DBGHELP.@)
+ */
+void WINAPI WinDbgExtensionDllInit(PWINDBG_EXTENSION_APIS lpExtensionApis,
+                                   unsigned short major, unsigned short minor)
 {
-   FIXME ("(0x%lx)L stub!\n", SymOptions);
-   return 0;
 }

Index: dbghelp.spec
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/dbghelp/dbghelp.spec,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- dbghelp.spec	31 Jul 2007 19:50:48 -0000	1.4
+++ dbghelp.spec	30 Aug 2007 14:15:59 -0000	1.5
@@ -1,129 +1,126 @@
-name	dbghelp
-type	win32
-
 @ stub DbgHelpCreateUserDump
 @ stub DbgHelpCreateUserDumpW
-@ stub EnumDirTree
-@ stub EnumDirTreeW
+@ stdcall EnumDirTree(long str str ptr ptr ptr)
+@ stdcall EnumDirTreeW(long wstr wstr ptr ptr ptr)
 @ stdcall EnumerateLoadedModules(long ptr ptr)
-@ stub EnumerateLoadedModules64
-@ stub EnumerateLoadedModulesW64
-@ stub ExtensionApiVersion
-@ stub FindDebugInfoFile
-@ stub FindDebugInfoFileEx
+@ stdcall EnumerateLoadedModules64(long ptr ptr)
+@ stdcall EnumerateLoadedModulesW64(long ptr ptr)
+@ stdcall ExtensionApiVersion()
+@ stdcall FindDebugInfoFile(str str ptr)
+@ stdcall FindDebugInfoFileEx(str str ptr ptr ptr)
 @ stub FindDebugInfoFileExW
-@ stub FindExecutableImage
-@ stub FindExecutableImageEx
-@ stub FindExecutableImageExW
+@ stdcall FindExecutableImage(str str str)
+@ stdcall FindExecutableImageEx(str str ptr ptr ptr)
+@ stdcall FindExecutableImageExW(wstr wstr ptr ptr ptr)
 @ stub FindFileInPath
 @ stub FindFileInSearchPath
-@ stub GetTimestampForLoadedLibrary
-@ stub ImageDirectoryEntryToData
+@ stdcall GetTimestampForLoadedLibrary(long)
+@ stdcall ImageDirectoryEntryToData(ptr long long ptr) ntdll.RtlImageDirectoryEntryToData
 @ stub ImageDirectoryEntryToDataEx
-@ stub ImageNtHeader
-@ stub ImageRvaToSection
-@ stub ImageRvaToVa
-@ stub ImagehlpApiVersion
-@ stub ImagehlpApiVersionEx
-@ stub MakeSureDirectoryPathExists
-@ stub MapDebugInformation
-@ stub MiniDumpReadDumpStream
-@ stub MiniDumpWriteDump
-@ stub SearchTreeForFile
-@ stub SearchTreeForFileW
-@ stub StackWalk
-@ stub StackWalk64
+@ stdcall ImageNtHeader(ptr) ntdll.RtlImageNtHeader
+@ stdcall ImageRvaToSection(ptr ptr long) ntdll.RtlImageRvaToSection
+@ stdcall ImageRvaToVa(ptr ptr long ptr) ntdll.RtlImageRvaToVa
+@ stdcall ImagehlpApiVersion()
+@ stdcall ImagehlpApiVersionEx(ptr)
+@ stdcall MakeSureDirectoryPathExists(str)
+@ stdcall MapDebugInformation(long str str long)
+@ stdcall MiniDumpReadDumpStream(ptr long ptr ptr ptr)
+@ stdcall MiniDumpWriteDump(ptr long ptr long long long long)
+@ stdcall SearchTreeForFile(str str ptr)
+@ stdcall SearchTreeForFileW(wstr wstr ptr)
+@ stdcall StackWalk(long long long ptr ptr ptr ptr ptr ptr)
+@ stdcall StackWalk64(long long long ptr ptr ptr ptr ptr ptr)
 @ stub SymAddSymbol
 @ stub SymAddSymbolW
-@ stdcall SymCleanup(ptr) SymCleanup
-@ stub SymEnumLines
+@ stdcall SymCleanup(long)
+@ stdcall SymEnumLines(ptr double str str ptr ptr)
 @ stub SymEnumLinesW
-@ stub SymEnumSourceFiles
+@ stdcall SymEnumSourceFiles(ptr double str ptr ptr)
 @ stub SymEnumSourceFilesW
 @ stub SymEnumSym
-@ stub SymEnumSymbols
-@ stub SymEnumSymbolsW
+@ stdcall SymEnumSymbols(ptr double str ptr ptr)
+@ stdcall SymEnumSymbolsW(ptr double wstr ptr ptr)
 @ stub SymEnumSymbolsForAddr
 @ stub SymEnumSymbolsForAddrW
-@ stub SymEnumTypes
-@ stub SymEnumTypesW
-@ stub SymEnumerateModules
-@ stub SymEnumerateModules64
-@ stub SymEnumerateModulesW64
-@ stub SymEnumerateSymbols
+@ stdcall SymEnumTypes(ptr double ptr ptr)
+@ stdcall SymEnumTypesW(ptr double ptr ptr)
+@ stdcall SymEnumerateModules(long ptr ptr)
+@ stdcall SymEnumerateModules64(long ptr ptr)
+@ stdcall SymEnumerateModulesW64(long ptr ptr)
+@ stdcall SymEnumerateSymbols(long long ptr ptr)
 @ stub SymEnumerateSymbols64
 @ stub SymEnumerateSymbolsW
 @ stub SymEnumerateSymbolsW64
 @ stub SymFindDebugInfoFile
 @ stub SymFindDebugInfoFileW
-@ stub SymFindFileInPath
-@ stub SymFindFileInPathW
-@ stub SymFromAddr
-@ stub SymFromAddrW
+@ stdcall SymFindFileInPath(long str str ptr long long long ptr ptr ptr)
+@ stdcall SymFindFileInPathW(long wstr wstr ptr long long long ptr ptr ptr)
+@ stdcall SymFromAddr(ptr double ptr ptr)
+@ stdcall SymFromAddrW(ptr double ptr ptr)
 @ stub SymFromIndex
 @ stub SymFromIndexW
-@ stub SymFromName
+@ stdcall SymFromName(long str ptr)
 @ stub SymFromNameW
 @ stub SymFromToken
 @ stub SymFromTokenW
-@ stub SymFunctionTableAccess
-@ stub SymFunctionTableAccess64
+@ stdcall SymFunctionTableAccess(long long)
+@ stdcall SymFunctionTableAccess64(long double)
 @ stub SymGetFileLineOffsets64
 @ stub SymGetHomeDirectory
 @ stub SymGetHomeDirectoryW
-@ stub SymGetLineFromAddr
-@ stub SymGetLineFromAddr64
-@ stub SymGetLineFromAddrW64
+@ stdcall SymGetLineFromAddr(long long ptr ptr)
+@ stdcall SymGetLineFromAddr64(long double ptr ptr)
+@ stdcall SymGetLineFromAddrW64(long double ptr ptr)
 @ stub SymGetLineFromName
 @ stub SymGetLineFromName64
-@ stub SymGetLineNext
-@ stub SymGetLineNext64
+@ stdcall SymGetLineNext(long ptr)
+@ stdcall SymGetLineNext64(long ptr)
 @ stub SymGetLineNextW64
-@ stub SymGetLinePrev
-@ stub SymGetLinePrev64
+@ stdcall SymGetLinePrev(long ptr)
+@ stdcall SymGetLinePrev64(long ptr)
 @ stub SymGetLinePrevW64
-@ stub SymGetModuleBase
-@ stub SymGetModuleBase64
-@ stub SymGetModuleInfo
-@ stub SymGetModuleInfo64
-@ stub SymGetModuleInfoW
-@ stub SymGetModuleInfoW64
+@ stdcall SymGetModuleBase(long long)
+@ stdcall SymGetModuleBase64(long double)
+@ stdcall SymGetModuleInfo(long long ptr)
+@ stdcall SymGetModuleInfo64(long double ptr)
+@ stdcall SymGetModuleInfoW(long long ptr)
+@ stdcall SymGetModuleInfoW64(long double ptr)
 @ stub SymGetOmapBlockBase
 @ stdcall SymGetOptions()
 @ stub SymGetScope
 @ stub SymGetScopeW
-@ stub SymGetSearchPath
-@ stub SymGetSearchPathW
+@ stdcall SymGetSearchPath(long ptr long)
+@ stdcall SymGetSearchPathW(long ptr long)
 @ stub SymGetSourceFileFromToken
 @ stub SymGetSourceFileFromTokenW
-@ stub SymGetSourceFileToken
-@ stub SymGetSourceFileTokenW
+@ stdcall SymGetSourceFileToken(ptr double str ptr ptr)
+@ stdcall SymGetSourceFileTokenW(ptr double wstr ptr ptr)
 @ stub SymGetSourceFileW
 @ stub SymGetSourceVarFromToken
 @ stub SymGetSourceVarFromTokenW
-@ stub SymGetSymFromAddr
-@ stub SymGetSymFromAddr64
-@ stub SymGetSymFromName
+@ stdcall SymGetSymFromAddr(long long ptr ptr)
+@ stdcall SymGetSymFromAddr64(long double ptr ptr)
+@ stdcall SymGetSymFromName(long str ptr)
 @ stub SymGetSymFromName64
-@ stub SymGetSymNext
+@ stdcall SymGetSymNext(long ptr)
 @ stub SymGetSymNext64
-@ stub SymGetSymPrev
+@ stdcall SymGetSymPrev(long ptr)
 @ stub SymGetSymPrev64
 @ stub SymGetSymbolFile
 @ stub SymGetSymbolFileW
-@ stub SymGetTypeFromName
+@ stdcall SymGetTypeFromName(ptr double str ptr)
 @ stub SymGetTypeFromNameW
-@ stub SymGetTypeInfo
+@ stdcall SymGetTypeInfo(ptr double long long ptr)
 @ stub SymGetTypeInfoEx
-@ stdcall SymInitialize(ptr ptr long) SymInitialize
-@ stub SymInitializeW
-@ stub SymLoadModule
-@ stub SymLoadModule64
-@ stub SymLoadModuleEx
-@ stub SymLoadModuleExW
-@ stub SymMatchFileName
-@ stub SymMatchFileNameW
-@ stub SymMatchString
+@ stdcall SymInitialize(long str long)
+@ stdcall SymInitializeW(long wstr long)
+@ stdcall SymLoadModule(long long str str long long)
+@ stdcall SymLoadModule64(long long str str double long)
+@ stdcall SymLoadModuleEx(long long str str double long ptr long)
+@ stdcall SymLoadModuleExW(long long wstr wstr double long ptr long)
+@ stdcall SymMatchFileName(str str ptr ptr)
+@ stdcall SymMatchFileNameW(wstr wstr ptr ptr)
+@ stdcall SymMatchString(str str long)
 @ stub SymMatchStringA
 @ stub SymMatchStringW
 @ stub SymNext
@@ -131,20 +128,20 @@
 @ stub SymPrev
 @ stub SymPrevW
 @ stub SymRefreshModuleList
-@ stub SymRegisterCallback
-@ stub SymRegisterCallback64
-@ stub SymRegisterCallbackW64
-@ stub SymRegisterFunctionEntryCallback
-@ stub SymRegisterFunctionEntryCallback64
-@ stub SymSearch
-@ stub SymSearchW
-@ stub SymSetContext
+@ stdcall SymRegisterCallback(long ptr ptr)
+@ stdcall SymRegisterCallback64(long ptr double)
+@ stdcall SymRegisterCallbackW64(long ptr double)
+@ stdcall SymRegisterFunctionEntryCallback(ptr ptr ptr)
+@ stdcall SymRegisterFunctionEntryCallback64(ptr ptr double)
+@ stdcall SymSearch(long double long long str double ptr ptr long)
+@ stdcall SymSearchW(long double long long wstr double ptr ptr long)
+@ stdcall SymSetContext(long ptr ptr)
 @ stub SymSetHomeDirectory
 @ stub SymSetHomeDirectoryW
 @ stdcall SymSetOptions(long)
-@ stub SymSetParentWindow
-@ stub SymSetSearchPath
-@ stub SymSetSearchPathW
+@ stdcall SymSetParentWindow(long)
+@ stdcall SymSetSearchPath(long str)
+@ stdcall SymSetSearchPathW(long wstr)
 @ stub SymSetSymWithAddr64
 @ stub SymSrvDeltaName
 @ stub SymSrvDeltaNameW
@@ -163,14 +160,14 @@
 @ stub SymSrvStoreSupplement
 @ stub SymSrvStoreSupplementW
 # @ stub SymSetSymWithAddr64 no longer present ??
-@ stub SymUnDName
+@ stdcall SymUnDName(ptr str long)
 @ stub SymUnDName64
-@ stub SymUnloadModule
-@ stub SymUnloadModule64
-@ stub UnDecorateSymbolName
+@ stdcall SymUnloadModule(long long)
+@ stdcall SymUnloadModule64(long double)
+@ stdcall UnDecorateSymbolName(str str long long)
 @ stub UnDecorateSymbolNameW
-@ stub UnmapDebugInformation
-@ stub WinDbgExtensionDllInit
+@ stdcall UnmapDebugInformation(ptr)
+@ stdcall WinDbgExtensionDllInit(ptr long long)
 #@ stub block
 #@ stub chksym
 #@ stub dbghelp

--- NEW FILE: dbghelp_private.h ---
/*
 * File dbghelp_private.h - dbghelp internal definitions
 *
 * Copyright (C) 1995, Alexandre Julliard
 * Copyright (C) 1996, Eric Youngdale.
 * Copyright (C) 1999-2000, Ulrich Weigand.
 * Copyright (C) 2004-2007, Eric Pouech.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winver.h"
#include "dbghelp.h"
#include "objbase.h"
#include "oaidl.h"
#include "winnls.h"
#include "wine/unicode.h"

#include "cvconst.h"

/* #define USE_STATS */

struct pool /* poor's man */
{
    struct pool_arena*  first;
    unsigned            arena_size;
};

void     pool_init(struct pool* a, unsigned arena_size);
void     pool_destroy(struct pool* a);
void*    pool_alloc(struct pool* a, unsigned len);
char*    pool_strdup(struct pool* a, const char* str);

struct vector
{
    void**      buckets;
    unsigned    elt_size;
    unsigned    shift;
    unsigned    num_elts;
    unsigned    num_buckets;
    unsigned    buckets_allocated;
};

void     vector_init(struct vector* v, unsigned elt_sz, unsigned bucket_sz);
unsigned vector_length(const struct vector* v);
void*    vector_at(const struct vector* v, unsigned pos);
void*    vector_add(struct vector* v, struct pool* pool);

struct sparse_array
{
    struct vector               key2index;
    struct vector               elements;
};

void     sparse_array_init(struct sparse_array* sa, unsigned elt_sz, unsigned bucket_sz);
void*    sparse_array_find(const struct sparse_array* sa, unsigned long idx);
void*    sparse_array_add(struct sparse_array* sa, unsigned long key, struct pool* pool);
unsigned sparse_array_length(const struct sparse_array* sa);

struct hash_table_elt
{
    const char*                 name;
    struct hash_table_elt*      next;
};

struct hash_table
{
    unsigned                    num_elts;
    unsigned                    num_buckets;
    struct hash_table_elt**     buckets;
    struct pool*                pool;
};

void     hash_table_init(struct pool* pool, struct hash_table* ht,
                         unsigned num_buckets);
void     hash_table_destroy(struct hash_table* ht);
void     hash_table_add(struct hash_table* ht, struct hash_table_elt* elt);
void*    hash_table_find(const struct hash_table* ht, const char* name);
unsigned hash_table_hash(const char* name, unsigned num_buckets);

struct hash_table_iter
{
    const struct hash_table*    ht;
    struct hash_table_elt*      element;
    int                         index;
    int                         last;
};

void     hash_table_iter_init(const struct hash_table* ht,
                              struct hash_table_iter* hti, const char* name);
void*    hash_table_iter_up(struct hash_table_iter* hti);

#define GET_ENTRY(__i, __t, __f) \
    ((__t*)((char*)(__i) - (unsigned int)(&((__t*)0)->__f)))


extern unsigned dbghelp_options;
/* some more Wine extensions */
#define SYMOPT_WINE_WITH_ELF_MODULES 0x40000000

enum location_kind {loc_error,          /* reg is the error code */
                    loc_absolute,       /* offset is the location */
                    loc_register,       /* reg is the location */
                    loc_regrel,         /* [reg+offset] is the location */
                    loc_user,           /* value is debug information dependent,
                                           reg & offset can be used ad libidem */
};

enum location_error {loc_err_internal = -1,     /* internal while computing */
                     loc_err_too_complex = -2,  /* couldn't compute location (even at runtime) */
                     loc_err_out_of_scope = -3, /* variable isn't available at current address */
                     loc_err_cant_read = -4,    /* couldn't read memory at given address */
};

struct location
{
    unsigned            kind : 8,
                        reg;
    unsigned long       offset;
};

struct symt
{
    enum SymTagEnum             tag;
};

struct symt_ht
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;        /* if global symbol or type */
};

/* lexical tree */
struct symt_block
{
    struct symt                 symt;
    unsigned long               address;
    unsigned long               size;
    struct symt*                container;      /* block, or func */
    struct vector               vchildren;      /* sub-blocks & local variables */
};

struct symt_compiland
{
    struct symt                 symt;
    unsigned long               address;
    unsigned                    source;
    struct vector               vchildren;      /* global variables & functions */
};

struct symt_data
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;       /* if global symbol */
    enum DataKind               kind;
    struct symt*                container;
    struct symt*                type;
    union                                       /* depends on kind */
    {
        /* DataIs{Global, FileStatic}:
         *      loc.kind is loc_absolute
         *      loc.offset is address
         * DataIs{Local,Param}:
         *      with loc.kind
         *              loc_absolute    not supported
         *              loc_register    location is in register loc.reg
         *              loc_regrel      location is at address loc.reg + loc.offset
         *              >= loc_user     ask debug info provider for resolution
         */
        struct location         var;
        /* DataIs{Member} (all values are in bits, not bytes) */
        struct
        {
            long                        offset;
            unsigned long               length;
        } member;
        /* DataIsConstant */
        VARIANT                 value;
    } u;
};

struct symt_function
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;       /* if global symbol */
    unsigned long               address;
    struct symt*                container;      /* compiland */
    struct symt*                type;           /* points to function_signature */
    unsigned long               size;
    struct vector               vlines;
    struct vector               vchildren;      /* locals, params, blocks, start/end, labels */
};

struct symt_function_point
{
    struct symt                 symt;           /* either SymTagFunctionDebugStart, SymTagFunctionDebugEnd, SymTagLabel */
    struct symt_function*       parent;
    struct location             loc;
    const char*                 name;           /* for labels */
};

struct symt_public
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;
    struct symt*                container;      /* compiland */
    unsigned long               address;
    unsigned long               size;
    unsigned                    in_code : 1,
                                is_function : 1;
};

struct symt_thunk
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;
    struct symt*                container;      /* compiland */
    unsigned long               address;
    unsigned long               size;
    THUNK_ORDINAL               ordinal;        /* FIXME: doesn't seem to be accessible */
};

/* class tree */
struct symt_array
{
    struct symt                 symt;
    int		                start;
    int		                end;
    struct symt*                base_type;
    struct symt*                index_type;
};

struct symt_basic
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;
    enum BasicType              bt;
    unsigned long               size;
};

struct symt_enum
{
    struct symt                 symt;
    const char*                 name;
    struct vector               vchildren;
};

struct symt_function_signature
{
    struct symt                 symt;
    struct symt*                rettype;
    struct vector               vchildren;
    enum CV_call_e              call_conv;
};

struct symt_function_arg_type
{
    struct symt                 symt;
    struct symt*                arg_type;
    struct symt*                container;
};

struct symt_pointer
{
    struct symt                 symt;
    struct symt*                pointsto;
};

struct symt_typedef
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;
    struct symt*                type;
};

struct symt_udt
{
    struct symt                 symt;
    struct hash_table_elt       hash_elt;
    enum UdtKind                kind;
    int		                size;
    struct vector               vchildren;
};

enum module_type
{
    DMT_UNKNOWN,        /* for lookup, not actually used for a module */
    DMT_ELF,            /* a real ELF shared module */
    DMT_PE,             /* a native or builtin PE module */
    DMT_PDB,            /* PDB file */
};

struct process;

struct module
{
    IMAGEHLP_MODULEW64          module;
    /* ANSI copy of module.ModuleName for efficiency */
    char                        module_name[MAX_PATH];
    struct module*              next;
    enum module_type		type : 16;
    unsigned short              is_virtual : 1;

    /* specific information for debug types */
    struct elf_module_info*	elf_info;
    struct dwarf2_module_info_s*dwarf2_info;

    /* memory allocation pool */
    struct pool                 pool;

    /* symbols & symbol tables */
    int                         sortlist_valid;
    unsigned                    num_sorttab;    /* number of symbols with addresses */
    struct symt_ht**            addr_sorttab;
    struct hash_table           ht_symbols;
    void                        (*loc_compute)(struct process* pcs,
                                               const struct module* module,
                                               const struct symt_function* func,
                                               struct location* loc);

    /* types */
    struct hash_table           ht_types;
    struct vector               vtypes;

    /* source files */
    unsigned                    sources_used;
    unsigned                    sources_alloc;
    char*                       sources;
};

struct process 
{
    struct process*             next;
    HANDLE                      handle;
    WCHAR*                      search_path;
    
    PSYMBOL_REGISTERED_CALLBACK64       reg_cb;
    BOOL                        reg_is_unicode;
    DWORD64                     reg_user;

    struct module*              lmodules;
    unsigned long               dbg_hdr_addr;

    IMAGEHLP_STACK_FRAME        ctx_frame;

    unsigned                    buffer_size;
    void*                       buffer;
};

struct line_info
{
    unsigned long               is_first : 1,
                                is_last : 1,
                                is_source_file : 1,
                                line_number;
    union
    {
        unsigned long               pc_offset;   /* if is_source_file isn't set */
        unsigned                    source_file; /* if is_source_file is set */
    } u;
};

struct module_pair
{
    struct process*             pcs;
    struct module*              requested; /* in:  to module_get_debug() */
    struct module*              effective; /* out: module with debug info */
};

enum pdb_kind {PDB_JG, PDB_DS};

struct pdb_lookup
{
    const char*                 filename;
    DWORD                       age;
    enum pdb_kind               kind;
    union
    {
        struct
        {
            DWORD               timestamp;
            struct PDB_JG_TOC*  toc;
        } jg;
        struct
        {
            GUID                guid;
            struct PDB_DS_TOC*  toc;
        } ds;
    } u;
};

/* dbghelp.c */
extern struct process* process_find_by_handle(HANDLE hProcess);
extern HANDLE hMsvcrt;
extern BOOL         validate_addr64(DWORD64 addr);
extern BOOL         pcs_callback(const struct process* pcs, ULONG action, void* data);
extern void*        fetch_buffer(struct process* pcs, unsigned size);

/* elf_module.c */
#define ELF_NO_MAP      ((const void*)0xffffffff)
typedef BOOL (*elf_enum_modules_cb)(const WCHAR*, unsigned long addr, void* user);
extern BOOL         elf_enum_modules(HANDLE hProc, elf_enum_modules_cb, void*);
extern BOOL         elf_fetch_file_info(const WCHAR* name, DWORD* base, DWORD* size, DWORD* checksum);
struct elf_file_map;
extern BOOL         elf_load_debug_info(struct module* module, struct elf_file_map* fmap);
extern struct module*
                    elf_load_module(struct process* pcs, const WCHAR* name, unsigned long);
extern BOOL         elf_read_wine_loader_dbg_info(struct process* pcs);
extern BOOL         elf_synchronize_module_list(struct process* pcs);
struct elf_thunk_area;
extern int          elf_is_in_thunk_area(unsigned long addr, const struct elf_thunk_area* thunks);
extern DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr);

/* module.c */
extern const WCHAR      S_ElfW[];
extern const WCHAR      S_WineLoaderW[];
extern const WCHAR      S_WinePThreadW[];
extern const WCHAR      S_WineKThreadW[];
extern const WCHAR      S_SlashW[];

extern struct module*
                    module_find_by_addr(const struct process* pcs, unsigned long addr,
                                        enum module_type type);
extern struct module*
                    module_find_by_name(const struct process* pcs,
                                        const WCHAR* name);
extern struct module*
                    module_find_by_nameA(const struct process* pcs,
                                         const char* name);
extern struct module*
                    module_is_already_loaded(const struct process* pcs,
                                             const WCHAR* imgname);
extern BOOL         module_get_debug(struct module_pair*);
extern struct module*
                    module_new(struct process* pcs, const WCHAR* name,
                               enum module_type type, BOOL virtual,
                               unsigned long addr, unsigned long size,
                               unsigned long stamp, unsigned long checksum);
extern struct module*
                    module_get_container(const struct process* pcs,
                                         const struct module* inner);
extern struct module*
                    module_get_containee(const struct process* pcs,
                                         const struct module* inner);
extern enum module_type
                    module_get_type_by_name(const WCHAR* name);
extern void         module_reset_debug_info(struct module* module);
extern BOOL         module_remove(struct process* pcs,
                                  struct module* module);
extern void         module_set_module(struct module* module, const WCHAR* name);

/* msc.c */
extern BOOL         pe_load_debug_directory(const struct process* pcs,
                                            struct module* module, 
                                            const BYTE* mapping,
                                            const IMAGE_SECTION_HEADER* sectp, DWORD nsect,
                                            const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg);
extern BOOL         pdb_fetch_file_info(struct pdb_lookup* pdb_lookup);

/* pe_module.c */
extern BOOL         pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth);
extern struct module*
                    pe_load_native_module(struct process* pcs, const WCHAR* name,
                                          HANDLE hFile, DWORD base, DWORD size);
extern struct module*
                    pe_load_builtin_module(struct process* pcs, const WCHAR* name,
                                           DWORD base, DWORD size);
extern BOOL         pe_load_debug_info(const struct process* pcs,
                                       struct module* module);
/* source.c */
extern unsigned     source_new(struct module* module, const char* basedir, const char* source);
extern const char*  source_get(const struct module* module, unsigned idx);

/* stabs.c */
extern BOOL         stabs_parse(struct module* module, unsigned long load_offset,
                                const void* stabs, int stablen,
                                const char* strs, int strtablen);

/* dwarf.c */
extern BOOL         dwarf2_parse(struct module* module, unsigned long load_offset,
                                 const struct elf_thunk_area* thunks,
				 const unsigned char* debug, unsigned int debug_size, 
				 const unsigned char* abbrev, unsigned int abbrev_size, 
				 const unsigned char* str, unsigned int str_size,
                                 const unsigned char* line, unsigned int line_size,
                                 const unsigned char* loclist, unsigned int loclist_size);

/* symbol.c */
extern const char*  symt_get_name(const struct symt* sym);
extern int          symt_cmp_addr(const void* p1, const void* p2);
extern void         copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si);
extern struct symt_ht*
                    symt_find_nearest(struct module* module, DWORD addr);
extern struct symt_compiland*
                    symt_new_compiland(struct module* module, unsigned long address,
                                       unsigned src_idx);
extern struct symt_public*
                    symt_new_public(struct module* module, 
                                    struct symt_compiland* parent, 
                                    const char* typename,
                                    unsigned long address, unsigned size,
                                    BOOL in_code, BOOL is_func);
extern struct symt_data*
                    symt_new_global_variable(struct module* module, 
                                             struct symt_compiland* parent,
                                             const char* name, unsigned is_static,
                                             unsigned long addr, unsigned long size, 
                                             struct symt* type);
extern struct symt_function*
                    symt_new_function(struct module* module,
                                      struct symt_compiland* parent,
                                      const char* name,
                                      unsigned long addr, unsigned long size,
                                      struct symt* type);
extern BOOL         symt_normalize_function(struct module* module, 
                                            struct symt_function* func);
extern void         symt_add_func_line(struct module* module,
                                       struct symt_function* func, 
                                       unsigned source_idx, int line_num, 
                                       unsigned long offset);
extern struct symt_data*
                    symt_add_func_local(struct module* module, 
                                        struct symt_function* func, 
                                        enum DataKind dt, const struct location* loc,
                                        struct symt_block* block,
                                        struct symt* type, const char* name);
extern struct symt_block*
                    symt_open_func_block(struct module* module, 
                                         struct symt_function* func,
                                         struct symt_block* block, 
                                         unsigned pc, unsigned len);
extern struct symt_block*
                    symt_close_func_block(struct module* module, 
                                          struct symt_function* func,
                                          struct symt_block* block, unsigned pc);
extern struct symt_function_point*
                    symt_add_function_point(struct module* module, 
                                            struct symt_function* func,
                                            enum SymTagEnum point, 
                                            const struct location* loc,
                                            const char* name);
extern BOOL         symt_fill_func_line_info(const struct module* module,
                                             const struct symt_function* func,
                                             DWORD addr, IMAGEHLP_LINE* line);
extern BOOL         symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE line);
extern struct symt_thunk*
                    symt_new_thunk(struct module* module, 
                                   struct symt_compiland* parent,
                                   const char* name, THUNK_ORDINAL ord,
                                   unsigned long addr, unsigned long size);
extern struct symt_data*
                    symt_new_constant(struct module* module,
                                      struct symt_compiland* parent,
                                      const char* name, struct symt* type,
                                      const VARIANT* v);

/* type.c */
extern void         symt_init_basic(struct module* module);
extern BOOL         symt_get_info(const struct symt* type,
                                  IMAGEHLP_SYMBOL_TYPE_INFO req, void* pInfo);
extern struct symt_basic*
                    symt_new_basic(struct module* module, enum BasicType, 
                                   const char* typename, unsigned size);
extern struct symt_udt*
                    symt_new_udt(struct module* module, const char* typename,
                                 unsigned size, enum UdtKind kind);
extern BOOL         symt_set_udt_size(struct module* module,
                                      struct symt_udt* type, unsigned size);
extern BOOL         symt_add_udt_element(struct module* module, 
                                         struct symt_udt* udt_type, 
                                         const char* name,
                                         struct symt* elt_type, unsigned offset, 
                                         unsigned size);
extern struct symt_enum*
                    symt_new_enum(struct module* module, const char* typename);
extern BOOL         symt_add_enum_element(struct module* module, 
                                          struct symt_enum* enum_type, 
                                          const char* name, int value);
extern struct symt_array*
                    symt_new_array(struct module* module, int min, int max, 
                                   struct symt* base, struct symt* index);
extern struct symt_function_signature*
                    symt_new_function_signature(struct module* module, 
                                                struct symt* ret_type,
                                                enum CV_call_e call_conv);
extern BOOL         symt_add_function_signature_parameter(struct module* module,
                                                          struct symt_function_signature* sig,
                                                          struct symt* param);
extern struct symt_pointer*
                    symt_new_pointer(struct module* module, 
                                     struct symt* ref_type);
extern struct symt_typedef*
                    symt_new_typedef(struct module* module, struct symt* ref, 
                                     const char* name);

--- NEW FILE: dwarf.c ---
/*
 * File dwarf.c - read dwarf2 information from the ELF modules
 *
 * Copyright (C) 2005, Raphael Junqueira
 * Copyright (C) 2006, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
[...2188 lines suppressed...]
    
        comp_unit_stream = (const dwarf2_comp_unit_stream_t*) comp_unit_cursor;
        comp_unit.length = *(unsigned long*)  comp_unit_stream->length;
        comp_unit.version = *(unsigned short*) comp_unit_stream->version;
        comp_unit.abbrev_offset = *(unsigned long*) comp_unit_stream->abbrev_offset;
        comp_unit.word_size = *(unsigned char*) comp_unit_stream->word_size;

        dwarf2_parse_compilation_unit(section, &comp_unit, module,
                                      thunks, comp_unit_cursor, load_offset);
        comp_unit_cursor += comp_unit.length + sizeof(unsigned);
    }
    module->module.SymType = SymDia;
    module->module.CVSig = 'D' | ('W' << 8) | ('A' << 16) | ('R' << 24);
    /* FIXME: we could have a finer grain here */
    module->module.GlobalSymbols = TRUE;
    module->module.TypeInfo = TRUE;
    module->module.SourceIndexed = TRUE;
    module->module.Publics = TRUE;
    return TRUE;
}

--- NEW FILE: dwarf.h ---
/*
 * dwarf2 definitions
 *
 * Copyright (C) 2005, Raphael Junqueira
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

typedef struct
{
  unsigned char length[4];
  unsigned char version[2];
  unsigned char abbrev_offset[4];
  unsigned char word_size[1];
} dwarf2_comp_unit_stream_t;

typedef struct
{
  unsigned long  length;
  unsigned short version;
  unsigned long  abbrev_offset;
  unsigned char  word_size;
} dwarf2_comp_unit_t;

typedef struct
{
  unsigned int   length;
  unsigned short version;
  unsigned int   prologue_length;
  unsigned char  min_insn_length;
  unsigned char  default_is_stmt;
  int            line_base;
  unsigned char  line_range;
  unsigned char  opcode_base;
} dwarf2_line_info_t;

typedef enum dwarf_tag_e
{
  DW_TAG_padding                        = 0x00,
  DW_TAG_array_type                     = 0x01,
  DW_TAG_class_type                     = 0x02,
  DW_TAG_entry_point                    = 0x03,
  DW_TAG_enumeration_type               = 0x04,
  DW_TAG_formal_parameter               = 0x05,
  DW_TAG_imported_declaration           = 0x08,
  DW_TAG_label                          = 0x0a,
  DW_TAG_lexical_block                  = 0x0b,
  DW_TAG_member                         = 0x0d,
  DW_TAG_pointer_type                   = 0x0f,
  DW_TAG_reference_type                 = 0x10,
  DW_TAG_compile_unit                   = 0x11,
  DW_TAG_string_type                    = 0x12,
  DW_TAG_structure_type                 = 0x13,
  DW_TAG_subroutine_type                = 0x15,
  DW_TAG_typedef                        = 0x16,
  DW_TAG_union_type                     = 0x17,
  DW_TAG_unspecified_parameters         = 0x18,
  DW_TAG_variant                        = 0x19,
  DW_TAG_common_block                   = 0x1a,
  DW_TAG_common_inclusion               = 0x1b,
  DW_TAG_inheritance                    = 0x1c,
  DW_TAG_inlined_subroutine             = 0x1d,
  DW_TAG_module                         = 0x1e,
  DW_TAG_ptr_to_member_type             = 0x1f,
  DW_TAG_set_type                       = 0x20,
  DW_TAG_subrange_type                  = 0x21,
  DW_TAG_with_stmt                      = 0x22,
  DW_TAG_access_declaration             = 0x23,
  DW_TAG_base_type                      = 0x24,
  DW_TAG_catch_block                    = 0x25,
  DW_TAG_const_type                     = 0x26,
  DW_TAG_constant                       = 0x27,
  DW_TAG_enumerator                     = 0x28,
  DW_TAG_file_type                      = 0x29,
  DW_TAG_friend                         = 0x2a,
  DW_TAG_namelist                       = 0x2b,
  DW_TAG_namelist_item                  = 0x2c,
  DW_TAG_packed_type                    = 0x2d,
  DW_TAG_subprogram                     = 0x2e,
  DW_TAG_template_type_param            = 0x2f,
  DW_TAG_template_value_param           = 0x30,
  DW_TAG_thrown_type                    = 0x31,
  DW_TAG_try_block                      = 0x32,
  DW_TAG_variant_part                   = 0x33,
  DW_TAG_variable                       = 0x34,
  DW_TAG_volatile_type                  = 0x35,
  /** extensions */
  DW_TAG_MIPS_loop                      = 0x4081,
  DW_TAG_format_label                   = 0x4101,
  DW_TAG_function_template              = 0x4102,
  DW_TAG_class_template                 = 0x4103
} dwarf_tag_t;

typedef enum dwarf_attribute_e
{
  DW_AT_sibling                         = 0x01,
  DW_AT_location                        = 0x02,
  DW_AT_name                            = 0x03,
  DW_AT_ordering                        = 0x09,
  DW_AT_subscr_data                     = 0x0a,
  DW_AT_byte_size                       = 0x0b,
  DW_AT_bit_offset                      = 0x0c,
  DW_AT_bit_size                        = 0x0d,
  DW_AT_element_list                    = 0x0f,
  DW_AT_stmt_list                       = 0x10,
  DW_AT_low_pc                          = 0x11,
  DW_AT_high_pc                         = 0x12,
  DW_AT_language                        = 0x13,
  DW_AT_member                          = 0x14,
  DW_AT_discr                           = 0x15,
  DW_AT_discr_value                     = 0x16,
  DW_AT_visibility                      = 0x17,
  DW_AT_import                          = 0x18,
  DW_AT_string_length                   = 0x19,
  DW_AT_common_reference                = 0x1a,
  DW_AT_comp_dir                        = 0x1b,
  DW_AT_const_value                     = 0x1c,
  DW_AT_containing_type                 = 0x1d,
  DW_AT_default_value                   = 0x1e,
  DW_AT_inline                          = 0x20,
  DW_AT_is_optional                     = 0x21,
  DW_AT_lower_bound                     = 0x22,
  DW_AT_producer                        = 0x25,
  DW_AT_prototyped                      = 0x27,
  DW_AT_return_addr                     = 0x2a,
  DW_AT_start_scope                     = 0x2c,
  DW_AT_stride_size                     = 0x2e,
  DW_AT_upper_bound                     = 0x2f,
  DW_AT_abstract_origin                 = 0x31,
  DW_AT_accessibility                   = 0x32,
  DW_AT_address_class                   = 0x33,
  DW_AT_artificial                      = 0x34,
  DW_AT_base_types                      = 0x35,
  DW_AT_calling_convention              = 0x36,
  DW_AT_count                           = 0x37,
  DW_AT_data_member_location            = 0x38,
  DW_AT_decl_column                     = 0x39,
  DW_AT_decl_file                       = 0x3a,
  DW_AT_decl_line                       = 0x3b,
  DW_AT_declaration                     = 0x3c,
  DW_AT_discr_list                      = 0x3d,
  DW_AT_encoding                        = 0x3e,
  DW_AT_external                        = 0x3f,
  DW_AT_frame_base                      = 0x40,
  DW_AT_friend                          = 0x41,
  DW_AT_identifier_case                 = 0x42,
  DW_AT_macro_info                      = 0x43,
  DW_AT_namelist_items                  = 0x44,
  DW_AT_priority                        = 0x45,
  DW_AT_segment                         = 0x46,
  DW_AT_specification                   = 0x47,
  DW_AT_static_link                     = 0x48,
  DW_AT_type                            = 0x49,
  DW_AT_use_location                    = 0x4a,
  DW_AT_variable_parameter              = 0x4b,
  DW_AT_virtuality                      = 0x4c,
  DW_AT_vtable_elem_location            = 0x4d,

  DW_AT_ranges                          = 0x55,
  /* extensions */
  DW_AT_MIPS_fde                        = 0x2001,
  DW_AT_MIPS_loop_begin                 = 0x2002,
  DW_AT_MIPS_tail_loop_begin            = 0x2003,
  DW_AT_MIPS_epilog_begin               = 0x2004,
  DW_AT_MIPS_loop_unroll_factor         = 0x2005,
  DW_AT_MIPS_software_pipeline_depth    = 0x2006,
  DW_AT_MIPS_linkage_name               = 0x2007,
  DW_AT_MIPS_stride                     = 0x2008,
  DW_AT_MIPS_abstract_name              = 0x2009,
  DW_AT_MIPS_clone_origin               = 0x200a,
  DW_AT_MIPS_has_inlines                = 0x200b,
  DW_AT_sf_names                        = 0x2101,
  DW_AT_src_info                        = 0x2102,
  DW_AT_mac_info                        = 0x2103,
  DW_AT_src_coords                      = 0x2104,
  DW_AT_body_begin                      = 0x2105,
  DW_AT_body_end                        = 0x2106
} dwarf_attribute_t;

typedef enum dwarf_form_e
{
  DW_FORM_addr                          = 0x01,
  DW_FORM_block2                        = 0x03,
  DW_FORM_block4                        = 0x04,
  DW_FORM_data2                         = 0x05,
  DW_FORM_data4                         = 0x06,
  DW_FORM_data8                         = 0x07,
  DW_FORM_string                        = 0x08,
  DW_FORM_block                         = 0x09,
  DW_FORM_block1                        = 0x0a,
  DW_FORM_data1                         = 0x0b,
  DW_FORM_flag                          = 0x0c,
  DW_FORM_sdata                         = 0x0d,
  DW_FORM_strp                          = 0x0e,
  DW_FORM_udata                         = 0x0f,
  DW_FORM_ref_addr                      = 0x10,
  DW_FORM_ref1                          = 0x11,
  DW_FORM_ref2                          = 0x12,
  DW_FORM_ref4                          = 0x13,
  DW_FORM_ref8                          = 0x14,
  DW_FORM_ref_udata                     = 0x15,
  DW_FORM_indirect                      = 0x16
} dwarf_form_t;

/** type encoding */
typedef enum dwarf_type_e
{
  DW_ATE_void                           = 0x0,
  DW_ATE_address                        = 0x1,
  DW_ATE_boolean                        = 0x2,
  DW_ATE_complex_float                  = 0x3,
  DW_ATE_float                          = 0x4,
  DW_ATE_signed                         = 0x5,
  DW_ATE_signed_char                    = 0x6,
  DW_ATE_unsigned                       = 0x7,
  DW_ATE_unsigned_char                  = 0x8
} dwarf_type_t;

typedef enum dwarf_operation_e
{
  DW_OP_addr                            = 0x03,
  DW_OP_deref                           = 0x06,
  DW_OP_const1u                         = 0x08,
  DW_OP_const1s                         = 0x09,
  DW_OP_const2u                         = 0x0a,
  DW_OP_const2s                         = 0x0b,
  DW_OP_const4u                         = 0x0c,
  DW_OP_const4s                         = 0x0d,
  DW_OP_const8u                         = 0x0e,
  DW_OP_const8s                         = 0x0f,
  DW_OP_constu                          = 0x10,
  DW_OP_consts                          = 0x11,
  DW_OP_dup                             = 0x12,
  DW_OP_drop                            = 0x13,
  DW_OP_over                            = 0x14,
  DW_OP_pick                            = 0x15,
  DW_OP_swap                            = 0x16,
  DW_OP_rot                             = 0x17,
  DW_OP_xderef                          = 0x18,
  DW_OP_abs                             = 0x19,
  DW_OP_and                             = 0x1a,
  DW_OP_div                             = 0x1b,
  DW_OP_minus                           = 0x1c,
  DW_OP_mod                             = 0x1d,
  DW_OP_mul                             = 0x1e,
  DW_OP_neg                             = 0x1f,
  DW_OP_not                             = 0x20,
  DW_OP_or                              = 0x21,
  DW_OP_plus                            = 0x22,
  DW_OP_plus_uconst                     = 0x23,
  DW_OP_shl                             = 0x24,
  DW_OP_shr                             = 0x25,
  DW_OP_shra                            = 0x26,
  DW_OP_xor                             = 0x27,
  DW_OP_bra                             = 0x28,
  DW_OP_eq                              = 0x29,
  DW_OP_ge                              = 0x2a,
  DW_OP_gt                              = 0x2b,
  DW_OP_le                              = 0x2c,
  DW_OP_lt                              = 0x2d,
  DW_OP_ne                              = 0x2e,
  DW_OP_skip                            = 0x2f,
  DW_OP_lit0                            = 0x30,
  DW_OP_lit1                            = 0x31,
  DW_OP_lit2                            = 0x32,
  DW_OP_lit3                            = 0x33,
  DW_OP_lit4                            = 0x34,
  DW_OP_lit5                            = 0x35,
  DW_OP_lit6                            = 0x36,
  DW_OP_lit7                            = 0x37,
  DW_OP_lit8                            = 0x38,
  DW_OP_lit9                            = 0x39,
  DW_OP_lit10                           = 0x3a,
  DW_OP_lit11                           = 0x3b,
  DW_OP_lit12                           = 0x3c,
  DW_OP_lit13                           = 0x3d,
  DW_OP_lit14                           = 0x3e,
  DW_OP_lit15                           = 0x3f,
  DW_OP_lit16                           = 0x40,
  DW_OP_lit17                           = 0x41,
  DW_OP_lit18                           = 0x42,
  DW_OP_lit19                           = 0x43,
  DW_OP_lit20                           = 0x44,
  DW_OP_lit21                           = 0x45,
  DW_OP_lit22                           = 0x46,
  DW_OP_lit23                           = 0x47,
  DW_OP_lit24                           = 0x48,
  DW_OP_lit25                           = 0x49,
  DW_OP_lit26                           = 0x4a,
  DW_OP_lit27                           = 0x4b,
  DW_OP_lit28                           = 0x4c,
  DW_OP_lit29                           = 0x4d,
  DW_OP_lit30                           = 0x4e,
  DW_OP_lit31                           = 0x4f,
  DW_OP_reg0                            = 0x50,
  DW_OP_reg1                            = 0x51,
  DW_OP_reg2                            = 0x52,
  DW_OP_reg3                            = 0x53,
  DW_OP_reg4                            = 0x54,
  DW_OP_reg5                            = 0x55,
  DW_OP_reg6                            = 0x56,
  DW_OP_reg7                            = 0x57,
  DW_OP_reg8                            = 0x58,
  DW_OP_reg9                            = 0x59,
  DW_OP_reg10                           = 0x5a,
  DW_OP_reg11                           = 0x5b,
  DW_OP_reg12                           = 0x5c,
  DW_OP_reg13                           = 0x5d,
  DW_OP_reg14                           = 0x5e,
  DW_OP_reg15                           = 0x5f,
  DW_OP_reg16                           = 0x60,
  DW_OP_reg17                           = 0x61,
  DW_OP_reg18                           = 0x62,
  DW_OP_reg19                           = 0x63,
  DW_OP_reg20                           = 0x64,
  DW_OP_reg21                           = 0x65,
  DW_OP_reg22                           = 0x66,
  DW_OP_reg23                           = 0x67,
  DW_OP_reg24                           = 0x68,
  DW_OP_reg25                           = 0x69,
  DW_OP_reg26                           = 0x6a,
  DW_OP_reg27                           = 0x6b,
  DW_OP_reg28                           = 0x6c,
  DW_OP_reg29                           = 0x6d,
  DW_OP_reg30                           = 0x6e,
  DW_OP_reg31                           = 0x6f,
  DW_OP_breg0                           = 0x70,
  DW_OP_breg1                           = 0x71,
  DW_OP_breg2                           = 0x72,
  DW_OP_breg3                           = 0x73,
  DW_OP_breg4                           = 0x74,
  DW_OP_breg5                           = 0x75,
  DW_OP_breg6                           = 0x76,
  DW_OP_breg7                           = 0x77,
  DW_OP_breg8                           = 0x78,
  DW_OP_breg9                           = 0x79,
  DW_OP_breg10                          = 0x7a,
  DW_OP_breg11                          = 0x7b,
  DW_OP_breg12                          = 0x7c,
  DW_OP_breg13                          = 0x7d,
  DW_OP_breg14                          = 0x7e,
  DW_OP_breg15                          = 0x7f,
  DW_OP_breg16                          = 0x80,
  DW_OP_breg17                          = 0x81,
  DW_OP_breg18                          = 0x82,
  DW_OP_breg19                          = 0x83,
  DW_OP_breg20                          = 0x84,
  DW_OP_breg21                          = 0x85,
  DW_OP_breg22                          = 0x86,
  DW_OP_breg23                          = 0x87,
  DW_OP_breg24                          = 0x88,
  DW_OP_breg25                          = 0x89,
  DW_OP_breg26                          = 0x8a,
  DW_OP_breg27                          = 0x8b,
  DW_OP_breg28                          = 0x8c,
  DW_OP_breg29                          = 0x8d,
  DW_OP_breg30                          = 0x8e,
  DW_OP_breg31                          = 0x8f,
  DW_OP_regx                            = 0x90,
  DW_OP_fbreg                           = 0x91,
  DW_OP_bregx                           = 0x92,
  DW_OP_piece                           = 0x93,
  DW_OP_deref_size                      = 0x94,
  DW_OP_xderef_size                     = 0x95,
  DW_OP_nop                             = 0x96
} dwarf_operation_t;

enum dwarf_calling_convention
{
    DW_CC_normal                        = 0x1,
    DW_CC_program                       = 0x2,
    DW_CC_nocall                        = 0x3
};

#define DW_CC_lo_user 0x40
#define DW_CC_hi_user 0xff

#define DW_LNS_extended_op              0x00
#define DW_LNS_copy                     0x01
#define DW_LNS_advance_pc               0x02
#define DW_LNS_advance_line             0x03
#define DW_LNS_set_file                 0x04
#define DW_LNS_set_column               0x05
#define DW_LNS_negate_stmt              0x06
#define DW_LNS_set_basic_block          0x07
#define DW_LNS_const_add_pc             0x08
#define DW_LNS_fixed_advance_pc         0x09

#define DW_LNE_end_sequence             0x01
#define DW_LNE_set_address              0x02
#define DW_LNE_define_file              0x03

--- NEW FILE: elf_module.c ---
/*
 * File elf.c - processing of ELF files
 *
 * Copyright (C) 1996, Eric Youngdale.
 *		 1999-2007 Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
[...1622 lines suppressed...]
{
    return FALSE;
}

struct module*  elf_load_module(struct process* pcs, const WCHAR* name, unsigned long addr)
{
    return NULL;
}

BOOL elf_load_debug_info(struct module* module, struct elf_file_map* fmap)
{
    return FALSE;
}

int elf_is_in_thunk_area(unsigned long addr,
                         const struct elf_thunk_area* thunks)
{
    return -1;
}
#endif  /* __ELF__ */

--- NEW FILE: image.c ---
/*
 * File image.c - managing images
 *
 * Copyright (C) 2004, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "dbghelp_private.h"
#include "winternl.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

/***********************************************************************
 *		GetTimestampForLoadedLibrary (DBGHELP.@)
 */
DWORD WINAPI GetTimestampForLoadedLibrary(HMODULE Module)
{
    IMAGE_NT_HEADERS*   nth = RtlImageNtHeader(Module);
    return (nth) ? nth->FileHeader.TimeDateStamp : 0;
}

/***********************************************************************
 *		MapDebugInformation (DBGHELP.@)
 */
PIMAGE_DEBUG_INFORMATION WINAPI MapDebugInformation(HANDLE FileHandle, LPSTR FileName,
                                                    LPSTR SymbolPath, DWORD ImageBase)
{
    FIXME("(%p, %s, %s, 0x%08x): stub\n", FileHandle, FileName, SymbolPath, ImageBase);
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return NULL;
}

/***********************************************************************
 *		UnmapDebugInformation (DBGHELP.@)
 */
BOOL WINAPI UnmapDebugInformation(PIMAGE_DEBUG_INFORMATION DebugInfo)
{
    FIXME("(%p): stub\n", DebugInfo);
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
}

Index: Makefile.in
===================================================================
RCS file: /var/lib/cvsd/cvsroot/winex/dlls/dbghelp/Makefile.in,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- Makefile.in	30 Mar 2007 19:52:41 -0000	1.1
+++ Makefile.in	30 Aug 2007 14:15:59 -0000	1.2
@@ -2,11 +2,29 @@
 TOPOBJDIR = ../..
 SRCDIR    = @srcdir@
 VPATH     = @srcdir@
-MODULE    = dbghelp
-
-LDDLLFLAGS = @LDDLLFLAGS@
-SYMBOLFILE = $(MODULE).tmp.o
+MODULE    = dbghelp.dll
+IMPORTLIB = libdbghelp.$(IMPLIBEXT)
+IMPORTS   = psapi kernel32 ntdll
 
-C_SRCS = dbghelp.c
+C_SRCS = \
+	coff.c \
+	dbghelp.c \
+	dwarf.c \
+	elf_module.c \
+	image.c \
+	memory.c \
+	minidump.c \
+	module.c \
+	msc.c \
+	path.c \
+	pe_module.c \
+	source.c \
+	stabs.c \
+	stack.c \
+	storage.c \
+	symbol.c \
+	type.c
 
 @MAKE_DLL_RULES@
+
+@DEPENDENCIES@  # everything below this line is overwritten by make depend

--- NEW FILE: memory.c ---
/*
 * File memory.c - managing memory
 *
 * Copyright (C) 2004, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"

#include <assert.h>
#include "dbghelp_private.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

/******************************************************************
 *		addr_to_linear
 *
 * converts an address into its linear value
 */
DWORD WINAPI addr_to_linear(HANDLE hProcess, HANDLE hThread, ADDRESS* addr)
{
    LDT_ENTRY	le;

    switch (addr->Mode)
    {
    case AddrMode1616:
        if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
            return (le.HighWord.Bits.BaseHi << 24) + 
                (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + LOWORD(addr->Offset);
        break;
    case AddrMode1632:
        if (GetThreadSelectorEntry(hThread, addr->Segment, &le))
            return (le.HighWord.Bits.BaseHi << 24) + 
                (le.HighWord.Bits.BaseMid << 16) + le.BaseLow + addr->Offset;
        break;
    case AddrModeReal:
        return (DWORD)(LOWORD(addr->Segment) << 4) + addr->Offset;
    case AddrModeFlat:
        return addr->Offset;
    default:
        FIXME("Unsupported (yet) mode (%x)\n", addr->Mode);
        return 0;
    }
    FIXME("Failed to linearize address %04x:%08x (mode %x)\n",
          addr->Segment, addr->Offset, addr->Mode);
    return 0;
}

--- NEW FILE: minidump.c ---
/*
 * File minidump.c - management of dumps (read & write)
 *
 * Copyright (C) 2004-2005, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <time.h>

#define NONAMELESSUNION
#define NONAMELESSSTRUCT

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "dbghelp_private.h"
#include "winternl.h"
#include "psapi.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

struct dump_memory
{
    ULONG                               base;
    ULONG                               size;
    ULONG                               rva;
};

struct dump_module
{
    unsigned                            is_elf;
    ULONG                               base;
    ULONG                               size;
    DWORD                               timestamp;
    DWORD                               checksum;
    WCHAR                               name[MAX_PATH];
};

struct dump_context
{
    /* process & thread information */
    HANDLE                              hProcess;
    DWORD                               pid;
    void*                               pcs_buffer;
    SYSTEM_PROCESS_INFORMATION*         spi;
    /* module information */
    struct dump_module*                 module;
    unsigned                            num_module;
    /* exception information */
    /* output information */
    MINIDUMP_TYPE                       type;
    HANDLE                              hFile;
    RVA                                 rva;
    struct dump_memory*                 mem;
    unsigned                            num_mem;
    /* callback information */
    MINIDUMP_CALLBACK_INFORMATION*      cb;
};

/******************************************************************
 *		fetch_process_info
 *
 * reads system wide process information, and make spi point to the record
 * for process of id 'pid'
 */
static BOOL fetch_process_info(struct dump_context* dc)
{
    ULONG       buf_size = 0x1000;
    NTSTATUS    nts;

    dc->pcs_buffer = NULL;
    if (!(dc->pcs_buffer = HeapAlloc(GetProcessHeap(), 0, buf_size))) return FALSE;
    for (;;)
    {
        nts = NtQuerySystemInformation(SystemProcessInformation, 
                                       dc->pcs_buffer, buf_size, NULL);
        if (nts != STATUS_INFO_LENGTH_MISMATCH) break;
        dc->pcs_buffer = HeapReAlloc(GetProcessHeap(), 0, dc->pcs_buffer, 
                                     buf_size *= 2);
        if (!dc->pcs_buffer) return FALSE;
    }

    if (nts == STATUS_SUCCESS)
    {
        dc->spi = dc->pcs_buffer;
        for (;;)
        {
            if (dc->spi->dwProcessID == dc->pid) return TRUE;
            if (!dc->spi->dwOffset) break;
            dc->spi = (SYSTEM_PROCESS_INFORMATION*)     
                ((char*)dc->spi + dc->spi->dwOffset);
        }
    }
    HeapFree(GetProcessHeap(), 0, dc->pcs_buffer);
    dc->pcs_buffer = NULL;
    dc->spi = NULL;
    return FALSE;
}

static void fetch_thread_stack(struct dump_context* dc, const void* teb_addr,
                               const CONTEXT* ctx, MINIDUMP_MEMORY_DESCRIPTOR* mmd)
{
    NT_TIB      tib;

    if (ReadProcessMemory(dc->hProcess, teb_addr, &tib, sizeof(tib), NULL))
    {
#ifdef __i386__
        /* limiting the stack dumping to the size actually used */
        if (ctx->Esp)
            mmd->StartOfMemoryRange = (ctx->Esp - 4);
        else
            mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
#elif defined(__powerpc__)
        if (ctx->Iar)
            mmd->StartOfMemoryRange = ctx->Iar - 4;
        else
            mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
#elif defined(__x86_64__)
        if (ctx->Rsp)
            mmd->StartOfMemoryRange = (ctx->Rsp - 8);
        else
            mmd->StartOfMemoryRange = (ULONG_PTR)tib.StackLimit;
#else
#error unsupported CPU
#endif
        mmd->Memory.DataSize = (ULONG_PTR)tib.StackBase - mmd->StartOfMemoryRange;
    }
}

/******************************************************************
 *		fetch_thread_info
 *
 * fetches some information about thread of id 'tid'
 */
static BOOL fetch_thread_info(struct dump_context* dc, int thd_idx,
                              const MINIDUMP_EXCEPTION_INFORMATION* except,
                              MINIDUMP_THREAD* mdThd, CONTEXT* ctx)
{
    DWORD                       tid = dc->spi->ti[thd_idx].dwThreadID;
    HANDLE                      hThread;
    THREAD_BASIC_INFORMATION    tbi;

    memset(ctx, 0, sizeof(*ctx));

    mdThd->ThreadId = dc->spi->ti[thd_idx].dwThreadID;
    mdThd->SuspendCount = 0;
    mdThd->Teb = 0;
    mdThd->Stack.StartOfMemoryRange = 0;
    mdThd->Stack.Memory.DataSize = 0;
    mdThd->Stack.Memory.Rva = 0;
    mdThd->ThreadContext.DataSize = 0;
    mdThd->ThreadContext.Rva = 0;
    mdThd->PriorityClass = dc->spi->ti[thd_idx].dwBasePriority; /* FIXME */
    mdThd->Priority = dc->spi->ti[thd_idx].dwCurrentPriority;

    if ((hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, tid)) == NULL)
    {
        FIXME("Couldn't open thread %u (%u)\n",
              dc->spi->ti[thd_idx].dwThreadID, GetLastError());
        return FALSE;
    }
    
    if (NtQueryInformationThread(hThread, ThreadBasicInformation,
                                 &tbi, sizeof(tbi), NULL) == STATUS_SUCCESS)
    {
        mdThd->Teb = (ULONG_PTR)tbi.TebBaseAddress;
        if (tbi.ExitStatus == STILL_ACTIVE)
        {
            if (tid != GetCurrentThreadId() &&
                (mdThd->SuspendCount = SuspendThread(hThread)) != (DWORD)-1)
            {
                mdThd->SuspendCount--;
                ctx->ContextFlags = CONTEXT_FULL;
                if (!GetThreadContext(hThread, ctx))
                    memset(ctx, 0, sizeof(*ctx));

                fetch_thread_stack(dc, tbi.TebBaseAddress, ctx, &mdThd->Stack);
                ResumeThread(hThread);
            }
            else if (tid == GetCurrentThreadId() && except)
            {
                CONTEXT lctx, *pctx;
                if (except->ClientPointers)
                {
                    EXCEPTION_POINTERS      ep;

                    ReadProcessMemory(dc->hProcess, except->ExceptionPointers,
                                      &ep, sizeof(ep), NULL);
                    ReadProcessMemory(dc->hProcess, ep.ContextRecord,
                                      &ctx, sizeof(ctx), NULL);
                    pctx = &lctx;
                }
                else pctx = except->ExceptionPointers->ContextRecord;
                fetch_thread_stack(dc, tbi.TebBaseAddress, pctx, &mdThd->Stack);
            }
        }
    }
    CloseHandle(hThread);
    return TRUE;
}

/******************************************************************
 *		add_module
 *
 * Add a module to a dump context
 */
static BOOL add_module(struct dump_context* dc, const WCHAR* name,
                       DWORD base, DWORD size, DWORD timestamp, DWORD checksum,
                       BOOL is_elf)
{
    if (!dc->module)
        dc->module = HeapAlloc(GetProcessHeap(), 0,
                               ++dc->num_module * sizeof(*dc->module));
    else
        dc->module = HeapReAlloc(GetProcessHeap(), 0, dc->module,
                                 ++dc->num_module * sizeof(*dc->module));
    if (!dc->module) return FALSE;
    if (is_elf ||
        !GetModuleFileNameExW(dc->hProcess, (HMODULE)base,
                              dc->module[dc->num_module - 1].name,
                              sizeof(dc->module[dc->num_module - 1].name) / sizeof(WCHAR)))
        lstrcpynW(dc->module[dc->num_module - 1].name, name,
                  sizeof(dc->module[dc->num_module - 1].name) / sizeof(WCHAR));
    dc->module[dc->num_module - 1].base = base;
    dc->module[dc->num_module - 1].size = size;
    dc->module[dc->num_module - 1].timestamp = timestamp;
    dc->module[dc->num_module - 1].checksum = checksum;
    dc->module[dc->num_module - 1].is_elf = is_elf;

    return TRUE;
}

/******************************************************************
 *		fetch_pe_module_info_cb
 *
 * Callback for accumulating in dump_context a PE modules set
 */
static BOOL WINAPI fetch_pe_module_info_cb(WCHAR* name, DWORD64 base, DWORD size,
                                           void* user)
{
    struct dump_context*        dc = (struct dump_context*)user;
    IMAGE_NT_HEADERS            nth;

    if (!validate_addr64(base)) return FALSE;

    if (pe_load_nt_header(dc->hProcess, base, &nth))
        add_module((struct dump_context*)user, name, base, size,
                   nth.FileHeader.TimeDateStamp, nth.OptionalHeader.CheckSum,
                   FALSE);
    return TRUE;
}

/******************************************************************
 *		fetch_elf_module_info_cb
 *
 * Callback for accumulating in dump_context an ELF modules set
 */
static BOOL fetch_elf_module_info_cb(const WCHAR* name, unsigned long base,
                                     void* user)
{
    struct dump_context*        dc = (struct dump_context*)user;
    DWORD                       rbase, size, checksum;

    /* FIXME: there's no relevant timestamp on ELF modules */
    /* NB: if we have a non-null base from the live-target use it (whenever
     * the ELF module is relocatable or not). If we have a null base (ELF
     * module isn't relocatable) then grab its base address from ELF file
     */
    if (!elf_fetch_file_info(name, &rbase, &size, &checksum))
        size = checksum = 0;
    add_module(dc, name, base ? base : rbase, size, 0 /* FIXME */, checksum, TRUE);
    return TRUE;
}

static void fetch_module_info(struct dump_context* dc)
{
    EnumerateLoadedModulesW64(dc->hProcess, fetch_pe_module_info_cb, dc);
    /* Since we include ELF modules in a separate stream from the regular PE ones,
     * we can always include those ELF modules (they don't eat lots of space)
     * And it's always a good idea to have a trace of the loaded ELF modules for
     * a given application in a post mortem debugging condition.
     */
    elf_enum_modules(dc->hProcess, fetch_elf_module_info_cb, dc);
}

/******************************************************************
 *		add_memory_block
 *
 * Add a memory block to be dumped in a minidump
 * If rva is non 0, it's the rva in the minidump where has to be stored
 * also the rva of the memory block when written (this allows to reference
 * a memory block from outside the list of memory blocks).
 */
static void add_memory_block(struct dump_context* dc, ULONG64 base, ULONG size, ULONG rva)
{
    if (dc->mem)
        dc->mem = HeapReAlloc(GetProcessHeap(), 0, dc->mem, 
                              ++dc->num_mem * sizeof(*dc->mem));
    else
        dc->mem = HeapAlloc(GetProcessHeap(), 0, ++dc->num_mem * sizeof(*dc->mem));
    if (dc->mem)
    {
        dc->mem[dc->num_mem - 1].base = base;
        dc->mem[dc->num_mem - 1].size = size;
        dc->mem[dc->num_mem - 1].rva  = rva;
    }
    else dc->num_mem = 0;
}

/******************************************************************
 *		writeat
 *
 * Writes a chunk of data at a given position in the minidump
 */
static void writeat(struct dump_context* dc, RVA rva, const void* data, unsigned size)
{
    DWORD       written;

    SetFilePointer(dc->hFile, rva, NULL, FILE_BEGIN);
    WriteFile(dc->hFile, data, size, &written, NULL);
}

/******************************************************************
 *		append
 *
 * writes a new chunk of data to the minidump, increasing the current
 * rva in dc
 */
static void append(struct dump_context* dc, void* data, unsigned size)
{
    writeat(dc, dc->rva, data, size);
    dc->rva += size;
}

/******************************************************************
 *		dump_exception_info
 *
 * Write in File the exception information from pcs
 */
static  void    dump_exception_info(struct dump_context* dc,
                                    const MINIDUMP_EXCEPTION_INFORMATION* except)
{
    MINIDUMP_EXCEPTION_STREAM   mdExcpt;
    EXCEPTION_RECORD            rec, *prec;
    CONTEXT                     ctx, *pctx;
    int                         i;

    mdExcpt.ThreadId = except->ThreadId;
    mdExcpt.__alignment = 0;
    if (except->ClientPointers)
    {
        EXCEPTION_POINTERS      ep;

        ReadProcessMemory(dc->hProcess, 
                          except->ExceptionPointers, &ep, sizeof(ep), NULL);
        ReadProcessMemory(dc->hProcess, 
                          ep.ExceptionRecord, &rec, sizeof(rec), NULL);
        ReadProcessMemory(dc->hProcess, 
                          ep.ContextRecord, &ctx, sizeof(ctx), NULL);
        prec = &rec;
        pctx = &ctx;
    }
    else
    {
        prec = except->ExceptionPointers->ExceptionRecord;
        pctx = except->ExceptionPointers->ContextRecord;
    }
    mdExcpt.ExceptionRecord.ExceptionCode = prec->ExceptionCode;
    mdExcpt.ExceptionRecord.ExceptionFlags = prec->ExceptionFlags;
    mdExcpt.ExceptionRecord.ExceptionRecord = (DWORD_PTR)prec->ExceptionRecord;
    mdExcpt.ExceptionRecord.ExceptionAddress = (DWORD_PTR)prec->ExceptionAddress;
    mdExcpt.ExceptionRecord.NumberParameters = prec->NumberParameters;
    mdExcpt.ExceptionRecord.__unusedAlignment = 0;
    for (i = 0; i < mdExcpt.ExceptionRecord.NumberParameters; i++)
        mdExcpt.ExceptionRecord.ExceptionInformation[i] = (DWORD_PTR)prec->ExceptionInformation[i];
    mdExcpt.ThreadContext.DataSize = sizeof(*pctx);
    mdExcpt.ThreadContext.Rva = dc->rva + sizeof(mdExcpt);

    append(dc, &mdExcpt, sizeof(mdExcpt));
    append(dc, pctx, sizeof(*pctx));
}

/******************************************************************
 *		dump_modules
 *
 * Write in File the modules from pcs
 */
static  void    dump_modules(struct dump_context* dc, BOOL dump_elf)
{
    MINIDUMP_MODULE             mdModule;
    MINIDUMP_MODULE_LIST        mdModuleList;
    char                        tmp[1024];
    MINIDUMP_STRING*            ms = (MINIDUMP_STRING*)tmp;
    ULONG                       i, nmod;
    RVA                         rva_base;
    DWORD                       flags_out;

    for (i = nmod = 0; i < dc->num_module; i++)
    {
        if ((dc->module[i].is_elf && dump_elf) ||
            (!dc->module[i].is_elf && !dump_elf))
            nmod++;
    }

    mdModuleList.NumberOfModules = 0;
    /* reserve space for mdModuleList
     * FIXME: since we don't support 0 length arrays, we cannot use the
     * size of mdModuleList
     * FIXME: if we don't ask for all modules in cb, we'll get a hole in the file
     */
    rva_base = dc->rva;
    dc->rva += sizeof(mdModuleList.NumberOfModules) + sizeof(mdModule) * nmod;
    for (i = 0; i < dc->num_module; i++)
    {
        if ((dc->module[i].is_elf && !dump_elf) ||
            (!dc->module[i].is_elf && dump_elf))
            continue;

        flags_out = ModuleWriteModule | ModuleWriteMiscRecord | ModuleWriteCvRecord;
        if (dc->type & MiniDumpWithDataSegs)
            flags_out |= ModuleWriteDataSeg;
        if (dc->type & MiniDumpWithProcessThreadData)
            flags_out |= ModuleWriteTlsData;
        if (dc->type & MiniDumpWithCodeSegs)
            flags_out |= ModuleWriteCodeSegs;
        ms->Length = (lstrlenW(dc->module[i].name) + 1) * sizeof(WCHAR);
        if (sizeof(ULONG) + ms->Length > sizeof(tmp))
            FIXME("Buffer overflow!!!\n");
        lstrcpyW(ms->Buffer, dc->module[i].name);

        if (dc->cb)
        {
            MINIDUMP_CALLBACK_INPUT     cbin;
            MINIDUMP_CALLBACK_OUTPUT    cbout;

            cbin.ProcessId = dc->pid;
            cbin.ProcessHandle = dc->hProcess;
            cbin.CallbackType = ModuleCallback;

            cbin.u.Module.FullPath = ms->Buffer;
            cbin.u.Module.BaseOfImage = dc->module[i].base;
            cbin.u.Module.SizeOfImage = dc->module[i].size;
            cbin.u.Module.CheckSum = dc->module[i].checksum;
            cbin.u.Module.TimeDateStamp = dc->module[i].timestamp;
            memset(&cbin.u.Module.VersionInfo, 0, sizeof(cbin.u.Module.VersionInfo));
            cbin.u.Module.CvRecord = NULL;
            cbin.u.Module.SizeOfCvRecord = 0;
            cbin.u.Module.MiscRecord = NULL;
            cbin.u.Module.SizeOfMiscRecord = 0;

            cbout.u.ModuleWriteFlags = flags_out;
            if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
                continue;
            flags_out &= cbout.u.ModuleWriteFlags;
        }
        if (flags_out & ModuleWriteModule)
        {
            mdModule.BaseOfImage = dc->module[i].base;
            mdModule.SizeOfImage = dc->module[i].size;
            mdModule.CheckSum = dc->module[i].checksum;
            mdModule.TimeDateStamp = dc->module[i].timestamp;
            mdModule.ModuleNameRva = dc->rva;
            ms->Length -= sizeof(WCHAR);
            append(dc, ms, sizeof(ULONG) + ms->Length + sizeof(WCHAR));
            memset(&mdModule.VersionInfo, 0, sizeof(mdModule.VersionInfo)); /* FIXME */
            mdModule.CvRecord.DataSize = 0; /* FIXME */
            mdModule.CvRecord.Rva = 0; /* FIXME */
            mdModule.MiscRecord.DataSize = 0; /* FIXME */
            mdModule.MiscRecord.Rva = 0; /* FIXME */
            mdModule.Reserved0 = 0; /* FIXME */
            mdModule.Reserved1 = 0; /* FIXME */
            writeat(dc,
                    rva_base + sizeof(mdModuleList.NumberOfModules) + 
                        mdModuleList.NumberOfModules++ * sizeof(mdModule), 
                    &mdModule, sizeof(mdModule));
        }
    }
    writeat(dc, rva_base, &mdModuleList.NumberOfModules, 
            sizeof(mdModuleList.NumberOfModules));
}

/******************************************************************
 *		dump_system_info
 *
 * Dumps into File the information about the system
 */
static  void    dump_system_info(struct dump_context* dc)
{
    MINIDUMP_SYSTEM_INFO        mdSysInfo;
    SYSTEM_INFO                 sysInfo;
    OSVERSIONINFOW              osInfo;
    DWORD                       written;
    ULONG                       slen;

    GetSystemInfo(&sysInfo);
    osInfo.dwOSVersionInfoSize = sizeof(osInfo);
    GetVersionExW(&osInfo);

    mdSysInfo.ProcessorArchitecture = sysInfo.u.s.wProcessorArchitecture;
    mdSysInfo.ProcessorLevel = sysInfo.wProcessorLevel;
    mdSysInfo.ProcessorRevision = sysInfo.wProcessorRevision;
    mdSysInfo.u.s.NumberOfProcessors = sysInfo.dwNumberOfProcessors;
    mdSysInfo.u.s.ProductType = VER_NT_WORKSTATION; /* FIXME */
    mdSysInfo.MajorVersion = osInfo.dwMajorVersion;
    mdSysInfo.MinorVersion = osInfo.dwMinorVersion;
    mdSysInfo.BuildNumber = osInfo.dwBuildNumber;
    mdSysInfo.PlatformId = osInfo.dwPlatformId;

    mdSysInfo.CSDVersionRva = dc->rva + sizeof(mdSysInfo);
    mdSysInfo.u1.Reserved1 = 0;

    memset(&mdSysInfo.Cpu, 0, sizeof(mdSysInfo.Cpu));

    append(dc, &mdSysInfo, sizeof(mdSysInfo));

    slen = lstrlenW(osInfo.szCSDVersion) * sizeof(WCHAR);
    WriteFile(dc->hFile, &slen, sizeof(slen), &written, NULL);
    WriteFile(dc->hFile, osInfo.szCSDVersion, slen, &written, NULL);
    dc->rva += sizeof(ULONG) + slen;
}

/******************************************************************
 *		dump_threads
 *
 * Dumps into File the information about running threads
 */
static  void    dump_threads(struct dump_context* dc,
                             const MINIDUMP_EXCEPTION_INFORMATION* except)
{
    MINIDUMP_THREAD             mdThd;
    MINIDUMP_THREAD_LIST        mdThdList;
    unsigned                    i;
    RVA                         rva_base;
    DWORD                       flags_out;
    CONTEXT                     ctx;

    mdThdList.NumberOfThreads = 0;

    rva_base = dc->rva;
    dc->rva += sizeof(mdThdList.NumberOfThreads) +
        dc->spi->dwThreadCount * sizeof(mdThd);

    for (i = 0; i < dc->spi->dwThreadCount; i++)
    {
        fetch_thread_info(dc, i, except, &mdThd, &ctx);

        flags_out = ThreadWriteThread | ThreadWriteStack | ThreadWriteContext |
            ThreadWriteInstructionWindow;
        if (dc->type & MiniDumpWithProcessThreadData)
            flags_out |= ThreadWriteThreadData;
        if (dc->type & MiniDumpWithThreadInfo)
            flags_out |= ThreadWriteThreadInfo;

        if (dc->cb)
        {
            MINIDUMP_CALLBACK_INPUT     cbin;
            MINIDUMP_CALLBACK_OUTPUT    cbout;

            cbin.ProcessId = dc->pid;
            cbin.ProcessHandle = dc->hProcess;
            cbin.CallbackType = ThreadCallback;
            cbin.u.Thread.ThreadId = dc->spi->ti[i].dwThreadID;
            cbin.u.Thread.ThreadHandle = 0; /* FIXME */
            memcpy(&cbin.u.Thread.Context, &ctx, sizeof(CONTEXT));
            cbin.u.Thread.SizeOfContext = sizeof(CONTEXT);
            cbin.u.Thread.StackBase = mdThd.Stack.StartOfMemoryRange;
            cbin.u.Thread.StackEnd = mdThd.Stack.StartOfMemoryRange +
                mdThd.Stack.Memory.DataSize;

            cbout.u.ThreadWriteFlags = flags_out;
            if (!dc->cb->CallbackRoutine(dc->cb->CallbackParam, &cbin, &cbout))
                continue;
            flags_out &= cbout.u.ThreadWriteFlags;
        }
        if (flags_out & ThreadWriteThread)
        {
            if (ctx.ContextFlags && (flags_out & ThreadWriteContext))
            {
                mdThd.ThreadContext.Rva = dc->rva;
                mdThd.ThreadContext.DataSize = sizeof(CONTEXT);
                append(dc, &ctx, sizeof(CONTEXT));
            }
            if (mdThd.Stack.Memory.DataSize && (flags_out & ThreadWriteStack))
            {
                add_memory_block(dc, mdThd.Stack.StartOfMemoryRange,
                                 mdThd.Stack.Memory.DataSize,
                                 rva_base + sizeof(mdThdList.NumberOfThreads) +
                                     mdThdList.NumberOfThreads * sizeof(mdThd) +
                                     FIELD_OFFSET(MINIDUMP_THREAD, Stack.Memory.Rva));
            }
            writeat(dc, 
                    rva_base + sizeof(mdThdList.NumberOfThreads) +
                        mdThdList.NumberOfThreads * sizeof(mdThd),
                    &mdThd, sizeof(mdThd));
            mdThdList.NumberOfThreads++;
        }
        if (ctx.ContextFlags && (flags_out & ThreadWriteInstructionWindow))
        {
            /* FIXME: - Native dbghelp also dumps 0x80 bytes around EIP
             *        - also crop values across module boundaries, 
             *        - and don't make it i386 dependent 
             */
            /* add_memory_block(dc, ctx.Eip - 0x80, ctx.Eip + 0x80, 0); */
        }
    }
    writeat(dc, rva_base,
            &mdThdList.NumberOfThreads, sizeof(mdThdList.NumberOfThreads));
}

/******************************************************************
 *		dump_memory_info
 *
 * dumps information about the memory of the process (stack of the threads)
 */
static void dump_memory_info(struct dump_context* dc)
{
    MINIDUMP_MEMORY_LIST        mdMemList;
    MINIDUMP_MEMORY_DESCRIPTOR  mdMem;
    DWORD                       written;
    unsigned                    i, pos, len;
    RVA                         rva_base;
    char                        tmp[1024];

    mdMemList.NumberOfMemoryRanges = dc->num_mem;
    append(dc, &mdMemList.NumberOfMemoryRanges,
           sizeof(mdMemList.NumberOfMemoryRanges));
    rva_base = dc->rva;
    dc->rva += mdMemList.NumberOfMemoryRanges * sizeof(mdMem);

    for (i = 0; i < dc->num_mem; i++)
    {
        mdMem.StartOfMemoryRange = dc->mem[i].base;
        mdMem.Memory.Rva = dc->rva;
        mdMem.Memory.DataSize = dc->mem[i].size;
        SetFilePointer(dc->hFile, dc->rva, NULL, FILE_BEGIN);
        for (pos = 0; pos < dc->mem[i].size; pos += sizeof(tmp))
        {
            len = min(dc->mem[i].size - pos, sizeof(tmp));
            if (ReadProcessMemory(dc->hProcess, 
                                  (void*)(ULONG)(dc->mem[i].base + pos), 
                                  tmp, len, NULL))
                WriteFile(dc->hFile, tmp, len, &written, NULL);
        }
        dc->rva += mdMem.Memory.DataSize;
        writeat(dc, rva_base + i * sizeof(mdMem), &mdMem, sizeof(mdMem));
        if (dc->mem[i].rva)
        {
            writeat(dc, dc->mem[i].rva, &mdMem.Memory.Rva, sizeof(mdMem.Memory.Rva));
        }
    }
}

static void dump_misc_info(struct dump_context* dc)
{
    MINIDUMP_MISC_INFO  mmi;

    mmi.SizeOfInfo = sizeof(mmi);
    mmi.Flags1 = MINIDUMP_MISC1_PROCESS_ID;
    mmi.ProcessId = dc->pid;
    /* FIXME: create/user/kernel time */
    append(dc, &mmi, sizeof(mmi));
}

/******************************************************************
 *		MiniDumpWriteDump (DEBUGHLP.@)
 *
 */
BOOL WINAPI MiniDumpWriteDump(HANDLE hProcess, DWORD pid, HANDLE hFile,
                              MINIDUMP_TYPE DumpType,
                              PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
                              PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
                              PMINIDUMP_CALLBACK_INFORMATION CallbackParam)
{
    MINIDUMP_HEADER     mdHead;
    MINIDUMP_DIRECTORY  mdDir;
    DWORD               i, nStreams, idx_stream;
    struct dump_context dc;

    dc.hProcess = hProcess;
    dc.hFile = hFile;
    dc.pid = pid;
    dc.module = NULL;
    dc.num_module = 0;
    dc.cb = CallbackParam;
    dc.type = DumpType;
    dc.mem = NULL;
    dc.num_mem = 0;
    dc.rva = 0;

    if (!fetch_process_info(&dc)) return FALSE;
    fetch_module_info(&dc);

    /* 1) init */
    nStreams = 6 + (ExceptionParam ? 1 : 0) +
        (UserStreamParam ? UserStreamParam->UserStreamCount : 0);

    if (DumpType & MiniDumpWithDataSegs)
        FIXME("NIY MiniDumpWithDataSegs\n");
    if (DumpType & MiniDumpWithFullMemory)
        FIXME("NIY MiniDumpWithFullMemory\n");
    if (DumpType & MiniDumpWithHandleData)
        FIXME("NIY MiniDumpWithHandleData\n");
    if (DumpType & MiniDumpFilterMemory)
        FIXME("NIY MiniDumpFilterMemory\n");
    if (DumpType & MiniDumpScanMemory)
        FIXME("NIY MiniDumpScanMemory\n");

    /* 2) write header */
    mdHead.Signature = MINIDUMP_SIGNATURE;
    mdHead.Version = MINIDUMP_VERSION;
    mdHead.NumberOfStreams = nStreams;
    mdHead.StreamDirectoryRva = sizeof(mdHead);
    mdHead.u.TimeDateStamp = time(NULL);
    mdHead.Flags = DumpType;
    append(&dc, &mdHead, sizeof(mdHead));

    /* 3) write stream directories */
    dc.rva += nStreams * sizeof(mdDir);
    idx_stream = 0;

    /* 3.1) write data stream directories */

    mdDir.StreamType = ThreadListStream;
    mdDir.Location.Rva = dc.rva;
    dump_threads(&dc, ExceptionParam);
    mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
    writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir), 
            &mdDir, sizeof(mdDir));

    mdDir.StreamType = ModuleListStream;
    mdDir.Location.Rva = dc.rva;
    dump_modules(&dc, FALSE);
    mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
    writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
            &mdDir, sizeof(mdDir));

    mdDir.StreamType = 0xfff0; /* FIXME: this is part of MS reserved streams */
    mdDir.Location.Rva = dc.rva;
    dump_modules(&dc, TRUE);
    mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
    writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
            &mdDir, sizeof(mdDir));

    mdDir.StreamType = MemoryListStream;
    mdDir.Location.Rva = dc.rva;
    dump_memory_info(&dc);
    mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
    writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
            &mdDir, sizeof(mdDir));

    mdDir.StreamType = SystemInfoStream;
    mdDir.Location.Rva = dc.rva;
    dump_system_info(&dc);
    mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
    writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
            &mdDir, sizeof(mdDir));

    mdDir.StreamType = MiscInfoStream;
    mdDir.Location.Rva = dc.rva;
    dump_misc_info(&dc);
    mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
    writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
            &mdDir, sizeof(mdDir));

    /* 3.2) write exception information (if any) */
    if (ExceptionParam)
    {
        mdDir.StreamType = ExceptionStream;
        mdDir.Location.Rva = dc.rva;
        dump_exception_info(&dc, ExceptionParam);
        mdDir.Location.DataSize = dc.rva - mdDir.Location.Rva;
        writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
                &mdDir, sizeof(mdDir));
    }

    /* 3.3) write user defined streams (if any) */
    if (UserStreamParam)
    {
        for (i = 0; i < UserStreamParam->UserStreamCount; i++)
        {
            mdDir.StreamType = UserStreamParam->UserStreamArray[i].Type;
            mdDir.Location.DataSize = UserStreamParam->UserStreamArray[i].BufferSize;
            mdDir.Location.Rva = dc.rva;
            writeat(&dc, mdHead.StreamDirectoryRva + idx_stream++ * sizeof(mdDir),
                    &mdDir, sizeof(mdDir));
            append(&dc, UserStreamParam->UserStreamArray[i].Buffer, 
                   UserStreamParam->UserStreamArray[i].BufferSize);
        }
    }

    HeapFree(GetProcessHeap(), 0, dc.pcs_buffer);
    HeapFree(GetProcessHeap(), 0, dc.mem);
    HeapFree(GetProcessHeap(), 0, dc.module);

    return TRUE;
}

/******************************************************************
 *		MiniDumpReadDumpStream (DEBUGHLP.@)
 *
 *
 */
BOOL WINAPI MiniDumpReadDumpStream(void* base, ULONG str_idx,
                                   PMINIDUMP_DIRECTORY* pdir,
                                   void** stream, ULONG* size)
{
    MINIDUMP_HEADER*    mdHead = (MINIDUMP_HEADER*)base;

    if (mdHead->Signature == MINIDUMP_SIGNATURE)
    {
        MINIDUMP_DIRECTORY* dir;
        int                 i;

        dir = (MINIDUMP_DIRECTORY*)((char*)base + mdHead->StreamDirectoryRva);
        for (i = 0; i < mdHead->NumberOfStreams; i++, dir++)
        {
            if (dir->StreamType == str_idx)
            {
                *pdir = dir;
                *stream = (char*)base + dir->Location.Rva;
                *size = dir->Location.DataSize;
                return TRUE;
            }
        }
    }
    SetLastError(ERROR_INVALID_PARAMETER);
    return FALSE;
}

--- NEW FILE: module.c ---
/*
 * File module.c - module handling for the wine debugger
 *
 * Copyright (C) 1993,      Eric Youngdale.
 * 		 2000-2007, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
[...965 lines suppressed...]

/******************************************************************
 *		module_reset_debug_info
 * Removes any debug information linked to a given module.
 */
void module_reset_debug_info(struct module* module)
{
    module->sortlist_valid = TRUE;
    module->addr_sorttab = NULL;
    hash_table_destroy(&module->ht_symbols);
    module->ht_symbols.num_buckets = 0;
    module->ht_symbols.buckets = NULL;
    hash_table_destroy(&module->ht_types);
    module->ht_types.num_buckets = 0;
    module->ht_types.buckets = NULL;
    module->vtypes.num_elts = 0;
    hash_table_destroy(&module->ht_symbols);
    module->sources_used = module->sources_alloc = 0;
    module->sources = NULL;
}

--- NEW FILE: msc.c ---
/*
 * File msc.c - read VC++ debug information from COFF and eventually
 * from PDB files.
 *
 * Copyright (C) 1996,      Eric Youngdale.
 * Copyright (C) 1999-2000, Ulrich Weigand.
 * Copyright (C) 2004-2006, Eric Pouech.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
[...2508 lines suppressed...]
	WORD        cdwParams;             /* # bytes in params/4 */

	WORD        cbProlog : 8;          /* # bytes in prolog */
	WORD        cbRegs   : 3;          /* # regs saved */
	WORD        fHasSEH  : 1;          /* TRUE if SEH in func */
	WORD        fUseBP   : 1;          /* TRUE if EBP has been allocated */
	WORD        reserved : 1;          /* reserved for future use */
	WORD        cbFrame  : 2;          /* frame type */
} FPO_DATA;
#endif

    }
    __EXCEPT_PAGE_FAULT
    {
        ERR("Got a page fault while loading symbols\n");
        ret = FALSE;
    }
    __ENDTRY
    return ret;
}

--- NEW FILE: path.c ---
/*
 * File path.c - managing path in debugging environments
 *
 * Copyright (C) 2004, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "dbghelp_private.h"
#include "winnls.h"
#include "winternl.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

static inline BOOL is_sep(char ch) {return ch == '/' || ch == '\\';}
static inline BOOL is_sepW(WCHAR ch) {return ch == '/' || ch == '\\';}

static inline const char* file_name(const char* str)
{
    const char*       p;

    for (p = str + strlen(str) - 1; p >= str && !is_sep(*p); p--);
    return p + 1;
}

static inline const WCHAR* file_nameW(const WCHAR* str)
{
    const WCHAR*      p;

    for (p = str + strlenW(str) - 1; p >= str && !is_sepW(*p); p--);
    return p + 1;
}

/******************************************************************
 *		FindDebugInfoFile (DBGHELP.@)
 *
 */
HANDLE WINAPI FindDebugInfoFile(PCSTR FileName, PCSTR SymbolPath, PSTR DebugFilePath)
{
    HANDLE      h;

    h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (h == INVALID_HANDLE_VALUE)
    {
        if (!SearchPathA(SymbolPath, file_name(FileName), NULL, MAX_PATH, DebugFilePath, NULL))
            return NULL;
        h = CreateFileA(DebugFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    }
    return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}
 
/******************************************************************
 *		FindDebugInfoFileEx (DBGHELP.@)
 *
 */
HANDLE WINAPI FindDebugInfoFileEx(PCSTR FileName, PCSTR SymbolPath,
                                  PSTR DebugFilePath, 
                                  PFIND_DEBUG_FILE_CALLBACK Callback,
                                  PVOID CallerData)
{
    FIXME("(%s %s %p %p %p): stub\n", 
          FileName, SymbolPath, DebugFilePath, Callback, CallerData);
    return NULL;
}

/******************************************************************
 *		FindExecutableImageExW (DBGHELP.@)
 *
 */
HANDLE WINAPI FindExecutableImageExW(PCWSTR FileName, PCWSTR SymbolPath, PWSTR ImageFilePath,
                                     PFIND_EXE_FILE_CALLBACKW Callback, void* user)
{
    HANDLE h;

    if (Callback) FIXME("Unsupported callback yet\n");
    if (!SearchPathW(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
        return NULL;
    h = CreateFileW(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}

/******************************************************************
 *		FindExecutableImageEx (DBGHELP.@)
 *
 */
HANDLE WINAPI FindExecutableImageEx(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath,
                                    PFIND_EXE_FILE_CALLBACK Callback, void* user)
{
    HANDLE h;

    if (Callback) FIXME("Unsupported callback yet\n");
    if (!SearchPathA(SymbolPath, FileName, NULL, MAX_PATH, ImageFilePath, NULL))
        return NULL;
    h = CreateFileA(ImageFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
                    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    return (h == INVALID_HANDLE_VALUE) ? NULL : h;
}

/******************************************************************
 *		FindExecutableImage (DBGHELP.@)
 *
 */
HANDLE WINAPI FindExecutableImage(PCSTR FileName, PCSTR SymbolPath, PSTR ImageFilePath)
{
    return FindExecutableImageEx(FileName, SymbolPath, ImageFilePath, NULL, NULL);
}

/***********************************************************************
 *           MakeSureDirectoryPathExists (DBGHELP.@)
 */
BOOL WINAPI MakeSureDirectoryPathExists(LPCSTR DirPath)
{
    char path[MAX_PATH];
    const char *p = DirPath;
    int  n;

    if (p[0] && p[1] == ':') p += 2;
    while (*p == '\\') p++; /* skip drive root */
    while ((p = strchr(p, '\\')) != NULL)
    {
       n = p - DirPath + 1;
       memcpy(path, DirPath, n);
       path[n] = '\0';
       if( !CreateDirectoryA(path, NULL)            &&
           (GetLastError() != ERROR_ALREADY_EXISTS))
           return FALSE;
       p++;
    }
    if (GetLastError() == ERROR_ALREADY_EXISTS)
       SetLastError(ERROR_SUCCESS);

    return TRUE;
}

/******************************************************************
 *		SymMatchFileNameW (DBGHELP.@)
 *
 */
BOOL WINAPI SymMatchFileNameW(WCHAR* file, WCHAR* match,
                              WCHAR** filestop, WCHAR** matchstop)
{
    WCHAR*      fptr;
    WCHAR*      mptr;

    TRACE("(%s %s %p %p)\n",
          debugstr_w(file), debugstr_w(match), filestop, matchstop);

    fptr = file + strlenW(file) - 1;
    mptr = match + strlenW(match) - 1;

    while (fptr >= file && mptr >= match)
    {
        if (toupperW(*fptr) != toupperW(*mptr) && !(is_sepW(*fptr) && is_sepW(*mptr)))
            break;
        fptr--; mptr--;
    }
    if (filestop) *filestop = fptr;
    if (matchstop) *matchstop = mptr;

    return mptr == match - 1;
}

/******************************************************************
 *		SymMatchFileName (DBGHELP.@)
 *
 */
BOOL WINAPI SymMatchFileName(char* file, char* match,
                             char** filestop, char** matchstop)
{
    char*       fptr;
    char*       mptr;

    TRACE("(%s %s %p %p)\n", file, match, filestop, matchstop);

    fptr = file + strlen(file) - 1;
    mptr = match + strlen(match) - 1;

    while (fptr >= file && mptr >= match)
    {
        if (toupper(*fptr) != toupper(*mptr) && !(is_sep(*fptr) && is_sep(*mptr)))
            break;
        fptr--; mptr--;
    }
    if (filestop) *filestop = fptr;
    if (matchstop) *matchstop = mptr;

    return mptr == match - 1;
}

static BOOL do_searchW(const WCHAR* file, WCHAR* buffer, BOOL recurse,
                       PENUMDIRTREE_CALLBACKW cb, void* user)
{
    HANDLE              h;
    WIN32_FIND_DATAW    fd;
    unsigned            pos;
    BOOL                found = FALSE;
    static const WCHAR  S_AllW[] = {'*','.','*','\0'};
    static const WCHAR  S_DotW[] = {'.','\0'};
    static const WCHAR  S_DotDotW[] = {'.','\0'};

    pos = strlenW(buffer);
    if (buffer[pos - 1] != '\\') buffer[pos++] = '\\';
    strcpyW(buffer + pos, S_AllW);
    if ((h = FindFirstFileW(buffer, &fd)) == INVALID_HANDLE_VALUE)
        return FALSE;
    /* doc doesn't specify how the tree is enumerated...
     * doing a depth first based on, but may be wrong
     */
    do
    {
        if (!strcmpW(fd.cFileName, S_DotW) || !strcmpW(fd.cFileName, S_DotDotW)) continue;

        strcpyW(buffer + pos, fd.cFileName);
        if (recurse && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
            found = do_searchW(file, buffer, TRUE, cb, user);
        else if (SymMatchFileNameW(buffer, (WCHAR*)file, NULL, NULL))
        {
            if (!cb || cb(buffer, user)) found = TRUE;
        }
    } while (!found && FindNextFileW(h, &fd));
    if (!found) buffer[--pos] = '\0';
    FindClose(h);

    return found;
}

/***********************************************************************
 *           SearchTreeForFileW (DBGHELP.@)
 */
BOOL WINAPI SearchTreeForFileW(PCWSTR root, PCWSTR file, PWSTR buffer)
{
    TRACE("(%s, %s, %p)\n",
          debugstr_w(root), debugstr_w(file), buffer);
    strcpyW(buffer, root);
    return do_searchW(file, buffer, TRUE, NULL, NULL);
}

/***********************************************************************
 *           SearchTreeForFile (DBGHELP.@)
 */
BOOL WINAPI SearchTreeForFile(PCSTR root, PCSTR file, PSTR buffer)
{
    WCHAR       rootW[MAX_PATH];
    WCHAR       fileW[MAX_PATH];
    WCHAR       bufferW[MAX_PATH];
    BOOL        ret;

    MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH);
    MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH);
    ret = SearchTreeForFileW(rootW, fileW, bufferW);
    if (ret)
        WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
    return ret;
}

/******************************************************************
 *		EnumDirTreeW (DBGHELP.@)
 *
 *
 */
BOOL WINAPI EnumDirTreeW(HANDLE hProcess, PCWSTR root, PCWSTR file,
                        LPWSTR buffer, PENUMDIRTREE_CALLBACKW cb, PVOID user)
{
    TRACE("(%p %s %s %p %p %p)\n",
          hProcess, debugstr_w(root), debugstr_w(file), buffer, cb, user);

    strcpyW(buffer, root);
    return do_searchW(file, buffer, TRUE, cb, user);
}

/******************************************************************
 *		EnumDirTree (DBGHELP.@)
 *
 *
 */
struct enum_dir_treeWA
{
    PENUMDIRTREE_CALLBACK       cb;
    void*                       user;
    char                        name[MAX_PATH];
};

static BOOL CALLBACK enum_dir_treeWA(LPCWSTR name, PVOID user)
{
    struct enum_dir_treeWA*     edt = user;

    WideCharToMultiByte(CP_ACP, 0, name, -1, edt->name, MAX_PATH, NULL, NULL);
    return edt->cb(edt->name, edt->user);
}

BOOL WINAPI EnumDirTree(HANDLE hProcess, PCSTR root, PCSTR file,
                        LPSTR buffer, PENUMDIRTREE_CALLBACK cb, PVOID user)
{
    WCHAR                       rootW[MAX_PATH];
    WCHAR                       fileW[MAX_PATH];
    WCHAR                       bufferW[MAX_PATH];
    struct enum_dir_treeWA      edt;
    BOOL                        ret;

    edt.cb = cb;
    edt.user = user;
    MultiByteToWideChar(CP_ACP, 0, root, -1, rootW, MAX_PATH);
    MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, MAX_PATH);
    if ((ret = EnumDirTreeW(hProcess, rootW, fileW, bufferW, enum_dir_treeWA, &edt)))
        WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
    return ret;
}

struct sffip
{
    enum module_type            kind;
    /* pe:  id  -> DWORD:timestamp
     *      two -> size of image (from PE header)
     * pdb: id  -> PDB signature
     *            I think either DWORD:timestamp or GUID:guid depending on PDB version
     *      two -> PDB age ???
     * elf: id  -> DWORD:CRC 32 of ELF image (Wine only)
     */
    PVOID                       id;
    DWORD                       two;
    DWORD                       three;
    DWORD                       flags;
    PFINDFILEINPATHCALLBACKW    cb;
    void*                       user;
};

/* checks that buffer (as found by matching the name) matches the info
 * (information is based on file type)
 * returns TRUE when file is found, FALSE to continue searching
 * (NB this is the opposite conventions as for SymFindFileInPathProc)
 */
static BOOL CALLBACK sffip_cb(LPCWSTR buffer, void* user)
{
    struct sffip*       s = (struct sffip*)user;
    DWORD               size, checksum;

    /* FIXME: should check that id/two/three match the file pointed
     * by buffer
     */
    switch (s->kind)
    {
    case DMT_PE:
        {
            HANDLE  hFile, hMap;
            void*   mapping;
            DWORD   timestamp;

            timestamp = ~(DWORD_PTR)s->id;
            size = ~s->two;
            hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ, NULL,
                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
            if (hFile == INVALID_HANDLE_VALUE) return FALSE;
            if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
            {
                if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
                {
                    IMAGE_NT_HEADERS*   nth = RtlImageNtHeader(mapping);
                    timestamp = nth->FileHeader.TimeDateStamp;
                    size = nth->OptionalHeader.SizeOfImage;
                    UnmapViewOfFile(mapping);
                }
                CloseHandle(hMap);
            }
            CloseHandle(hFile);
            if (timestamp != (DWORD_PTR)s->id || size != s->two)
            {
                WARN("Found %s, but wrong size or timestamp\n", debugstr_w(buffer));
                return FALSE;
            }
        }
        break;
    case DMT_ELF:
        if (elf_fetch_file_info(buffer, 0, &size, &checksum))
        {
            if (checksum != (DWORD_PTR)s->id)
            {
                WARN("Found %s, but wrong checksums: %08x %08lx\n",
                     debugstr_w(buffer), checksum, (DWORD_PTR)s->id);
                return FALSE;
            }
        }
        else
        {
            WARN("Couldn't read %s\n", debugstr_w(buffer));
            return FALSE;
        }
        break;
    case DMT_PDB:
        {
            struct pdb_lookup   pdb_lookup;
            char                fn[MAX_PATH];

            WideCharToMultiByte(CP_ACP, 0, buffer, -1, fn, MAX_PATH, NULL, NULL);
            pdb_lookup.filename = fn;

            if (!pdb_fetch_file_info(&pdb_lookup)) return FALSE;
            switch (pdb_lookup.kind)
            {
            case PDB_JG:
                if (s->flags & SSRVOPT_GUIDPTR)
                {
                    WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
                    return FALSE;
                }
                if (pdb_lookup.u.jg.timestamp != (DWORD_PTR)s->id)
                {
                    WARN("Found %s, but wrong signature: %08x %08lx\n",
                         debugstr_w(buffer), pdb_lookup.u.jg.timestamp, (DWORD_PTR)s->id);
                    return FALSE;
                }
                break;
            case PDB_DS:
                if (!(s->flags & SSRVOPT_GUIDPTR))
                {
                    WARN("Found %s, but wrong PDB version\n", debugstr_w(buffer));
                    return FALSE;
                }
                if (memcmp(&pdb_lookup.u.ds.guid, (GUID*)s->id, sizeof(GUID)))
                {
                    WARN("Found %s, but wrong GUID: %s %s\n",
                         debugstr_w(buffer), debugstr_guid(&pdb_lookup.u.ds.guid),
                         debugstr_guid((GUID*)s->id));
                    return FALSE;
                }
                break;
            }
            if (pdb_lookup.age != s->two)
            {
                WARN("Found %s, but wrong age: %08x %08x\n",
                     debugstr_w(buffer), pdb_lookup.age, s->two);
                return FALSE;
            }
        }
        break;
    default:
        FIXME("What the heck??\n");
        return FALSE;
    }
    /* yes, EnumDirTree/do_search and SymFindFileInPath callbacks use the opposite
     * convention to stop/continue enumeration. sigh.
     */
    return !(s->cb)((WCHAR*)buffer, s->user);
}

/******************************************************************
 *		SymFindFileInPathW (DBGHELP.@)
 *
 */
BOOL WINAPI SymFindFileInPathW(HANDLE hProcess, PCWSTR searchPath, PCWSTR full_path,
                               PVOID id, DWORD two, DWORD three, DWORD flags,
                               LPWSTR buffer, PFINDFILEINPATHCALLBACKW cb,
                               PVOID user)
{
    struct sffip        s;
    struct process*     pcs = process_find_by_handle(hProcess);
    WCHAR               tmp[MAX_PATH];
    WCHAR*              ptr;
    const WCHAR*        filename;

    TRACE("(hProcess = %p, searchPath = '%s', full_path = '%s', id = %p, two = 0x%08x, three = 0x%08x, flags = 0x%08x, buffer = %p, cb = %p, user = %p)\n",
          hProcess, debugstr_w(searchPath), debugstr_w(full_path),
          id, two, three, flags, buffer, cb, user);

    if (!pcs) return FALSE;
    if (!searchPath) searchPath = pcs->search_path;

    s.id = id;
    s.two = two;
    s.three = three;
    s.flags = flags;
    s.cb = cb;
    s.user = user;

    filename = file_nameW(full_path);
    s.kind = module_get_type_by_name(filename);

    /* first check full path to file */
    if (sffip_cb(full_path, &s))
    {
        strcpyW(buffer, full_path);
        return TRUE;
    }

    while (searchPath)
    {
        ptr = strchrW(searchPath, ';');
        if (ptr)
        {
            memcpy(tmp, searchPath, (ptr - searchPath) * sizeof(WCHAR));
            tmp[ptr - searchPath] = 0;
            searchPath = ptr + 1;
        }
        else
        {
            strcpyW(tmp, searchPath);
            searchPath = NULL;
        }
        if (do_searchW(filename, tmp, FALSE, sffip_cb, &s))
        {
            strcpyW(buffer, tmp);
            return TRUE;
        }
    }
    return FALSE;
}

/******************************************************************
 *		SymFindFileInPath (DBGHELP.@)
 *
 */
BOOL WINAPI SymFindFileInPath(HANDLE hProcess, PCSTR searchPath, PCSTR full_path,
                              PVOID id, DWORD two, DWORD three, DWORD flags,
                              LPSTR buffer, PFINDFILEINPATHCALLBACK cb,
                              PVOID user)
{
    WCHAR                       searchPathW[MAX_PATH];
    WCHAR                       full_pathW[MAX_PATH];
    WCHAR                       bufferW[MAX_PATH];
    struct enum_dir_treeWA      edt;
    BOOL                        ret;

    /* a PFINDFILEINPATHCALLBACK and a PENUMDIRTREE_CALLBACK have actually the
     * same signature & semantics, hence we can reuse the EnumDirTree W->A
     * conversion helper
     */
    edt.cb = cb;
    edt.user = user;
    if (searchPath)
        MultiByteToWideChar(CP_ACP, 0, searchPath, -1, searchPathW, MAX_PATH);
    MultiByteToWideChar(CP_ACP, 0, full_path, -1, full_pathW, MAX_PATH);
    if ((ret =  SymFindFileInPathW(hProcess, searchPath ? searchPathW : NULL, full_pathW,
                                   id, two, three, flags,
                                   bufferW, enum_dir_treeWA, &edt)))
        WideCharToMultiByte(CP_ACP, 0, bufferW, -1, buffer, MAX_PATH, NULL, NULL);
    return ret;
}

--- NEW FILE: pe_module.c ---
/*
 * File pe_module.c - handle PE module information
 *
 * Copyright (C) 1996,      Eric Youngdale.
 * Copyright (C) 1999-2000, Ulrich Weigand.
 * Copyright (C) 2004-2007, Eric Pouech.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 */

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "dbghelp_private.h"
#include "winternl.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

/******************************************************************
 *		pe_load_stabs
 *
 * look for stabs information in PE header (it's how the mingw compiler provides 
 * its debugging information)
 */
static BOOL pe_load_stabs(const struct process* pcs, struct module* module, 
                          const void* mapping, IMAGE_NT_HEADERS* nth)
{
    IMAGE_SECTION_HEADER*       section;
    int                         i, stabsize = 0, stabstrsize = 0;
    unsigned int                stabs = 0, stabstr = 0;
    BOOL                        ret = FALSE;

    section = (IMAGE_SECTION_HEADER*)
        ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
    for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++)
    {
        if (!strcasecmp((const char*)section->Name, ".stab"))
        {
            stabs = section->VirtualAddress;
            stabsize = section->SizeOfRawData;
        }
        else if (!strncasecmp((const char*)section->Name, ".stabstr", 8))
        {
            stabstr = section->VirtualAddress;
            stabstrsize = section->SizeOfRawData;
        }
    }

    if (stabstrsize && stabsize)
    {
        ret = stabs_parse(module, 
                          module->module.BaseOfImage - nth->OptionalHeader.ImageBase, 
                          RtlImageRvaToVa(nth, (void*)mapping, stabs, NULL),
                          stabsize,
                          RtlImageRvaToVa(nth, (void*)mapping, stabstr, NULL),
                          stabstrsize);
    }
    return ret;
}

static BOOL CALLBACK dbg_match(const char* file, void* user)
{
    /* accept first file */
    return FALSE;
}

/******************************************************************
 *		pe_load_dbg_file
 *
 * loads a .dbg file
 */
static BOOL pe_load_dbg_file(const struct process* pcs, struct module* module,
                             const char* dbg_name, DWORD timestamp)
{
    char                                tmp[MAX_PATH];
    HANDLE                              hFile = INVALID_HANDLE_VALUE, hMap = 0;
    const BYTE*                         dbg_mapping = NULL;
    const IMAGE_SEPARATE_DEBUG_HEADER*  hdr;
    const IMAGE_DEBUG_DIRECTORY*        dbg;
    BOOL                                ret = FALSE;

    WINE_TRACE("Processing DBG file %s\n", dbg_name);

    if (SymFindFileInPath(pcs->handle, NULL, dbg_name, NULL, 0, 0, 0, tmp, dbg_match, NULL) &&
        (hFile = CreateFileA(tmp, GENERIC_READ, FILE_SHARE_READ, NULL,
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE &&
        ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0) &&
        ((dbg_mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL))
    {
        hdr = (const IMAGE_SEPARATE_DEBUG_HEADER*)dbg_mapping;
        if (hdr->TimeDateStamp != timestamp)
        {
            WINE_ERR("Warning - %s has incorrect internal timestamp\n",
                     dbg_name);
            /*
             * Well, sometimes this happens to DBG files which ARE REALLY the
             * right .DBG files but nonetheless this check fails. Anyway,
             * WINDBG (debugger for Windows by Microsoft) loads debug symbols
             * which have incorrect timestamps.
             */
        }
        if (hdr->Signature == IMAGE_SEPARATE_DEBUG_SIGNATURE)
        {
            /* section headers come immediately after debug header */
            const IMAGE_SECTION_HEADER *sectp =
                (const IMAGE_SECTION_HEADER*)(hdr + 1);
            /* and after that and the exported names comes the debug directory */
            dbg = (const IMAGE_DEBUG_DIRECTORY*) 
                (dbg_mapping + sizeof(*hdr) + 
                 hdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) +
                 hdr->ExportedNamesSize);


            ret = pe_load_debug_directory(pcs, module, dbg_mapping, sectp,
                                          hdr->NumberOfSections, dbg,
                                          hdr->DebugDirectorySize / sizeof(*dbg));
        }
        else
            ERR("Wrong signature in .DBG file %s\n", debugstr_a(tmp));
    }
    else
        WINE_ERR("-Unable to peruse .DBG file %s (%s)\n", dbg_name, debugstr_a(tmp));

    if (dbg_mapping) UnmapViewOfFile(dbg_mapping);
    if (hMap) CloseHandle(hMap);
    if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
    return ret;
}

/******************************************************************
 *		pe_load_msc_debug_info
 *
 * Process MSC debug information in PE file.
 */
static BOOL pe_load_msc_debug_info(const struct process* pcs, 
                                   struct module* module,
                                   const void* mapping, IMAGE_NT_HEADERS* nth)
{
    BOOL                        ret = FALSE;
    const IMAGE_DATA_DIRECTORY* dir;
    const IMAGE_DEBUG_DIRECTORY*dbg = NULL;
    int                         nDbg;

    /* Read in debug directory */
    dir = nth->OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_DEBUG;
    nDbg = dir->Size / sizeof(IMAGE_DEBUG_DIRECTORY);
    if (!nDbg) return FALSE;

    dbg = RtlImageRvaToVa(nth, (void*)mapping, dir->VirtualAddress, NULL);

    /* Parse debug directory */
    if (nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)
    {
        /* Debug info is stripped to .DBG file */
        const IMAGE_DEBUG_MISC* misc = (const IMAGE_DEBUG_MISC*)
            ((const char*)mapping + dbg->PointerToRawData);

        if (nDbg != 1 || dbg->Type != IMAGE_DEBUG_TYPE_MISC ||
            misc->DataType != IMAGE_DEBUG_MISC_EXENAME)
        {
            WINE_ERR("-Debug info stripped, but no .DBG file in module %s\n",
                     debugstr_w(module->module.ModuleName));
        }
        else
        {
            ret = pe_load_dbg_file(pcs, module, (const char*)misc->Data, nth->FileHeader.TimeDateStamp);
        }
    }
    else
    {
        const IMAGE_SECTION_HEADER *sectp = (const IMAGE_SECTION_HEADER*)((const char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
        /* Debug info is embedded into PE module */
        ret = pe_load_debug_directory(pcs, module, mapping, sectp,
            nth->FileHeader.NumberOfSections, dbg, nDbg);
    }

    return ret;
}

/***********************************************************************
 *			pe_load_export_debug_info
 */
static BOOL pe_load_export_debug_info(const struct process* pcs, 
                                      struct module* module, 
                                      const void* mapping, IMAGE_NT_HEADERS* nth)
{
    unsigned int 		        i;
    const IMAGE_EXPORT_DIRECTORY* 	exports;
    DWORD			        base = module->module.BaseOfImage;
    DWORD                               size;

    if (dbghelp_options & SYMOPT_NO_PUBLICS) return TRUE;

#if 0
    /* Add start of DLL (better use the (yet unimplemented) Exe SymTag for this) */
    /* FIXME: module.ModuleName isn't correctly set yet if it's passed in SymLoadModule */
    symt_new_public(module, NULL, module->module.ModuleName, base, 1,
                    TRUE /* FIXME */, TRUE /* FIXME */);
#endif
    
    /* Add entry point */
    symt_new_public(module, NULL, "EntryPoint", 
                    base + nth->OptionalHeader.AddressOfEntryPoint, 1,
                    TRUE, TRUE);
#if 0
    /* FIXME: we'd better store addresses linked to sections rather than 
       absolute values */
    IMAGE_SECTION_HEADER*       section;
    /* Add start of sections */
    section = (IMAGE_SECTION_HEADER*)
        ((char*)&nth->OptionalHeader + nth->FileHeader.SizeOfOptionalHeader);
    for (i = 0; i < nth->FileHeader.NumberOfSections; i++, section++) 
    {
	symt_new_public(module, NULL, section->Name, 
                        RtlImageRvaToVa(nth, (void*)mapping, section->VirtualAddress, NULL), 
                        1, TRUE /* FIXME */, TRUE /* FIXME */);
    }
#endif

    /* Add exported functions */
    if ((exports = RtlImageDirectoryEntryToData((void*)mapping, FALSE,
                                                IMAGE_DIRECTORY_ENTRY_EXPORT, &size)))
    {
        const WORD*             ordinals = NULL;
        const DWORD_PTR*	functions = NULL;
        const DWORD*		names = NULL;
        unsigned int		j;
        char			buffer[16];

        functions = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfFunctions, NULL);
        ordinals  = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfNameOrdinals, NULL);
        names     = RtlImageRvaToVa(nth, (void*)mapping, exports->AddressOfNames, NULL);

        for (i = 0; i < exports->NumberOfNames; i++) 
        {
            if (!names[i]) continue;
            symt_new_public(module, NULL, 
                            RtlImageRvaToVa(nth, (void*)mapping, names[i], NULL),
                            base + functions[ordinals[i]], 
                            1, TRUE /* FIXME */, TRUE /* FIXME */);
        }
	    
        for (i = 0; i < exports->NumberOfFunctions; i++) 
        {
            if (!functions[i]) continue;
            /* Check if we already added it with a name */
            for (j = 0; j < exports->NumberOfNames; j++)
                if ((ordinals[j] == i) && names[j]) break;
            if (j < exports->NumberOfNames) continue;
            snprintf(buffer, sizeof(buffer), "%d", i + exports->Base);
            symt_new_public(module, NULL, buffer, base + (DWORD)functions[i], 1,
                            TRUE /* FIXME */, TRUE /* FIXME */);
        }
    }
    /* no real debug info, only entry points */
    if (module->module.SymType == SymDeferred)
        module->module.SymType = SymExport;
    return TRUE;
}

/******************************************************************
 *		pe_load_debug_info
 *
 */
BOOL pe_load_debug_info(const struct process* pcs, struct module* module)
{
    BOOL                ret = FALSE;
    HANDLE              hFile;
    HANDLE              hMap;
    void*               mapping;
    IMAGE_NT_HEADERS*   nth;

    hFile = CreateFileW(module->module.LoadedImageName, GENERIC_READ, FILE_SHARE_READ,
                        NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile == INVALID_HANDLE_VALUE) return ret;
    if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != 0)
    {
        if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
        {
            nth = RtlImageNtHeader(mapping);

            if (!(dbghelp_options & SYMOPT_PUBLICS_ONLY))
            {
                ret = pe_load_stabs(pcs, module, mapping, nth) ||
                    pe_load_msc_debug_info(pcs, module, mapping, nth);
                /* if we still have no debug info (we could only get SymExport at this
                 * point), then do the SymExport except if we have an ELF container, 
                 * in which case we'll rely on the export's on the ELF side
                 */
            }
/* FIXME shouldn't we check that? if (!module_get_debug(pcs, module))l */
            if (pe_load_export_debug_info(pcs, module, mapping, nth) && !ret)
                ret = TRUE;
            UnmapViewOfFile(mapping);
        }
        CloseHandle(hMap);
    }
    CloseHandle(hFile);

    return ret;
}

/******************************************************************
 *		pe_load_native_module
 *
 */
struct module* pe_load_native_module(struct process* pcs, const WCHAR* name,
                                     HANDLE hFile, DWORD base, DWORD size)
{
    struct module*      module = NULL;
    BOOL                opened = FALSE;
    HANDLE              hMap;
    WCHAR               loaded_name[MAX_PATH];

    loaded_name[0] = '\0';
    if (!hFile)
    {

        assert(name);

        if ((hFile = FindExecutableImageExW(name, pcs->search_path, loaded_name, NULL, NULL)) == NULL)
            return NULL;
        opened = TRUE;
    }
    else if (name) strcpyW(loaded_name, name);
    else if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
        FIXME("Trouble ahead (no module name passed in deferred mode)\n");

    if ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
    {
        void*   mapping;

        if ((mapping = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
        {
            IMAGE_NT_HEADERS*   nth = RtlImageNtHeader(mapping);

            if (nth)
            {
                if (!base) base = nth->OptionalHeader.ImageBase;
                if (!size) size = nth->OptionalHeader.SizeOfImage;

                module = module_new(pcs, loaded_name, DMT_PE, FALSE, base, size,
                                    nth->FileHeader.TimeDateStamp,
                                    nth->OptionalHeader.CheckSum);
                if (module)
                {
                    if (dbghelp_options & SYMOPT_DEFERRED_LOADS)
                        module->module.SymType = SymDeferred;
                    else
                        pe_load_debug_info(pcs, module);
                }
            }
            UnmapViewOfFile(mapping);
        }
        CloseHandle(hMap);
    }
    if (opened) CloseHandle(hFile);

    return module;
}

/******************************************************************
 *		pe_load_nt_header
 *
 */
BOOL pe_load_nt_header(HANDLE hProc, DWORD base, IMAGE_NT_HEADERS* nth)
{
    IMAGE_DOS_HEADER    dos;

    return ReadProcessMemory(hProc, (char*)base, &dos, sizeof(dos), NULL) &&
        dos.e_magic == IMAGE_DOS_SIGNATURE &&
        ReadProcessMemory(hProc, (char*)(base + dos.e_lfanew), 
                          nth, sizeof(*nth), NULL) &&
        nth->Signature == IMAGE_NT_SIGNATURE;
}

/******************************************************************
 *		pe_load_builtin_module
 *
 */
struct module* pe_load_builtin_module(struct process* pcs, const WCHAR* name,
                                      DWORD base, DWORD size)
{
    struct module*      module = NULL;

    if (base && pcs->dbg_hdr_addr)
    {
        IMAGE_NT_HEADERS    nth;

        if (pe_load_nt_header(pcs->handle, base, &nth))
        {
            if (!size) size = nth.OptionalHeader.SizeOfImage;
            module = module_new(pcs, name, DMT_PE, FALSE, base, size,
                                nth.FileHeader.TimeDateStamp,
                                nth.OptionalHeader.CheckSum);
        }
    }
    return module;
}

--- NEW FILE: source.c ---
/*
 * File source.c - source files management
 *
 * Copyright (C) 2004,      Eric Pouech.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 */
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "dbghelp_private.h"
#include "wine/debug.h"
#ifdef HAVE_REGEX_H
# include <regex.h>
#endif

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

/******************************************************************
 *		source_find
 *
 * check whether a source file has already been stored
 */
static unsigned source_find(const struct module* module, const char* name)
{
    char*       ptr = module->sources;

    while (*ptr)
    {
        if (strcmp(ptr, name) == 0) return ptr - module->sources;
        ptr += strlen(ptr) + 1;
    }
    return (unsigned)-1;
}

/******************************************************************
 *		source_new
 *
 * checks if source exists. if not, add it
 */
unsigned source_new(struct module* module, const char* base, const char* name)
{
    unsigned    ret;
    const char* full;
    char*       tmp = NULL;

    if (!name) return (unsigned)-1;
    if (!base || *name == '/')
        full = name;
    else
    {
        unsigned bsz = strlen(base);

        tmp = HeapAlloc(GetProcessHeap(), 0, bsz + 1 + strlen(name) + 1);
        if (!tmp) return (unsigned)-1;
        full = tmp;
        strcpy(tmp, base);
        if (tmp[bsz - 1] != '/') tmp[bsz++] = '/';
        strcpy(&tmp[bsz], name);
    }
    if (!module->sources || (ret = source_find(module, full)) == (unsigned)-1)
    {
        int len = strlen(full) + 1;
        if (module->sources_used + len + 1 > module->sources_alloc)
        {
            /* Alloc by block of 256 bytes */
            module->sources_alloc = (module->sources_used + len + 1 + 255) & ~255;
            if (!module->sources)
                module->sources = HeapAlloc(GetProcessHeap(), 0, module->sources_alloc);
            else
                module->sources = HeapReAlloc(GetProcessHeap(), 0, module->sources,
                                              module->sources_alloc);
        }
        ret = module->sources_used;
        memcpy(module->sources + module->sources_used, full, len);
        module->sources_used += len;
        module->sources[module->sources_used] = '\0';
    }
    HeapFree(GetProcessHeap(), 0, tmp);
    return ret;
}

/******************************************************************
 *		source_get
 *
 * returns a stored source file name
 */
const char* source_get(const struct module* module, unsigned idx)
{
    if (idx == -1) return "";
    assert(module->sources);
    return module->sources + idx;
}

/******************************************************************
 *		SymEnumSourceFiles (DBGHELP.@)
 *
 */
BOOL WINAPI SymEnumSourceFiles(HANDLE hProcess, ULONG64 ModBase, PCSTR Mask,
                               PSYM_ENUMSOURCEFILES_CALLBACK cbSrcFiles,
                               PVOID UserContext)
{
    struct module_pair  pair;
    SOURCEFILE          sf;
    char*               ptr;
    
    if (!cbSrcFiles) return FALSE;
    pair.pcs = process_find_by_handle(hProcess);
    if (!pair.pcs) return FALSE;
         
    if (ModBase)
    {
        pair.requested = module_find_by_addr(pair.pcs, ModBase, DMT_UNKNOWN);
        if (!module_get_debug(&pair)) return FALSE;
    }
    else
    {
        if (Mask[0] == '!')
        {
            pair.requested = module_find_by_nameA(pair.pcs, Mask + 1);
            if (!module_get_debug(&pair)) return FALSE;
        }
        else
        {
            FIXME("Unsupported yet (should get info from current context)\n");
            return FALSE;
        }
    }
    if (!pair.effective->sources) return FALSE;
    for (ptr = pair.effective->sources; *ptr; ptr += strlen(ptr) + 1)
    {
        /* FIXME: not using Mask */
        sf.ModBase = ModBase;
        sf.FileName = ptr;
        if (!cbSrcFiles(&sf, UserContext)) break;
    }

    return TRUE;
}

/******************************************************************
 *		SymEnumLines (DBGHELP.@)
 *
 */
BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland,
                         PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user)
{
    struct module_pair          pair;
    struct hash_table_iter      hti;
    struct symt_ht*             sym;
    regex_t                     re;
    struct line_info*           dli;
    void*                       ptr;
    SRCCODEINFO                 sci;
    const char*                 file;

    if (!cb) return FALSE;
    if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE;
    if (regcomp(&re, srcfile, REG_NOSUB))
    {
        FIXME("Couldn't compile %s\n", srcfile);
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
    pair.pcs = process_find_by_handle(hProcess);
    if (!pair.pcs) return FALSE;
    if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland);
    pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN);
    if (!module_get_debug(&pair)) return FALSE;

    sci.SizeOfStruct = sizeof(sci);
    sci.ModBase      = base;

    hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL);
    while ((ptr = hash_table_iter_up(&hti)))
    {
        int    i;

        sym = GET_ENTRY(ptr, struct symt_ht, hash_elt);
        if (sym->symt.tag != SymTagFunction) continue;

        sci.FileName[0] = '\0';
        for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++)
        {
            dli = vector_at(&((struct symt_function*)sym)->vlines, i);
            if (dli->is_source_file)
            {
                file = source_get(pair.effective, dli->u.source_file);
                if (regexec(&re, file, 0, NULL, 0) != 0) file = "";
                strcpy(sci.FileName, file);
            }
            else if (sci.FileName[0])
            {
                sci.Key = dli;
                sci.Obj[0] = '\0'; /* FIXME */
                sci.LineNumber = dli->line_number;
                sci.Address = dli->u.pc_offset;
                if (!cb(&sci, user)) break;
            }
        }
    }
    return TRUE;
}

/******************************************************************
 *		SymGetSourceFileToken (DBGHELP.@)
 *
 */
BOOL WINAPI SymGetSourceFileToken(HANDLE hProcess, ULONG64 base,
                                  PCSTR src, PVOID* token, DWORD* size)
{
    FIXME("%p %s %s %p %p: stub!\n",
          hProcess, wine_dbgstr_longlong(base), debugstr_a(src), token, size);
    SetLastError(ERROR_NOT_SUPPORTED);
    return FALSE;
}

/******************************************************************
 *		SymGetSourceFileTokenW (DBGHELP.@)
 *
 */
BOOL WINAPI SymGetSourceFileTokenW(HANDLE hProcess, ULONG64 base,
                                   PCWSTR src, PVOID* token, DWORD* size)
{
    FIXME("%p %s %s %p %p: stub!\n",
          hProcess, wine_dbgstr_longlong(base), debugstr_w(src), token, size);
    SetLastError(ERROR_NOT_SUPPORTED);
    return FALSE;
}

--- NEW FILE: stabs.c ---
/*
 * File stabs.c - read stabs information from the modules
 *
 * Copyright (C) 1996,      Eric Youngdale.
 *		 1999-2005, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
[...1491 lines suppressed...]
        }
        stabbuff[0] = '\0';
        TRACE("0x%02x %lx %s\n", 
              stab_ptr->n_type, stab_ptr->n_value, debugstr_a(strs + stab_ptr->n_un.n_strx));
    }
    module->module.SymType = SymDia;
    module->module.CVSig = 'S' | ('T' << 8) | ('A' << 16) | ('B' << 24);
    /* FIXME: we could have a finer grain here */
    module->module.LineNumbers = TRUE;
    module->module.GlobalSymbols = TRUE;
    module->module.TypeInfo = TRUE;
    module->module.SourceIndexed = TRUE;
    module->module.Publics = TRUE;
done:
    HeapFree(GetProcessHeap(), 0, stabbuff);
    stabs_free_includes();
    HeapFree(GetProcessHeap(), 0, pending.vars);

    return ret;
}

--- NEW FILE: stack.c ---
/*
 * Stack walking
 *
 * Copyright 1995 Alexandre Julliard
 * Copyright 1996 Eric Youngdale
 * Copyright 1999 Ove KÃ¥ven
 * Copyright 2004 Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "dbghelp_private.h"
#include "winternl.h"
#include "wine/winbase16.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

enum st_mode {stm_start, stm_32bit, stm_16bit, stm_done};

static const char* wine_dbgstr_addr(const ADDRESS* addr)
{
    if (!addr) return "(null)";
    switch (addr->Mode)
    {
    case AddrModeFlat:
        return wine_dbg_sprintf("flat<%08x>", addr->Offset);
    case AddrMode1616:
        return wine_dbg_sprintf("1616<%04x:%04x>", addr->Segment, addr->Offset);
    case AddrMode1632:
        return wine_dbg_sprintf("1632<%04x:%08x>", addr->Segment, addr->Offset);
    case AddrModeReal:
        return wine_dbg_sprintf("real<%04x:%04x>", addr->Segment, addr->Offset);
    default:
        return "unknown";
    }
}

static BOOL CALLBACK read_mem(HANDLE hProcess, DWORD addr, void* buffer,
                              DWORD size, LPDWORD nread)
{
    SIZE_T      r;
    if (!ReadProcessMemory(hProcess, (void*)addr, buffer, size, &r)) return FALSE;
    if (nread) *nread = r;
    return TRUE;
}

static BOOL CALLBACK read_mem64(HANDLE hProcess, DWORD64 addr, void* buffer,
                                DWORD size, LPDWORD nread)
{
    SIZE_T      r;
    if (!ReadProcessMemory(hProcess, (void*)(DWORD_PTR)addr, buffer, size, &r)) return FALSE;
    if (nread) *nread = r;
    return TRUE;
}

/* indexes in Reserved array */
#define __CurrentMode     0
#define __CurrentSwitch   1
#define __NextSwitch      2

#define curr_mode   (frame->Reserved[__CurrentMode])
#define curr_switch (frame->Reserved[__CurrentSwitch])
#define next_switch (frame->Reserved[__NextSwitch])

struct stack_walk_callback
{
    HANDLE      hProcess;
    HANDLE      hThread;
    BOOL        is32;
    union
    {
        struct
        {
            PREAD_PROCESS_MEMORY_ROUTINE        f_read_mem;
            PTRANSLATE_ADDRESS_ROUTINE          f_xlat_adr;
            PFUNCTION_TABLE_ACCESS_ROUTINE      f_tabl_acs;
            PGET_MODULE_BASE_ROUTINE            f_modl_bas;
        } s32;
        struct
        {
            PREAD_PROCESS_MEMORY_ROUTINE64      f_read_mem;
            PTRANSLATE_ADDRESS_ROUTINE64        f_xlat_adr;
            PFUNCTION_TABLE_ACCESS_ROUTINE64    f_tabl_acs;
            PGET_MODULE_BASE_ROUTINE64          f_modl_bas;
        } s64;
    } u;
};

static inline void addr_32to64(const ADDRESS* addr32, ADDRESS64* addr64)
{
    addr64->Offset = (ULONG64)addr32->Offset;
    addr64->Segment = addr32->Segment;
    addr64->Mode = addr32->Mode;
}

static inline void addr_64to32(const ADDRESS64* addr64, ADDRESS* addr32)
{
    addr32->Offset = (ULONG)addr64->Offset;
    addr32->Segment = addr64->Segment;
    addr32->Mode = addr64->Mode;
}

static inline BOOL sw_read_mem(struct stack_walk_callback* cb, DWORD addr, void* ptr, DWORD sz)
{
    if (cb->is32)
        return cb->u.s32.f_read_mem(cb->hProcess, addr, ptr, sz, NULL);
    else
        return cb->u.s64.f_read_mem(cb->hProcess, addr, ptr, sz, NULL);
}

static inline DWORD sw_xlat_addr(struct stack_walk_callback* cb, ADDRESS* addr)
{
    if (addr->Mode == AddrModeFlat) return addr->Offset;
    if (cb->is32) return cb->u.s32.f_xlat_adr(cb->hProcess, cb->hThread, addr);
    if (cb->u.s64.f_xlat_adr)
    {
        ADDRESS64       addr64;

        addr_32to64(addr, &addr64);
        return cb->u.s64.f_xlat_adr(cb->hProcess, cb->hThread, &addr64);
    }
    return addr_to_linear(cb->hProcess, cb->hThread, addr);
}

static inline void* sw_tabl_acs(struct stack_walk_callback* cb, DWORD addr)
{
    if (cb->is32)
        return cb->u.s32.f_tabl_acs(cb->hProcess, addr);
    else
        return cb->u.s64.f_tabl_acs(cb->hProcess, addr);
}

static inline DWORD sw_modl_bas(struct stack_walk_callback* cb, DWORD addr)
{
    if (cb->is32)
        return cb->u.s32.f_modl_bas(cb->hProcess, addr);
    else
        return cb->u.s64.f_modl_bas(cb->hProcess, addr);
}

static BOOL stack_walk(struct stack_walk_callback* cb, LPSTACKFRAME frame)
{
    STACK32FRAME        frame32;
    STACK16FRAME        frame16;
    char                ch;
    ADDRESS             tmp;
    DWORD               p;
    WORD                val;
    BOOL                do_switch;

    /* sanity check */
    if (curr_mode >= stm_done) return FALSE;

    TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x\n",
          wine_dbgstr_addr(&frame->AddrPC),
          wine_dbgstr_addr(&frame->AddrFrame),
          wine_dbgstr_addr(&frame->AddrReturn),
          wine_dbgstr_addr(&frame->AddrStack), 
          curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
          curr_switch, next_switch);

    if (curr_mode == stm_start)
    {
        THREAD_BASIC_INFORMATION info;

        if ((frame->AddrPC.Mode == AddrModeFlat) &&
            (frame->AddrFrame.Mode != AddrModeFlat))
        {
            WARN("Bad AddrPC.Mode / AddrFrame.Mode combination\n");
            goto done_err;
        }

        /* Init done */
        curr_mode = (frame->AddrPC.Mode == AddrModeFlat) ? 
            stm_32bit : stm_16bit;

        /* cur_switch holds address of WOW32Reserved field in TEB in debuggee
         * address space
         */
        if (NtQueryInformationThread(cb->hThread, ThreadBasicInformation, &info,
                                     sizeof(info), NULL) == STATUS_SUCCESS)
        {
            curr_switch = (unsigned long)info.TebBaseAddress + FIELD_OFFSET(TEB, WOW32Reserved);
            if (!sw_read_mem(cb, curr_switch, &next_switch, sizeof(next_switch)))
            {
                WARN("Can't read TEB:WOW32Reserved\n");
                goto done_err;
            }
            if (curr_mode == stm_16bit)
            {
                if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32)))
                {
                    WARN("Bad stack frame 0x%08x\n", next_switch);
                    goto done_err;
                }
                curr_switch = (DWORD)frame32.frame16;
                tmp.Mode    = AddrMode1616;
                tmp.Segment = SELECTOROF(curr_switch);
                tmp.Offset  = OFFSETOF(curr_switch);
                if (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch)))
                    curr_switch = 0xFFFFFFFF;
            }
            else
            {
                tmp.Mode    = AddrMode1616;
                tmp.Segment = SELECTOROF(next_switch);
                tmp.Offset  = OFFSETOF(next_switch);
                p = sw_xlat_addr(cb, &tmp);
                if (!sw_read_mem(cb, p, &frame16, sizeof(frame16)))
                {
                    WARN("Bad stack frame 0x%08x\n", p);
                    goto done_err;
                }
                curr_switch = (DWORD)frame16.frame32;

                if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch)))
                    curr_switch = 0xFFFFFFFF;
            }
        }
        else
            /* FIXME: this will allow to work when we're not attached to a live target, 
             * but the 16 <=> 32 switch facility won't be available.
             */
            curr_switch = 0;
        frame->AddrReturn.Mode = frame->AddrStack.Mode = (curr_mode == stm_16bit) ? AddrMode1616 : AddrModeFlat;
        /* don't set up AddrStack on first call. Either the caller has set it up, or
         * we will get it in the next frame
         */
        memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
    }
    else
    {
        if (frame->AddrFrame.Offset == 0) goto done_err;
        if (frame->AddrFrame.Mode == AddrModeFlat)
        {
            assert(curr_mode == stm_32bit);
            do_switch = curr_switch && frame->AddrFrame.Offset >= curr_switch;
        }
        else
        {
            assert(curr_mode == stm_16bit);
            do_switch = curr_switch && 
                frame->AddrFrame.Segment == SELECTOROF(curr_switch) &&
                frame->AddrFrame.Offset >= OFFSETOF(curr_switch);
        }
	   
        if (do_switch)
        {
            if (curr_mode == stm_16bit)
            {
                if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32)))
                {
                    WARN("Bad stack frame 0x%08x\n", next_switch);
                    goto done_err;
                }

                frame->AddrPC.Mode        = AddrModeFlat;
                frame->AddrPC.Segment     = 0;
                frame->AddrPC.Offset      = frame32.retaddr;
                frame->AddrFrame.Mode     = AddrModeFlat;
                frame->AddrFrame.Segment  = 0;
                frame->AddrFrame.Offset   = frame32.ebp;

                frame->AddrStack.Mode     = AddrModeFlat;
                frame->AddrStack.Segment  = 0;
                frame->AddrReturn.Mode    = AddrModeFlat;
                frame->AddrReturn.Segment = 0;

                next_switch = curr_switch;
                tmp.Mode    = AddrMode1616;
                tmp.Segment = SELECTOROF(next_switch);
                tmp.Offset  = OFFSETOF(next_switch);
                p = sw_xlat_addr(cb, &tmp);

                if (!sw_read_mem(cb, p, &frame16, sizeof(frame16)))
                {
                    WARN("Bad stack frame 0x%08x\n", p);
                    goto done_err;
                }
                curr_switch = (DWORD)frame16.frame32;
                curr_mode = stm_32bit;
                if (!sw_read_mem(cb, curr_switch, &ch, sizeof(ch)))
                    curr_switch = 0;
            }
            else
            {
                tmp.Mode    = AddrMode1616;
                tmp.Segment = SELECTOROF(next_switch);
                tmp.Offset  = OFFSETOF(next_switch);
                p = sw_xlat_addr(cb, &tmp);

                if (!sw_read_mem(cb, p, &frame16, sizeof(frame16)))
                {
                    WARN("Bad stack frame 0x%08x\n", p);
                    goto done_err;
                }

                TRACE("Got a 16 bit stack switch:"
                      "\n\tframe32: %08lx"
                      "\n\tedx:%08x ecx:%08x ebp:%08x"
                      "\n\tds:%04x es:%04x fs:%04x gs:%04x"
                      "\n\tcall_from_ip:%08x module_cs:%04x relay=%08x"
                      "\n\tentry_ip:%04x entry_point:%08x"
                      "\n\tbp:%04x ip:%04x cs:%04x\n",
                      (unsigned long)frame16.frame32,
                      frame16.edx, frame16.ecx, frame16.ebp,
                      frame16.ds, frame16.es, frame16.fs, frame16.gs,
                      frame16.callfrom_ip, frame16.module_cs, frame16.relay,
                      frame16.entry_ip, frame16.entry_point,
                      frame16.bp, frame16.ip, frame16.cs);

                      
                frame->AddrPC.Mode       = AddrMode1616;
                frame->AddrPC.Segment    = frame16.cs;
                frame->AddrPC.Offset     = frame16.ip;

                frame->AddrFrame.Mode    = AddrMode1616;
                frame->AddrFrame.Segment = SELECTOROF(next_switch);
                frame->AddrFrame.Offset  = frame16.bp;

                frame->AddrStack.Mode    = AddrMode1616;
                frame->AddrStack.Segment = SELECTOROF(next_switch);

                frame->AddrReturn.Mode    = AddrMode1616;
                frame->AddrReturn.Segment = frame16.cs;

                next_switch = curr_switch;
                if (!sw_read_mem(cb, next_switch, &frame32, sizeof(frame32)))
                {
                    WARN("Bad stack frame 0x%08x\n", next_switch);
                    goto done_err;
                }
                curr_switch = (DWORD)frame32.frame16;
                tmp.Mode    = AddrMode1616;
                tmp.Segment = SELECTOROF(curr_switch);
                tmp.Offset  = OFFSETOF(curr_switch);

                if (!sw_read_mem(cb, sw_xlat_addr(cb, &tmp), &ch, sizeof(ch)))
                    curr_switch = 0;
                curr_mode = stm_16bit;
            }
        }
        else
        {
            frame->AddrPC = frame->AddrReturn;
            if (curr_mode == stm_16bit)
            {
                frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(WORD);
                /* "pop up" previous BP value */
                if (!sw_read_mem(cb, sw_xlat_addr(cb, &frame->AddrFrame),
                                 &val, sizeof(WORD)))
                    goto done_err;
                frame->AddrFrame.Offset = val;
            }
            else
            {
                frame->AddrStack.Offset = frame->AddrFrame.Offset + 2 * sizeof(DWORD);
                /* "pop up" previous EBP value */
                if (!sw_read_mem(cb, frame->AddrFrame.Offset, 
                                 &frame->AddrFrame.Offset, sizeof(DWORD)))
                    goto done_err;
            }
        }
    }

    if (curr_mode == stm_16bit)
    {
        int     i;

        p = sw_xlat_addr(cb, &frame->AddrFrame);
        if (!sw_read_mem(cb, p + sizeof(WORD), &val, sizeof(WORD)))
            goto done_err;
        frame->AddrReturn.Offset = val;
        /* get potential cs if a far call was used */
        if (!sw_read_mem(cb, p + 2 * sizeof(WORD), &val, sizeof(WORD)))
            goto done_err;
        if (frame->AddrFrame.Offset & 1)
            frame->AddrReturn.Segment = val; /* far call assumed */
        else
        {
            /* not explicitly marked as far call, 
             * but check whether it could be anyway
             */
            if ((val & 7) == 7 && val != frame->AddrReturn.Segment)
            {
                LDT_ENTRY	le;

                if (GetThreadSelectorEntry(cb->hThread, val, &le) &&
                    (le.HighWord.Bits.Type & 0x08)) /* code segment */
                {
                    /* it is very uncommon to push a code segment cs as
                     * a parameter, so this should work in most cases 
                     */
                    frame->AddrReturn.Segment = val;
                }
	    }
	}
        frame->AddrFrame.Offset &= ~1;
        /* we "pop" parameters as 16 bit entities... of course, this won't
         * work if the parameter is in fact bigger than 16bit, but
         * there's no way to know that here
         */
        for (i = 0; i < sizeof(frame->Params) / sizeof(frame->Params[0]); i++)
        {
            sw_read_mem(cb, p + (2 + i) * sizeof(WORD), &val, sizeof(val));
            frame->Params[i] = val;
        }
    }
    else
    {
        if (!sw_read_mem(cb, frame->AddrFrame.Offset + sizeof(DWORD),
                         &frame->AddrReturn.Offset, sizeof(DWORD)))
        {
            WARN("Cannot read new frame offset %08x\n", frame->AddrFrame.Offset + (int)sizeof(DWORD));
            goto done_err;
        }
        sw_read_mem(cb, frame->AddrFrame.Offset + 2 * sizeof(DWORD),
                    frame->Params, sizeof(frame->Params));
    }

    frame->Far = TRUE;
    frame->Virtual = TRUE;
    p = sw_xlat_addr(cb, &frame->AddrPC);
    if (p && sw_modl_bas(cb, p))
        frame->FuncTableEntry = sw_tabl_acs(cb, p);
    else
        frame->FuncTableEntry = NULL;

    TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s cSwitch=%08x nSwitch=%08x FuncTable=%p\n",
          wine_dbgstr_addr(&frame->AddrPC),
          wine_dbgstr_addr(&frame->AddrFrame),
          wine_dbgstr_addr(&frame->AddrReturn),
          wine_dbgstr_addr(&frame->AddrStack), 
          curr_mode == stm_start ? "start" : (curr_mode == stm_16bit ? "16bit" : "32bit"),
          curr_switch, next_switch, frame->FuncTableEntry);

    return TRUE;
done_err:
    curr_mode = stm_done;
    return FALSE;
}

/***********************************************************************
 *		StackWalk (DBGHELP.@)
 */
BOOL WINAPI StackWalk(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
                      LPSTACKFRAME frame, LPVOID ctx,
                      PREAD_PROCESS_MEMORY_ROUTINE f_read_mem,
                      PFUNCTION_TABLE_ACCESS_ROUTINE FunctionTableAccessRoutine,
                      PGET_MODULE_BASE_ROUTINE GetModuleBaseRoutine,
                      PTRANSLATE_ADDRESS_ROUTINE f_xlat_adr)
{
    struct stack_walk_callback  swcb;

    TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n",
          MachineType, hProcess, hThread, frame, ctx,
          f_read_mem, FunctionTableAccessRoutine,
          GetModuleBaseRoutine, f_xlat_adr);

    if (MachineType != IMAGE_FILE_MACHINE_I386)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    swcb.hProcess = hProcess;
    swcb.hThread = hThread;
    swcb.is32 = TRUE;
    /* sigh... MS isn't even consistent in the func prototypes */
    swcb.u.s32.f_read_mem = (f_read_mem) ? f_read_mem : read_mem;
    swcb.u.s32.f_xlat_adr = (f_xlat_adr) ? f_xlat_adr : addr_to_linear;
    swcb.u.s32.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess;
    swcb.u.s32.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase;

    return stack_walk(&swcb, frame);
}


/***********************************************************************
 *		StackWalk64 (DBGHELP.@)
 */
BOOL WINAPI StackWalk64(DWORD MachineType, HANDLE hProcess, HANDLE hThread,
                        LPSTACKFRAME64 frame64, LPVOID ctx,
                        PREAD_PROCESS_MEMORY_ROUTINE64 f_read_mem,
                        PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
                        PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
                        PTRANSLATE_ADDRESS_ROUTINE64 f_xlat_adr)
{
    struct stack_walk_callback  swcb;
    STACKFRAME                  frame32;
    BOOL                        ret;

    TRACE("(%d, %p, %p, %p, %p, %p, %p, %p, %p)\n",
          MachineType, hProcess, hThread, frame64, ctx,
          f_read_mem, FunctionTableAccessRoutine,
          GetModuleBaseRoutine, f_xlat_adr);

    if (MachineType != IMAGE_FILE_MACHINE_I386)
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    addr_64to32(&frame64->AddrPC,     &frame32.AddrPC);
    addr_64to32(&frame64->AddrReturn, &frame32.AddrReturn);
    addr_64to32(&frame64->AddrFrame,  &frame32.AddrFrame);
    addr_64to32(&frame64->AddrStack,  &frame32.AddrStack);
    addr_64to32(&frame64->AddrBStore, &frame32.AddrBStore);
    frame32.FuncTableEntry = frame64->FuncTableEntry; /* FIXME */
    frame32.Far = frame64->Far;
    frame32.Virtual = frame64->Virtual;
    frame32.Reserved[0] = (ULONG)frame64->Reserved[0];
    frame32.Reserved[1] = (ULONG)frame64->Reserved[1];
    frame32.Reserved[2] = (ULONG)frame64->Reserved[2];
    /* we don't handle KdHelp */

    swcb.hProcess = hProcess;
    swcb.hThread = hThread;
    swcb.is32 = FALSE;
    /* sigh... MS isn't even consistent in the func prototypes */
    swcb.u.s64.f_read_mem = (f_read_mem) ? f_read_mem : read_mem64;
    swcb.u.s64.f_xlat_adr = f_xlat_adr;
    swcb.u.s64.f_tabl_acs = (FunctionTableAccessRoutine) ? FunctionTableAccessRoutine : SymFunctionTableAccess64;
    swcb.u.s64.f_modl_bas = (GetModuleBaseRoutine) ? GetModuleBaseRoutine : SymGetModuleBase64;

    ret = stack_walk(&swcb, &frame32);

    addr_32to64(&frame32.AddrPC,     &frame64->AddrPC);
    addr_32to64(&frame32.AddrReturn, &frame64->AddrReturn);
    addr_32to64(&frame32.AddrFrame,  &frame64->AddrFrame);
    addr_32to64(&frame32.AddrStack,  &frame64->AddrStack);
    addr_32to64(&frame32.AddrBStore, &frame64->AddrBStore);
    frame64->FuncTableEntry = frame32.FuncTableEntry; /* FIXME */
    frame64->Params[0] = (ULONG)frame32.Params[0];
    frame64->Params[1] = (ULONG)frame32.Params[1];
    frame64->Params[2] = (ULONG)frame32.Params[2];
    frame64->Params[3] = (ULONG)frame32.Params[3];
    frame64->Far = frame32.Far;
    frame64->Virtual = frame32.Virtual;
    frame64->Reserved[0] = (ULONG)frame32.Reserved[0];
    frame64->Reserved[1] = (ULONG)frame32.Reserved[1];
    frame64->Reserved[2] = (ULONG)frame32.Reserved[2];
    /* we don't handle KdHelp */
    frame64->KdHelp.Thread = 0xC000FADE;
    frame64->KdHelp.ThCallbackStack = 0x10;
    frame64->KdHelp.ThCallbackBStore = 0;
    frame64->KdHelp.NextCallback = 0;
    frame64->KdHelp.FramePointer = 0;
    frame64->KdHelp.KiCallUserMode = 0xD000DAFE;
    frame64->KdHelp.KeUserCallbackDispatcher = 0xE000F000;
    frame64->KdHelp.SystemRangeStart = 0xC0000000;
    frame64->KdHelp.Reserved[0] /* KiUserExceptionDispatcher */ = 0xE0005000;

    return ret;
}

/******************************************************************
 *		SymRegisterFunctionEntryCallback (DBGHELP.@)
 *
 *
 */
BOOL WINAPI SymRegisterFunctionEntryCallback(HANDLE hProc,
                                             PSYMBOL_FUNCENTRY_CALLBACK cb, PVOID user)
{
    FIXME("(%p %p %p): stub!\n", hProc, cb, user);
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
}

/******************************************************************
 *		SymRegisterFunctionEntryCallback64 (DBGHELP.@)
 *
 *
 */
BOOL WINAPI SymRegisterFunctionEntryCallback64(HANDLE hProc,
                                               PSYMBOL_FUNCENTRY_CALLBACK64 cb,
                                               ULONG64 user)
{
    FIXME("(%p %p %s): stub!\n", hProc, cb, wine_dbgstr_longlong(user));
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
    return FALSE;
}

--- NEW FILE: storage.c ---
/*
 * Various storage structures (pool allocation, vector, hash table)
 *
 * Copyright (C) 1993, Eric Youngdale.
 *               2004, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */


#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include "wine/debug.h"

#include "dbghelp_private.h"
#ifdef USE_STATS
#include <math.h>
#endif

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

struct pool_arena
{
    struct pool_arena*  next;
    char*               current;
};

void pool_init(struct pool* a, unsigned arena_size)
{
    a->arena_size = arena_size;
    a->first = NULL;
}

void pool_destroy(struct pool* pool)
{
    struct pool_arena*  arena;
    struct pool_arena*  next;

#ifdef USE_STATS
    unsigned    alloc, used, num;
    
    alloc = used = num = 0;
    arena = pool->first;
    while (arena)
    {
        alloc += pool->arena_size;
        used += arena->current - (char*)arena;
        num++;
        arena = arena->next;
    }
    if (alloc == 0) alloc = 1;      /* avoid division by zero */
    FIXME("STATS: pool %p has allocated %u kbytes, used %u kbytes in %u arenas,\n"
          "\t\t\t\tnon-allocation ratio: %.2f%%\n",
          pool, alloc >> 10, used >> 10, num, 100.0 - (float)used / (float)alloc * 100.0);
#endif

    arena = pool->first;
    while (arena)
    {
        next = arena->next;
        HeapFree(GetProcessHeap(), 0, arena);
        arena = next;
    }
    pool_init(pool, 0);
}

void* pool_alloc(struct pool* pool, unsigned len)
{
    struct pool_arena*  arena;
    void*               ret;

    len = (len + 3) & ~3; /* round up size on DWORD boundary */
    assert(sizeof(struct pool_arena) + len <= pool->arena_size && len);

    for (arena = pool->first; arena; arena = arena->next)
    {
        if ((char*)arena + pool->arena_size - arena->current >= len)
        {
            ret = arena->current;
            arena->current += len;
            return ret;
        }
    }

    arena = HeapAlloc(GetProcessHeap(), 0, pool->arena_size);
    if (!arena) {FIXME("OOM\n");return NULL;}

    ret = (char*)arena + sizeof(*arena);
    arena->next = pool->first;
    pool->first = arena;
    arena->current = (char*)ret + len;
    return ret;
}

char* pool_strdup(struct pool* pool, const char* str)
{
    char* ret;
    if ((ret = pool_alloc(pool, strlen(str) + 1))) strcpy(ret, str);
    return ret;
}

void vector_init(struct vector* v, unsigned esz, unsigned bucket_sz)
{
    v->buckets = NULL;
    /* align size on DWORD boundaries */
    v->elt_size = (esz + 3) & ~3;
    switch (bucket_sz)
    {
    case    2: v->shift =  1; break;
    case    4: v->shift =  2; break;
    case    8: v->shift =  3; break;
    case   16: v->shift =  4; break;
    case   32: v->shift =  5; break;
    case   64: v->shift =  6; break;
    case  128: v->shift =  7; break;
    case  256: v->shift =  8; break;
    case  512: v->shift =  9; break;
    case 1024: v->shift = 10; break;
    default: assert(0);
    }
    v->num_buckets = 0;
    v->buckets_allocated = 0;
    v->num_elts = 0;
}

unsigned vector_length(const struct vector* v)
{
    return v->num_elts;
}

void* vector_at(const struct vector* v, unsigned pos)
{
    unsigned o;

    if (pos >= v->num_elts) return NULL;
    o = pos & ((1 << v->shift) - 1);
    return (char*)v->buckets[pos >> v->shift] + o * v->elt_size;
}

void* vector_add(struct vector* v, struct pool* pool)
{
    unsigned    ncurr = v->num_elts++;

    /* check that we don't wrap around */
    assert(v->num_elts > ncurr);
    if (ncurr == (v->num_buckets << v->shift))
    {
        if(v->num_buckets == v->buckets_allocated)
        {
            /* Double the bucket cache, so it scales well with big vectors.*/
            unsigned    new_reserved;
            void*       new;

            new_reserved = 2*v->buckets_allocated;
            if(new_reserved == 0) new_reserved = 1;

            /* Don't even try to resize memory.
               Pool datastructure is very inefficient with reallocs. */
            new = pool_alloc(pool, new_reserved * sizeof(void*));
            memcpy(new, v->buckets, v->buckets_allocated * sizeof(void*));
            v->buckets = new;
            v->buckets_allocated = new_reserved;
        }
        v->buckets[v->num_buckets] = pool_alloc(pool, v->elt_size << v->shift);
        return v->buckets[v->num_buckets++];
    }
    return vector_at(v, ncurr);
}

/* We construct the sparse array as two vectors (of equal size)
 * The first vector (key2index) is the lookup table between the key and
 * an index in the second vector (elements)
 * When inserting an element, it's always appended in second vector (and
 * never moved in memory later on), only the first vector is reordered
 */
struct key2index
{
    unsigned long       key;
    unsigned            index;
};

void sparse_array_init(struct sparse_array* sa, unsigned elt_sz, unsigned bucket_sz)
{
    vector_init(&sa->key2index, sizeof(struct key2index), bucket_sz);
    vector_init(&sa->elements, elt_sz, bucket_sz);
}

/******************************************************************
 *		sparse_array_lookup
 *
 * Returns the first index which key is >= at passed key
 */
static struct key2index* sparse_array_lookup(const struct sparse_array* sa,
                                             unsigned long key, unsigned* idx)
{
    struct key2index*   pk2i;
    unsigned            low, high;

    if (!sa->elements.num_elts)
    {
        *idx = 0;
        return NULL;
    }
    high = sa->elements.num_elts;
    pk2i = vector_at(&sa->key2index, high - 1);
    if (pk2i->key < key)
    {
        *idx = high;
        return NULL;
    }
    if (pk2i->key == key)
    {
        *idx = high - 1;
        return pk2i;
    }
    low = 0;
    pk2i = vector_at(&sa->key2index, low);
    if (pk2i->key >= key)
    {
        *idx = 0;
        return pk2i;
    }
    /* now we have: sa(lowest key) < key < sa(highest key) */
    while (low < high)
    {
        *idx = (low + high) / 2;
        pk2i = vector_at(&sa->key2index, *idx);
        if (pk2i->key > key)            high = *idx;
        else if (pk2i->key < key)       low = *idx + 1;
        else                            return pk2i;
    }
    /* binary search could return exact item, we search for highest one
     * below the key
     */
    if (pk2i->key < key)
        pk2i = vector_at(&sa->key2index, ++(*idx));
    return pk2i;
}

void*   sparse_array_find(const struct sparse_array* sa, unsigned long key)
{
    unsigned            idx;
    struct key2index*   pk2i;

    if ((pk2i = sparse_array_lookup(sa, key, &idx)) && pk2i->key == key)
        return vector_at(&sa->elements, pk2i->index);
    return NULL;
}

void*   sparse_array_add(struct sparse_array* sa, unsigned long key, 
                         struct pool* pool)
{
    unsigned            idx, i;
    struct key2index*   pk2i;
    struct key2index*   to;

    pk2i = sparse_array_lookup(sa, key, &idx);
    if (pk2i && pk2i->key == key)
    {
        FIXME("re adding an existing key\n");
        return NULL;
    }
    to = vector_add(&sa->key2index, pool);
    if (pk2i)
    {
        /* we need to shift vector's content... */
        /* let's do it brute force... (FIXME) */
        assert(sa->key2index.num_elts >= 2);
        for (i = sa->key2index.num_elts - 1; i > idx; i--)
        {
            pk2i = vector_at(&sa->key2index, i - 1);
            *to = *pk2i;
            to = pk2i;
        }
    }

    to->key = key;
    to->index = sa->elements.num_elts;

    return vector_add(&sa->elements, pool);
}

unsigned sparse_array_length(const struct sparse_array* sa)
{
    return sa->elements.num_elts;
}

unsigned hash_table_hash(const char* name, unsigned num_buckets)
{
    unsigned    hash = 0;
    while (*name)
    {
        hash += *name++;
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);
    return hash % num_buckets;
}

void hash_table_init(struct pool* pool, struct hash_table* ht, unsigned num_buckets)
{
    ht->num_elts = 0;
    ht->num_buckets = num_buckets;
    ht->pool = pool;
    ht->buckets = NULL;
}

void hash_table_destroy(struct hash_table* ht)
{
#if defined(USE_STATS)
    int                         i;
    unsigned                    len;
    unsigned                    min = 0xffffffff, max = 0, sq = 0;
    struct hash_table_elt*      elt;
    double                      mean, variance;

    for (i = 0; i < ht->num_buckets; i++)
    {
        for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
        if (len < min) min = len;
        if (len > max) max = len;
        sq += len * len;
    }
    mean = (double)ht->num_elts / ht->num_buckets;
    variance = (double)sq / ht->num_buckets - mean * mean;
    FIXME("STATS: elts[num:%-4u size:%u mean:%f] buckets[min:%-4u variance:%+f max:%-4u]\n",
          ht->num_elts, ht->num_buckets, mean, min, variance, max);
#if 1
    for (i = 0; i < ht->num_buckets; i++)
    {
        for (len = 0, elt = ht->buckets[i]; elt; elt = elt->next) len++;
        if (len == max)
        {
            FIXME("Longuest bucket:\n");
            for (elt = ht->buckets[i]; elt; elt = elt->next)
                FIXME("\t%s\n", elt->name);
            break;
        }

    }
#endif
#endif
}

void hash_table_add(struct hash_table* ht, struct hash_table_elt* elt)
{
    unsigned                    hash = hash_table_hash(elt->name, ht->num_buckets);
    struct hash_table_elt**     p;

    if (!ht->buckets)
    {
        ht->buckets = pool_alloc(ht->pool, ht->num_buckets * sizeof(struct hash_table_elt*));
        assert(ht->buckets);
        memset(ht->buckets, 0, ht->num_buckets * sizeof(struct hash_table_elt*));
    }

    /* in some cases, we need to get back the symbols of same name in the order
     * in which they've been inserted. So insert new elements at the end of the list.
     */
    for (p = &ht->buckets[hash]; *p; p = &((*p)->next));
    *p = elt;
    elt->next = NULL;
    ht->num_elts++;
}

void* hash_table_find(const struct hash_table* ht, const char* name)
{
    unsigned                    hash = hash_table_hash(name, ht->num_buckets);
    struct hash_table_elt*      elt;

    if(!ht->buckets) return NULL;

    for (elt = ht->buckets[hash]; elt; elt = elt->next)
        if (!strcmp(name, elt->name)) return elt;
    return NULL;
}

void hash_table_iter_init(const struct hash_table* ht, 
                          struct hash_table_iter* hti, const char* name)
{
    hti->ht = ht;
    if (name)
    {
        hti->last = hash_table_hash(name, ht->num_buckets);
        hti->index = hti->last - 1;
    }
    else
    {
        hti->last = ht->num_buckets - 1;
        hti->index = -1;
    }
    hti->element = NULL;
}

void* hash_table_iter_up(struct hash_table_iter* hti)
{
    if(!hti->ht->buckets) return NULL;

    if (hti->element) hti->element = hti->element->next;
    while (!hti->element && hti->index < hti->last) 
        hti->element = hti->ht->buckets[++hti->index];
    return hti->element;
}

--- NEW FILE: symbol.c ---
/*
 * File symbol.c - management of symbols (lexical tree)
 *
 * Copyright (C) 1993, Eric Youngdale.
 *               2004, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
[...1614 lines suppressed...]
          wine_dbgstr_longlong(Address), EnumSymbolsCallback,
          UserContext, Options);

    sew.ctx = UserContext;
    sew.cb = EnumSymbolsCallback;
    sew.sym_info = (PSYMBOL_INFOW)sew.buffer;

    if (Mask)
    {
        unsigned len = WideCharToMultiByte(CP_ACP, 0, Mask, -1, NULL, 0, NULL, NULL);
        maskA = HeapAlloc(GetProcessHeap(), 0, len);
        if (!maskA) return FALSE;
        WideCharToMultiByte(CP_ACP, 0, Mask, -1, maskA, len, NULL, NULL);
    }
    ret = SymSearch(hProcess, BaseOfDll, Index, SymTag, maskA, Address,
                    sym_enumW, &sew, Options);
    HeapFree(GetProcessHeap(), 0, maskA);

    return ret;
}

--- NEW FILE: type.c ---
/*
 * File types.c - management of types (hierarchical tree)
 *
 * Copyright (C) 1997, Eric Youngdale.
 *               2004, Eric Pouech.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * Note: This really doesn't do much at the moment, but it forms the framework
 * upon which full support for datatype handling will eventually be built.
 */
#include "config.h"
#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>

#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "wine/debug.h"
#include "dbghelp_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);
WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt);

static const char* symt_get_tag_str(DWORD tag)
{
    switch (tag)
    {
    case SymTagNull:                    return "SymTagNull";
    case SymTagExe:                     return "SymTagExe";
    case SymTagCompiland:               return "SymTagCompiland";
    case SymTagCompilandDetails:        return "SymTagCompilandDetails";
    case SymTagCompilandEnv:            return "SymTagCompilandEnv";
    case SymTagFunction:                return "SymTagFunction";
    case SymTagBlock:                   return "SymTagBlock";
    case SymTagData:                    return "SymTagData";
    case SymTagAnnotation:              return "SymTagAnnotation";
    case SymTagLabel:                   return "SymTagLabel";
    case SymTagPublicSymbol:            return "SymTagPublicSymbol";
    case SymTagUDT:                     return "SymTagUDT";
    case SymTagEnum:                    return "SymTagEnum";
    case SymTagFunctionType:            return "SymTagFunctionType";
    case SymTagPointerType:             return "SymTagPointerType";
    case SymTagArrayType:               return "SymTagArrayType";
    case SymTagBaseType:                return "SymTagBaseType";
    case SymTagTypedef:                 return "SymTagTypedef,";
    case SymTagBaseClass:               return "SymTagBaseClass";
    case SymTagFriend:                  return "SymTagFriend";
    case SymTagFunctionArgType:         return "SymTagFunctionArgType,";
    case SymTagFuncDebugStart:          return "SymTagFuncDebugStart,";
    case SymTagFuncDebugEnd:            return "SymTagFuncDebugEnd";
    case SymTagUsingNamespace:          return "SymTagUsingNamespace,";
    case SymTagVTableShape:             return "SymTagVTableShape";
    case SymTagVTable:                  return "SymTagVTable";
    case SymTagCustom:                  return "SymTagCustom";
    case SymTagThunk:                   return "SymTagThunk";
    case SymTagCustomType:              return "SymTagCustomType";
    case SymTagManagedType:             return "SymTagManagedType";
    case SymTagDimension:               return "SymTagDimension";
    default:                            return "---";
    }
}

const char* symt_get_name(const struct symt* sym)
{
    switch (sym->tag)
    {
    /* lexical tree */
    case SymTagData:            return ((const struct symt_data*)sym)->hash_elt.name;
    case SymTagFunction:        return ((const struct symt_function*)sym)->hash_elt.name;
    case SymTagPublicSymbol:    return ((const struct symt_public*)sym)->hash_elt.name;
    case SymTagBaseType:        return ((const struct symt_basic*)sym)->hash_elt.name;
    case SymTagLabel:           return ((const struct symt_function_point*)sym)->name;
    case SymTagThunk:           return ((const struct symt_thunk*)sym)->hash_elt.name;
    /* hierarchy tree */
    case SymTagEnum:            return ((const struct symt_enum*)sym)->name;
    case SymTagTypedef:         return ((const struct symt_typedef*)sym)->hash_elt.name;
    case SymTagUDT:             return ((const struct symt_udt*)sym)->hash_elt.name;
    default:
        FIXME("Unsupported sym-tag %s\n", symt_get_tag_str(sym->tag));
        /* fall through */
    case SymTagArrayType:
    case SymTagPointerType:
    case SymTagFunctionType:
        return NULL;
    }
}

static struct symt* symt_find_type_by_name(const struct module* module,
                                           enum SymTagEnum sym_tag, 
                                           const char* typename)
{
    void*                       ptr;
    struct symt_ht*             type;
    struct hash_table_iter      hti;

    assert(typename);
    assert(module);

    hash_table_iter_init(&module->ht_types, &hti, typename);
    while ((ptr = hash_table_iter_up(&hti)))
    {
        type = GET_ENTRY(ptr, struct symt_ht, hash_elt);

        if ((sym_tag == SymTagNull || type->symt.tag == sym_tag) &&
            type->hash_elt.name && !strcmp(type->hash_elt.name, typename))
            return &type->symt;
    }
    SetLastError(ERROR_INVALID_NAME); /* FIXME ?? */
    return NULL;
}

static void symt_add_type(struct module* module, struct symt* symt)
{
    struct symt**       p;
    p = vector_add(&module->vtypes, &module->pool);
    assert(p);
    *p = symt;
}

struct symt_basic* symt_new_basic(struct module* module, enum BasicType bt, 
                                  const char* typename, unsigned size)
{
    struct symt_basic*          sym;

    if (typename)
    {
        sym = (struct symt_basic*)symt_find_type_by_name(module, SymTagBaseType,
                                                         typename);
        if (sym && sym->bt == bt && sym->size == size)
            return sym;
    }
    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag = SymTagBaseType;
        if (typename)
        {
            sym->hash_elt.name = pool_strdup(&module->pool, typename);
            hash_table_add(&module->ht_types, &sym->hash_elt);
        } else sym->hash_elt.name = NULL;
        sym->bt = bt;
        sym->size = size;
        symt_add_type(module, &sym->symt);
    }
    return sym;
}

struct symt_udt* symt_new_udt(struct module* module, const char* typename, 
                              unsigned size, enum UdtKind kind)
{
    struct symt_udt*            sym;

    TRACE_(dbghelp_symt)("Adding udt %s:%s\n",
                         debugstr_w(module->module.ModuleName), typename);
    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag = SymTagUDT;
        sym->kind     = kind;
        sym->size     = size;
        if (typename)
        {
            sym->hash_elt.name = pool_strdup(&module->pool, typename);
            hash_table_add(&module->ht_types, &sym->hash_elt);
        } else sym->hash_elt.name = NULL;
        vector_init(&sym->vchildren, sizeof(struct symt*), 8);
        symt_add_type(module, &sym->symt);
    }
    return sym;
}

BOOL symt_set_udt_size(struct module* module, struct symt_udt* udt, unsigned size)
{
    assert(udt->symt.tag == SymTagUDT);
    if (vector_length(&udt->vchildren) != 0)
    {
        if (udt->size != size)
            FIXME_(dbghelp_symt)("Changing size for %s from %u to %u\n", 
                                 udt->hash_elt.name, udt->size, size);
        return TRUE;
    }
    udt->size = size;
    return TRUE;
}

/******************************************************************
 *		symt_add_udt_element
 *
 * add an element to a udt (struct, class, union)
 * the size & offset parameters are expressed in bits (not bytes) so that
 * we can mix in the single call bytes aligned elements (regular fields) and
 * the others (bit fields)
 */
BOOL symt_add_udt_element(struct module* module, struct symt_udt* udt_type,
                          const char* name, struct symt* elt_type,
                          unsigned offset, unsigned size)
{
    struct symt_data*   m;
    struct symt**       p;

    assert(udt_type->symt.tag == SymTagUDT);

    TRACE_(dbghelp_symt)("Adding %s to UDT %s\n", name, udt_type->hash_elt.name);
    if (name)
    {
        int    i;
        for (i=0; i<vector_length(&udt_type->vchildren); i++)
        {
            m = *(struct symt_data**)vector_at(&udt_type->vchildren, i);
            assert(m);
            assert(m->symt.tag == SymTagData);
            if (strcmp(m->hash_elt.name, name) == 0)
                return TRUE;
        }
    }

    if ((m = pool_alloc(&module->pool, sizeof(*m))) == NULL) return FALSE;
    memset(m, 0, sizeof(*m));
    m->symt.tag      = SymTagData;
    m->hash_elt.name = name ? pool_strdup(&module->pool, name) : "";
    m->hash_elt.next = NULL;

    m->kind            = DataIsMember;
    m->container       = &udt_type->symt;
    m->type            = elt_type;
    m->u.member.offset = offset;
    m->u.member.length = ((offset & 7) || (size & 7)) ? size : 0;
    p = vector_add(&udt_type->vchildren, &module->pool);
    *p = &m->symt;

    return TRUE;
}

struct symt_enum* symt_new_enum(struct module* module, const char* typename)
{
    struct symt_enum*   sym;

    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag            = SymTagEnum;
        sym->name = (typename) ? pool_strdup(&module->pool, typename) : NULL;
        vector_init(&sym->vchildren, sizeof(struct symt*), 8);
    }
    return sym;
}

BOOL symt_add_enum_element(struct module* module, struct symt_enum* enum_type,
                           const char* name, int value)
{
    struct symt_data*   e;
    struct symt**       p;

    assert(enum_type->symt.tag == SymTagEnum);
    e = pool_alloc(&module->pool, sizeof(*e));
    if (e == NULL) return FALSE;

    e->symt.tag = SymTagData;
    e->hash_elt.name = pool_strdup(&module->pool, name);
    e->hash_elt.next = NULL;
    e->kind = DataIsConstant;
    e->container = &enum_type->symt;
    /* CV defines the underlying type for the enumeration */
    e->type = &symt_new_basic(module, btInt, "int", 4)->symt;
    e->u.value.n1.n2.vt = VT_I4;
    e->u.value.n1.n2.n3.lVal = value;

    p = vector_add(&enum_type->vchildren, &module->pool);
    if (!p) return FALSE; /* FIXME we leak e */
    *p = &e->symt;

    return TRUE;
}

struct symt_array* symt_new_array(struct module* module, int min, int max, 
                                  struct symt* base, struct symt* index)
{
    struct symt_array*  sym;

    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag   = SymTagArrayType;
        sym->start      = min;
        sym->end        = max;
        sym->base_type  = base;
        sym->index_type = index;
        symt_add_type(module, &sym->symt);
    }
    return sym;
}

struct symt_function_signature* symt_new_function_signature(struct module* module, 
                                                            struct symt* ret_type,
                                                            enum CV_call_e call_conv)
{
    struct symt_function_signature*     sym;

    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag = SymTagFunctionType;
        sym->rettype  = ret_type;
        vector_init(&sym->vchildren, sizeof(struct symt*), 4);
        sym->call_conv = call_conv;
        symt_add_type(module, &sym->symt);
    }
    return sym;
}

BOOL symt_add_function_signature_parameter(struct module* module,
                                           struct symt_function_signature* sig_type,
                                           struct symt* param)
{
    struct symt**                       p;
    struct symt_function_arg_type*      arg;

    assert(sig_type->symt.tag == SymTagFunctionType);
    arg = pool_alloc(&module->pool, sizeof(*arg));
    if (!arg) return FALSE;
    arg->symt.tag = SymTagFunctionArgType;
    arg->arg_type = param;
    arg->container = &sig_type->symt;
    p = vector_add(&sig_type->vchildren, &module->pool);
    if (!p) return FALSE; /* FIXME we leak arg */
    *p = &arg->symt;

    return TRUE;
}

struct symt_pointer* symt_new_pointer(struct module* module, struct symt* ref_type)
{
    struct symt_pointer*        sym;

    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag = SymTagPointerType;
        sym->pointsto = ref_type;
        symt_add_type(module, &sym->symt);
    }
    return sym;
}

struct symt_typedef* symt_new_typedef(struct module* module, struct symt* ref, 
                                      const char* name)
{
    struct symt_typedef* sym;

    if ((sym = pool_alloc(&module->pool, sizeof(*sym))))
    {
        sym->symt.tag = SymTagTypedef;
        sym->type     = ref;
        sym->hash_elt.name = pool_strdup(&module->pool, name);
        hash_table_add(&module->ht_types, &sym->hash_elt);
        symt_add_type(module, &sym->symt);
    }
    return sym;
}

/******************************************************************
 *		SymEnumTypes (DBGHELP.@)
 *
 */
BOOL WINAPI SymEnumTypes(HANDLE hProcess, ULONG64 BaseOfDll,
                         PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback,
                         PVOID UserContext)
{
    struct module_pair  pair;
    char                buffer[sizeof(SYMBOL_INFO) + 256];
    SYMBOL_INFO*        sym_info = (SYMBOL_INFO*)buffer;
    const char*         tmp;
    struct symt*        type;
    DWORD64             size;
    int                 i;

    TRACE("(%p %s %p %p)\n",
          hProcess, wine_dbgstr_longlong(BaseOfDll), EnumSymbolsCallback,
          UserContext);

    if (!(pair.pcs = process_find_by_handle(hProcess))) return FALSE;
    pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN);
    if (!module_get_debug(&pair)) return FALSE;

    sym_info->SizeOfStruct = sizeof(SYMBOL_INFO);
    sym_info->MaxNameLen = sizeof(buffer) - sizeof(SYMBOL_INFO);

    for (i=0; i<vector_length(&pair.effective->vtypes); i++)
    {
        type = *(struct symt**)vector_at(&pair.effective->vtypes, i);
        sym_info->TypeIndex = (DWORD)type;
        sym_info->info = 0; /* FIXME */
        symt_get_info(type, TI_GET_LENGTH, &size);
        sym_info->Size = size;
        sym_info->ModBase = pair.requested->module.BaseOfImage;
        sym_info->Flags = 0; /* FIXME */
        sym_info->Value = 0; /* FIXME */
        sym_info->Address = 0; /* FIXME */
        sym_info->Register = 0; /* FIXME */
        sym_info->Scope = 0; /* FIXME */
        sym_info->Tag = type->tag;
        tmp = symt_get_name(type);
        if (tmp)
        {
            sym_info->NameLen = min(strlen(tmp),sym_info->MaxNameLen-1);
            memcpy(sym_info->Name, tmp, sym_info->NameLen);
            sym_info->Name[sym_info->NameLen] = '\0';
        }
        else
           sym_info->Name[sym_info->NameLen = 0] = '\0';
        if (!EnumSymbolsCallback(sym_info, sym_info->Size, UserContext)) break;
    }
    return TRUE;
}

struct enum_types_AtoW
{
    char                                buffer[sizeof(SYMBOL_INFOW) + 256 * sizeof(WCHAR)];
    void*                               user;
    PSYM_ENUMERATESYMBOLS_CALLBACKW     callback;
};

BOOL CALLBACK enum_types_AtoW(PSYMBOL_INFO si, ULONG addr, PVOID _et)
{
    struct enum_types_AtoW*     et = _et;
    SYMBOL_INFOW*               siW = (SYMBOL_INFOW*)et->buffer;

    copy_symbolW(siW, si);
    return et->callback(siW, addr, et->user);
}

/******************************************************************
 *		SymEnumTypesW (DBGHELP.@)
 *
 */
BOOL WINAPI SymEnumTypesW(HANDLE hProcess, ULONG64 BaseOfDll,
                          PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback,
                          PVOID UserContext)
{
    struct enum_types_AtoW     et;

    et.callback = EnumSymbolsCallback;
    et.user = UserContext;

    return SymEnumTypes(hProcess, BaseOfDll, enum_types_AtoW, &et);
}

/******************************************************************
 *		symt_get_info
 *
 * Retrieves information about a symt (either symbol or type)
 */
BOOL symt_get_info(const struct symt* type, IMAGEHLP_SYMBOL_TYPE_INFO req, 
                   void* pInfo)
{
    unsigned            len;

    if (!type) return FALSE;

/* helper to typecast pInfo to its expected type (_t) */
#define X(_t) (*((_t*)pInfo))

    switch (req)
    {
    case TI_FINDCHILDREN:
        {
            const struct vector*        v;
            struct symt**               pt;
            unsigned                    i;
            TI_FINDCHILDREN_PARAMS*     tifp = pInfo;

            switch (type->tag)
            {
            case SymTagUDT:          v = &((const struct symt_udt*)type)->vchildren; break;
            case SymTagEnum:         v = &((const struct symt_enum*)type)->vchildren; break;
            case SymTagFunctionType: v = &((const struct symt_function_signature*)type)->vchildren; break;
            case SymTagFunction:     v = &((const struct symt_function*)type)->vchildren; break;
            default:
                FIXME("Unsupported sym-tag %s for find-children\n", 
                      symt_get_tag_str(type->tag));
                return FALSE;
            }
            for (i = 0; i < tifp->Count; i++)
            {
                if (!(pt = vector_at(v, tifp->Start + i))) return FALSE;
                tifp->ChildId[i] = (DWORD)*pt;
            }
        }
        break;

    case TI_GET_ADDRESS:
        switch (type->tag)
        {
        case SymTagData:
            switch (((const struct symt_data*)type)->kind)
            {
            case DataIsGlobal:
            case DataIsFileStatic:
                X(ULONG64) = ((const struct symt_data*)type)->u.var.offset;
                break;
            default: return FALSE;
            }
            break;
        case SymTagFunction:
            X(ULONG64) = ((const struct symt_function*)type)->address;
            break;
        case SymTagPublicSymbol:
            X(ULONG64) = ((const struct symt_public*)type)->address;
            break;
        case SymTagFuncDebugStart:
        case SymTagFuncDebugEnd:
        case SymTagLabel:
            X(ULONG64) = ((const struct symt_function_point*)type)->parent->address + 
                ((const struct symt_function_point*)type)->loc.offset;
            break;
        case SymTagThunk:
            X(ULONG64) = ((const struct symt_thunk*)type)->address;
            break;
        case SymTagCompiland:
            X(ULONG64) = ((const struct symt_compiland*)type)->address;
            break;
        default:
            FIXME("Unsupported sym-tag %s for get-address\n", 
                  symt_get_tag_str(type->tag));
            return FALSE;
        }
        break;

    case TI_GET_BASETYPE:
        switch (type->tag)
        {
        case SymTagBaseType:
            X(DWORD) = ((const struct symt_basic*)type)->bt;
            break;
        case SymTagEnum:
            X(DWORD) = btInt;
            break;
        default:
            return FALSE;
        }
        break;

    case TI_GET_BITPOSITION:
        if (type->tag == SymTagData &&
            ((const struct symt_data*)type)->kind == DataIsMember &&
            ((const struct symt_data*)type)->u.member.length != 0)
            X(DWORD) = ((const struct symt_data*)type)->u.member.offset & 7;
        else return FALSE;
        break;

    case TI_GET_CHILDRENCOUNT:
        switch (type->tag)
        {
        case SymTagUDT:
            X(DWORD) = vector_length(&((const struct symt_udt*)type)->vchildren);
            break;
        case SymTagEnum:
            X(DWORD) = vector_length(&((const struct symt_enum*)type)->vchildren);
            break;
        case SymTagFunctionType:
            X(DWORD) = vector_length(&((const struct symt_function_signature*)type)->vchildren);
            break;
        case SymTagFunction:
            X(DWORD) = vector_length(&((const struct symt_function*)type)->vchildren);
            break;
        case SymTagPointerType: /* MS does it that way */
        case SymTagArrayType: /* MS does it that way */
        case SymTagThunk: /* MS does it that way */
            X(DWORD) = 0;
            break;
        default:
            FIXME("Unsupported sym-tag %s for get-children-count\n", 
                  symt_get_tag_str(type->tag));
            /* fall through */
        case SymTagData:
        case SymTagPublicSymbol:
        case SymTagBaseType:
            return FALSE;
        }
        break;

    case TI_GET_COUNT:
        switch (type->tag)
        {
        case SymTagArrayType:
            X(DWORD) = ((const struct symt_array*)type)->end - 
                ((const struct symt_array*)type)->start + 1;
            break;
        case SymTagFunctionType:
            /* this seems to be wrong for (future) C++ methods, where 'this' parameter
             * should be included in this value (and not in GET_CHILDREN_COUNT)
             */
            X(DWORD) = vector_length(&((const struct symt_function_signature*)type)->vchildren);
            break;
        default: return FALSE;
        }
        break;

    case TI_GET_DATAKIND:
        if (type->tag != SymTagData) return FALSE;
        X(DWORD) = ((const struct symt_data*)type)->kind;
        break;

    case TI_GET_LENGTH:
        switch (type->tag)
        {
        case SymTagBaseType:
            X(DWORD64) = ((const struct symt_basic*)type)->size;
            break;
        case SymTagFunction:
            X(DWORD64) = ((const struct symt_function*)type)->size;
            break;
        case SymTagPointerType:
            X(DWORD64) = sizeof(void*);
            break;
        case SymTagUDT:
            X(DWORD64) = ((const struct symt_udt*)type)->size;
            break;
        case SymTagEnum:
            X(DWORD64) = sizeof(int); /* FIXME: should be size of base-type of enum !!! */
            break;
        case SymTagData:
            if (((const struct symt_data*)type)->kind != DataIsMember ||
                !((const struct symt_data*)type)->u.member.length)
                return FALSE;
            X(DWORD64) = ((const struct symt_data*)type)->u.member.length;
            break;
        case SymTagArrayType:   
            if (!symt_get_info(((const struct symt_array*)type)->base_type, 
                               TI_GET_LENGTH, pInfo))
                return FALSE;
            X(DWORD64) *= ((const struct symt_array*)type)->end - 
                ((const struct symt_array*)type)->start + 1;
            break;
        case SymTagPublicSymbol:
            X(DWORD64) = ((const struct symt_public*)type)->size;
            break;
        case SymTagTypedef:
            return symt_get_info(((const struct symt_typedef*)type)->type, TI_GET_LENGTH, pInfo);
        case SymTagThunk:
            X(DWORD64) = ((const struct symt_thunk*)type)->size;
            break;
        default:
            FIXME("Unsupported sym-tag %s for get-length\n", 
                  symt_get_tag_str(type->tag));
            /* fall through */
        case SymTagFunctionType:
            return 0;
        }
        break;

    case TI_GET_LEXICALPARENT:
        switch (type->tag)
        {
        case SymTagBlock:
            X(DWORD) = (DWORD)((const struct symt_block*)type)->container;
            break;
        case SymTagData:
            X(DWORD) = (DWORD)((const struct symt_data*)type)->container;
            break;
        case SymTagFunction:
            X(DWORD) = (DWORD)((const struct symt_function*)type)->container;
            break;
        case SymTagThunk:
            X(DWORD) = (DWORD)((const struct symt_thunk*)type)->container;
            break;
        case SymTagFunctionArgType:
            X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->container;
            break;
        default:
            FIXME("Unsupported sym-tag %s for get-lexical-parent\n", 
                  symt_get_tag_str(type->tag));
            return FALSE;
        }
        break;

    case TI_GET_NESTED:
        switch (type->tag)
        {
        case SymTagUDT:
        case SymTagEnum:
            X(DWORD) = 0;
            break;
        default:
            return FALSE;
        }
        break;

    case TI_GET_OFFSET:
        switch (type->tag)
        {
        case SymTagData:
            switch (((const struct symt_data*)type)->kind)
            {
            case DataIsParam:
            case DataIsLocal:
                X(ULONG) = ((const struct symt_data*)type)->u.var.offset; 
                break;
            case DataIsMember:
                X(ULONG) = ((const struct symt_data*)type)->u.member.offset >> 3; 
                break;
            default:
                FIXME("Unknown kind (%u) for get-offset\n",     
                      ((const struct symt_data*)type)->kind);
                return FALSE;
            }
            break;
        default:
            FIXME("Unsupported sym-tag %s for get-offset\n", 
                  symt_get_tag_str(type->tag));
            return FALSE;
        }
        break;

    case TI_GET_SYMNAME:
        {
            const char* name = symt_get_name(type);
            if (!name) return FALSE;
            len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
            X(WCHAR*) = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
            if (!X(WCHAR*)) return FALSE;
            MultiByteToWideChar(CP_ACP, 0, name, -1, X(WCHAR*), len);
        }
        break;

    case TI_GET_SYMTAG:
        X(DWORD) = type->tag;
        break;

    case TI_GET_TYPE:
    case TI_GET_TYPEID:
        switch (type->tag)
        {
            /* hierarchical => hierarchical */
        case SymTagArrayType:
            X(DWORD) = (DWORD)((const struct symt_array*)type)->base_type;
            break;
        case SymTagPointerType:
            X(DWORD) = (DWORD)((const struct symt_pointer*)type)->pointsto;
            break;
        case SymTagFunctionType:
            X(DWORD) = (DWORD)((const struct symt_function_signature*)type)->rettype;
            break;
        case SymTagTypedef:
            X(DWORD) = (DWORD)((const struct symt_typedef*)type)->type;
            break;
            /* lexical => hierarchical */
        case SymTagData:
            X(DWORD) = (DWORD)((const struct symt_data*)type)->type; 
            break;
        case SymTagFunction:
            X(DWORD) = (DWORD)((const struct symt_function*)type)->type;
            break;
            /* FIXME: should also work for enums */
        case SymTagFunctionArgType:
            X(DWORD) = (DWORD)((const struct symt_function_arg_type*)type)->arg_type;
            break;
        default:
            FIXME("Unsupported sym-tag %s for get-type\n", 
                  symt_get_tag_str(type->tag));
        case SymTagPublicSymbol:
        case SymTagThunk:
            return FALSE;
        }
        break;

    case TI_GET_UDTKIND:
        if (type->tag != SymTagUDT) return FALSE;
        X(DWORD) = ((const struct symt_udt*)type)->kind;
        break;

    case TI_GET_VALUE:
        if (type->tag != SymTagData || ((const struct symt_data*)type)->kind != DataIsConstant)
            return FALSE;
        X(VARIANT) = ((const struct symt_data*)type)->u.value;
        break;

    case TI_GET_CALLING_CONVENTION:
        if (type->tag != SymTagFunctionType) return FALSE;
        if (((const struct symt_function_signature*)type)->call_conv == -1)
        {
            FIXME("No support for calling convention for this signature\n");
            X(DWORD) = CV_CALL_FAR_C; /* FIXME */
        }
        else X(DWORD) = ((const struct symt_function_signature*)type)->call_conv;
        break;
    case TI_GET_ARRAYINDEXTYPEID:
        if (type->tag != SymTagArrayType) return FALSE;
        X(DWORD) = (DWORD)((const struct symt_array*)type)->index_type;
        break;

#undef X

    case TI_GET_ADDRESSOFFSET:
    case TI_GET_CLASSPARENTID:
    case TI_GET_SYMINDEX:
    case TI_GET_THISADJUST:
    case TI_GET_VIRTUALBASECLASS:
    case TI_GET_VIRTUALBASEPOINTEROFFSET:
    case TI_GET_VIRTUALTABLESHAPEID:
    case TI_IS_EQUIV_TO:
        FIXME("Unsupported GetInfo request (%u)\n", req);
        return FALSE;
    default:
        FIXME("Unknown GetInfo request (%u)\n", req);
        return FALSE;
    }

    return TRUE;
}

/******************************************************************
 *		SymGetTypeInfo (DBGHELP.@)
 *
 */
BOOL WINAPI SymGetTypeInfo(HANDLE hProcess, DWORD64 ModBase,
                           ULONG TypeId, IMAGEHLP_SYMBOL_TYPE_INFO GetType,
                           PVOID pInfo)
{
    struct module_pair  pair;

    pair.pcs = process_find_by_handle(hProcess);
    if (!pair.pcs) return FALSE;

    pair.requested = module_find_by_addr(pair.pcs, ModBase, DMT_UNKNOWN);
    if (!module_get_debug(&pair))
    {
        FIXME("Someone didn't properly set ModBase (%s)\n", wine_dbgstr_longlong(ModBase));
        return FALSE;
    }

    return symt_get_info((struct symt*)TypeId, GetType, pInfo);
}

/******************************************************************
 *		SymGetTypeFromName (DBGHELP.@)
 *
 */
BOOL WINAPI SymGetTypeFromName(HANDLE hProcess, ULONG64 BaseOfDll,
                               PCSTR Name, PSYMBOL_INFO Symbol)
{
    struct process*     pcs = process_find_by_handle(hProcess);
    struct module*      module;
    struct symt*        type;

    if (!pcs) return FALSE;
    module = module_find_by_addr(pcs, BaseOfDll, DMT_UNKNOWN);
    if (!module) return FALSE;
    type = symt_find_type_by_name(module, SymTagNull, Name);
    if (!type) return FALSE;
    Symbol->TypeIndex = (DWORD)type;

    return TRUE;
}

--- NEW FILE: wdbgexts.h ---
/*
 * File wdbgexts.h: definition of windbg extensions
 *                  (dbghelp.dll is seen as a windbg extension)
 *
 * Copyright (C) 2005, Eric Pouech
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

typedef struct EXT_API_VERSION
{
    USHORT  MajorVersion;
    USHORT  MinorVersion;
    USHORT  Revision;
    USHORT  Reserved;
} EXT_API_VERSION, *LPEXT_API_VERSION;

typedef void  (*PWINDBG_OUTPUT_ROUTINE)(PCSTR, ...);
typedef ULONG_PTR (WINAPI *PWINDBG_GET_EXPRESSION)(PCSTR);
typedef void  (WINAPI *PWINDBG_GET_SYMBOL)(void*, char*, ULONG_PTR*);
typedef ULONG (WINAPI *PWINDBG_DISASM)(ULONG_PTR*, PCSTR, ULONG);
typedef ULONG (WINAPI *PWINDBG_CHECK_CONTROL_C)(void);
typedef ULONG (WINAPI *PWINDBG_READ_PROCESS_MEMORY_ROUTINE)(ULONG_PTR, void*, ULONG, PULONG);
typedef ULONG (WINAPI *PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE)(ULONG_PTR, const void*, ULONG, PULONG);
typedef ULONG (WINAPI *PWINDBG_GET_THREAD_CONTEXT_ROUTINE)(ULONG, PCONTEXT, ULONG);
typedef ULONG (WINAPI *PWINDBG_SET_THREAD_CONTEXT_ROUTINE)(ULONG, PCONTEXT, ULONG);
typedef ULONG (WINAPI *PWINDBG_IOCTL_ROUTINE)(USHORT, void*);
typedef struct _EXTSTACKTRACE
{
    ULONG       FramePointer;
    ULONG       ProgramCounter;
    ULONG       ReturnAddress;
    ULONG       Args[4];
} EXTSTACKTRACE, *PEXTSTACKTRACE;
typedef ULONG (WINAPI *PWINDBG_STACKTRACE_ROUTINE)(ULONG, ULONG, ULONG, PEXTSTACKTRACE, ULONG);

typedef struct _WINDBG_EXTENSION_APIS
{
    ULONG                                  nSize;
    PWINDBG_OUTPUT_ROUTINE                 lpOutputRoutine;
    PWINDBG_GET_EXPRESSION                 lpGetExpressionRoutine;
    PWINDBG_GET_SYMBOL                     lpGetSymbolRoutine;
    PWINDBG_DISASM                         lpDisasmRoutine;
    PWINDBG_CHECK_CONTROL_C                lpCheckControlCRoutine;
    PWINDBG_READ_PROCESS_MEMORY_ROUTINE    lpReadProcessMemoryRoutine;
    PWINDBG_WRITE_PROCESS_MEMORY_ROUTINE   lpWriteProcessMemoryRoutine;
    PWINDBG_GET_THREAD_CONTEXT_ROUTINE     lpGetThreadContextRoutine;
    PWINDBG_SET_THREAD_CONTEXT_ROUTINE     lpSetThreadContextRoutine;
    PWINDBG_IOCTL_ROUTINE                  lpIoctlRoutine;
    PWINDBG_STACKTRACE_ROUTINE             lpStackTraceRoutine;
} WINDBG_EXTENSION_APIS, *PWINDBG_EXTENSION_APIS;