msc.c 129 KB
Newer Older
1 2 3 4 5 6
/*
 * 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.
7
 * Copyright (C) 2004-2009, Eric Pouech.
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23 24 25 26 27 28 29 30 31 32 33 34
 */

/*
 * 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.
 */

35 36
#define NONAMELESSUNION

37 38 39 40
#include "config.h"
#include "wine/port.h"

#include <assert.h>
41
#include <stdio.h>
42 43 44 45 46 47
#include <stdlib.h>

#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
48

49 50 51 52 53 54 55 56
#include <stdarg.h>
#include "windef.h"
#include "winbase.h"
#include "winternl.h"

#include "wine/exception.h"
#include "wine/debug.h"
#include "dbghelp_private.h"
57
#include "wine/mscvpdb.h"
58 59 60

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp_msc);

61 62 63 64 65 66
struct pdb_stream_name
{
    const char* name;
    unsigned    index;
};

67 68 69 70
struct pdb_file_info
{
    enum pdb_kind               kind;
    DWORD                       age;
71 72
    HANDLE                      hMap;
    const char*                 image;
73
    struct pdb_stream_name*     stream_dict;
74
    unsigned                    fpoext_stream;
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    union
    {
        struct
        {
            DWORD               timestamp;
            struct PDB_JG_TOC*  toc;
        } jg;
        struct
        {
            GUID                guid;
            struct PDB_DS_TOC*  toc;
        } ds;
    } u;
};

90 91 92 93 94 95 96 97
/* FIXME: don't make it static */
#define CV_MAX_MODULES          32
struct pdb_module_info
{
    unsigned                    used_subfiles;
    struct pdb_file_info        pdb_files[CV_MAX_MODULES];
};

98 99 100 101
/*========================================================================
 * Debug file access helper routines
 */

102
static void dump(const void* ptr, unsigned len)
103
{
104
    unsigned int i, j;
Mike McCormack's avatar
Mike McCormack committed
105
    char        msg[128];
106
    const char* hexof = "0123456789abcdef";
107
    const BYTE* x = ptr;
108

109
    for (i = 0; i < len; i += 16)
110
    {
111 112 113
        sprintf(msg, "%08x: ", i);
        memset(msg + 10, ' ', 3 * 16 + 1 + 16);
        for (j = 0; j < min(16, len - i); j++)
114
        {
115 116 117 118 119
            msg[10 + 3 * j + 0] = hexof[x[i + j] >> 4];
            msg[10 + 3 * j + 1] = hexof[x[i + j] & 15];
            msg[10 + 3 * j + 2] = ' ';
            msg[10 + 3 * 16 + 1 + j] = (x[i + j] >= 0x20 && x[i + j] < 0x7f) ?
                x[i + j] : '.';
120
        }
121 122 123
        msg[10 + 3 * 16] = ' ';
        msg[10 + 3 * 16 + 1 + 16] = '\0';
        FIXME("%s\n", msg);
124 125 126 127 128 129 130
    }
}

/*========================================================================
 * Process CodeView type information.
 */

131
#define MAX_BUILTIN_TYPES	0x06FF
132
#define FIRST_DEFINABLE_TYPE    0x1000
133

134
static struct symt*     cv_basic_types[MAX_BUILTIN_TYPES];
135

136
struct cv_defined_module
137
{
138 139 140
    BOOL                allowed;
    unsigned int        num_defined_types;
    struct symt**       defined_types;
141
};
142 143 144 145
/* FIXME: don't make it static */
#define CV_MAX_MODULES          32
static struct cv_defined_module cv_zmodules[CV_MAX_MODULES];
static struct cv_defined_module*cv_current_module;
146 147 148 149 150 151 152 153 154 155 156 157 158

static void codeview_init_basic_types(struct module* module)
{
    /*
     * These are the common builtin types that are used by VC++.
     */
    cv_basic_types[T_NOTYPE] = NULL;
    cv_basic_types[T_ABS]    = NULL;
    cv_basic_types[T_VOID]   = &symt_new_basic(module, btVoid,  "void", 0)->symt;
    cv_basic_types[T_CHAR]   = &symt_new_basic(module, btChar,  "char", 1)->symt;
    cv_basic_types[T_SHORT]  = &symt_new_basic(module, btInt,   "short int", 2)->symt;
    cv_basic_types[T_LONG]   = &symt_new_basic(module, btInt,   "long int", 4)->symt;
    cv_basic_types[T_QUAD]   = &symt_new_basic(module, btInt,   "long long int", 8)->symt;
159
    cv_basic_types[T_UCHAR]  = &symt_new_basic(module, btUInt,  "unsigned char", 1)->symt;
160 161 162
    cv_basic_types[T_USHORT] = &symt_new_basic(module, btUInt,  "unsigned short", 2)->symt;
    cv_basic_types[T_ULONG]  = &symt_new_basic(module, btUInt,  "unsigned long", 4)->symt;
    cv_basic_types[T_UQUAD]  = &symt_new_basic(module, btUInt,  "unsigned long long", 8)->symt;
163 164 165 166
    cv_basic_types[T_BOOL08] = &symt_new_basic(module, btBool,  "BOOL08", 1)->symt;
    cv_basic_types[T_BOOL16] = &symt_new_basic(module, btBool,  "BOOL16", 2)->symt;
    cv_basic_types[T_BOOL32] = &symt_new_basic(module, btBool,  "BOOL32", 4)->symt;
    cv_basic_types[T_BOOL64] = &symt_new_basic(module, btBool,  "BOOL64", 8)->symt;
167 168
    cv_basic_types[T_REAL32] = &symt_new_basic(module, btFloat, "float", 4)->symt;
    cv_basic_types[T_REAL64] = &symt_new_basic(module, btFloat, "double", 8)->symt;
169
    cv_basic_types[T_REAL80] = &symt_new_basic(module, btFloat, "long double", 10)->symt;
170 171
    cv_basic_types[T_RCHAR]  = &symt_new_basic(module, btInt,   "signed char", 1)->symt;
    cv_basic_types[T_WCHAR]  = &symt_new_basic(module, btWChar, "wchar_t", 2)->symt;
172 173
    cv_basic_types[T_INT2]   = &symt_new_basic(module, btInt,   "INT2", 2)->symt;
    cv_basic_types[T_UINT2]  = &symt_new_basic(module, btUInt,  "UINT2", 2)->symt;
174 175
    cv_basic_types[T_INT4]   = &symt_new_basic(module, btInt,   "INT4", 4)->symt;
    cv_basic_types[T_UINT4]  = &symt_new_basic(module, btUInt,  "UINT4", 4)->symt;
176 177
    cv_basic_types[T_INT8]   = &symt_new_basic(module, btInt,   "INT8", 8)->symt;
    cv_basic_types[T_UINT8]  = &symt_new_basic(module, btUInt,  "UINT8", 8)->symt;
178
    cv_basic_types[T_HRESULT]= &symt_new_basic(module, btUInt,  "HRESULT", 4)->symt;
179

180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
    cv_basic_types[T_32PVOID]   = &symt_new_pointer(module, cv_basic_types[T_VOID], 4)->symt;
    cv_basic_types[T_32PCHAR]   = &symt_new_pointer(module, cv_basic_types[T_CHAR], 4)->symt;
    cv_basic_types[T_32PSHORT]  = &symt_new_pointer(module, cv_basic_types[T_SHORT], 4)->symt;
    cv_basic_types[T_32PLONG]   = &symt_new_pointer(module, cv_basic_types[T_LONG], 4)->symt;
    cv_basic_types[T_32PQUAD]   = &symt_new_pointer(module, cv_basic_types[T_QUAD], 4)->symt;
    cv_basic_types[T_32PUCHAR]  = &symt_new_pointer(module, cv_basic_types[T_UCHAR], 4)->symt;
    cv_basic_types[T_32PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], 4)->symt;
    cv_basic_types[T_32PULONG]  = &symt_new_pointer(module, cv_basic_types[T_ULONG], 4)->symt;
    cv_basic_types[T_32PUQUAD]  = &symt_new_pointer(module, cv_basic_types[T_UQUAD], 4)->symt;
    cv_basic_types[T_32PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], 4)->symt;
    cv_basic_types[T_32PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], 4)->symt;
    cv_basic_types[T_32PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], 4)->symt;
    cv_basic_types[T_32PBOOL64] = &symt_new_pointer(module, cv_basic_types[T_BOOL64], 4)->symt;
    cv_basic_types[T_32PREAL32] = &symt_new_pointer(module, cv_basic_types[T_REAL32], 4)->symt;
    cv_basic_types[T_32PREAL64] = &symt_new_pointer(module, cv_basic_types[T_REAL64], 4)->symt;
    cv_basic_types[T_32PREAL80] = &symt_new_pointer(module, cv_basic_types[T_REAL80], 4)->symt;
    cv_basic_types[T_32PRCHAR]  = &symt_new_pointer(module, cv_basic_types[T_RCHAR], 4)->symt;
    cv_basic_types[T_32PWCHAR]  = &symt_new_pointer(module, cv_basic_types[T_WCHAR], 4)->symt;
    cv_basic_types[T_32PINT2]   = &symt_new_pointer(module, cv_basic_types[T_INT2], 4)->symt;
    cv_basic_types[T_32PUINT2]  = &symt_new_pointer(module, cv_basic_types[T_UINT2], 4)->symt;
    cv_basic_types[T_32PINT4]   = &symt_new_pointer(module, cv_basic_types[T_INT4], 4)->symt;
    cv_basic_types[T_32PUINT4]  = &symt_new_pointer(module, cv_basic_types[T_UINT4], 4)->symt;
    cv_basic_types[T_32PINT8]   = &symt_new_pointer(module, cv_basic_types[T_INT8], 4)->symt;
    cv_basic_types[T_32PUINT8]  = &symt_new_pointer(module, cv_basic_types[T_UINT8], 4)->symt;
    cv_basic_types[T_32PHRESULT]= &symt_new_pointer(module, cv_basic_types[T_HRESULT], 4)->symt;

    cv_basic_types[T_64PVOID]   = &symt_new_pointer(module, cv_basic_types[T_VOID], 8)->symt;
    cv_basic_types[T_64PCHAR]   = &symt_new_pointer(module, cv_basic_types[T_CHAR], 8)->symt;
    cv_basic_types[T_64PSHORT]  = &symt_new_pointer(module, cv_basic_types[T_SHORT], 8)->symt;
    cv_basic_types[T_64PLONG]   = &symt_new_pointer(module, cv_basic_types[T_LONG], 8)->symt;
    cv_basic_types[T_64PQUAD]   = &symt_new_pointer(module, cv_basic_types[T_QUAD], 8)->symt;
    cv_basic_types[T_64PUCHAR]  = &symt_new_pointer(module, cv_basic_types[T_UCHAR], 8)->symt;
    cv_basic_types[T_64PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], 8)->symt;
    cv_basic_types[T_64PULONG]  = &symt_new_pointer(module, cv_basic_types[T_ULONG], 8)->symt;
    cv_basic_types[T_64PUQUAD]  = &symt_new_pointer(module, cv_basic_types[T_UQUAD], 8)->symt;
    cv_basic_types[T_64PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], 8)->symt;
    cv_basic_types[T_64PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], 8)->symt;
    cv_basic_types[T_64PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], 8)->symt;
    cv_basic_types[T_64PBOOL64] = &symt_new_pointer(module, cv_basic_types[T_BOOL64], 8)->symt;
    cv_basic_types[T_64PREAL32] = &symt_new_pointer(module, cv_basic_types[T_REAL32], 8)->symt;
    cv_basic_types[T_64PREAL64] = &symt_new_pointer(module, cv_basic_types[T_REAL64], 8)->symt;
    cv_basic_types[T_64PREAL80] = &symt_new_pointer(module, cv_basic_types[T_REAL80], 8)->symt;
    cv_basic_types[T_64PRCHAR]  = &symt_new_pointer(module, cv_basic_types[T_RCHAR], 8)->symt;
    cv_basic_types[T_64PWCHAR]  = &symt_new_pointer(module, cv_basic_types[T_WCHAR], 8)->symt;
    cv_basic_types[T_64PINT2]   = &symt_new_pointer(module, cv_basic_types[T_INT2], 8)->symt;
    cv_basic_types[T_64PUINT2]  = &symt_new_pointer(module, cv_basic_types[T_UINT2], 8)->symt;
    cv_basic_types[T_64PINT4]   = &symt_new_pointer(module, cv_basic_types[T_INT4], 8)->symt;
    cv_basic_types[T_64PUINT4]  = &symt_new_pointer(module, cv_basic_types[T_UINT4], 8)->symt;
    cv_basic_types[T_64PINT8]   = &symt_new_pointer(module, cv_basic_types[T_INT8], 8)->symt;
    cv_basic_types[T_64PUINT8]  = &symt_new_pointer(module, cv_basic_types[T_UINT8], 8)->symt;
    cv_basic_types[T_64PHRESULT]= &symt_new_pointer(module, cv_basic_types[T_HRESULT], 8)->symt;
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

    cv_basic_types[T_PVOID]   = &symt_new_pointer(module, cv_basic_types[T_VOID],   sizeof(void*))->symt;
    cv_basic_types[T_PCHAR]   = &symt_new_pointer(module, cv_basic_types[T_CHAR],   sizeof(void*))->symt;
    cv_basic_types[T_PSHORT]  = &symt_new_pointer(module, cv_basic_types[T_SHORT],  sizeof(void*))->symt;
    cv_basic_types[T_PLONG]   = &symt_new_pointer(module, cv_basic_types[T_LONG],   sizeof(void*))->symt;
    cv_basic_types[T_PQUAD]   = &symt_new_pointer(module, cv_basic_types[T_QUAD],   sizeof(void*))->symt;
    cv_basic_types[T_PUCHAR]  = &symt_new_pointer(module, cv_basic_types[T_UCHAR],  sizeof(void*))->symt;
    cv_basic_types[T_PUSHORT] = &symt_new_pointer(module, cv_basic_types[T_USHORT], sizeof(void*))->symt;
    cv_basic_types[T_PULONG]  = &symt_new_pointer(module, cv_basic_types[T_ULONG],  sizeof(void*))->symt;
    cv_basic_types[T_PUQUAD]  = &symt_new_pointer(module, cv_basic_types[T_UQUAD],  sizeof(void*))->symt;
    cv_basic_types[T_PBOOL08] = &symt_new_pointer(module, cv_basic_types[T_BOOL08], sizeof(void*))->symt;
    cv_basic_types[T_PBOOL16] = &symt_new_pointer(module, cv_basic_types[T_BOOL16], sizeof(void*))->symt;
    cv_basic_types[T_PBOOL32] = &symt_new_pointer(module, cv_basic_types[T_BOOL32], sizeof(void*))->symt;
    cv_basic_types[T_PBOOL64] = &symt_new_pointer(module, cv_basic_types[T_BOOL64], sizeof(void*))->symt;
    cv_basic_types[T_PREAL32] = &symt_new_pointer(module, cv_basic_types[T_REAL32], sizeof(void*))->symt;
    cv_basic_types[T_PREAL64] = &symt_new_pointer(module, cv_basic_types[T_REAL64], sizeof(void*))->symt;
    cv_basic_types[T_PREAL80] = &symt_new_pointer(module, cv_basic_types[T_REAL80], sizeof(void*))->symt;
    cv_basic_types[T_PRCHAR]  = &symt_new_pointer(module, cv_basic_types[T_RCHAR],  sizeof(void*))->symt;
    cv_basic_types[T_PWCHAR]  = &symt_new_pointer(module, cv_basic_types[T_WCHAR],  sizeof(void*))->symt;
    cv_basic_types[T_PINT2]   = &symt_new_pointer(module, cv_basic_types[T_INT2],   sizeof(void*))->symt;
    cv_basic_types[T_PUINT2]  = &symt_new_pointer(module, cv_basic_types[T_UINT2],  sizeof(void*))->symt;
    cv_basic_types[T_PINT4]   = &symt_new_pointer(module, cv_basic_types[T_INT4],   sizeof(void*))->symt;
    cv_basic_types[T_PUINT4]  = &symt_new_pointer(module, cv_basic_types[T_UINT4],  sizeof(void*))->symt;
    cv_basic_types[T_PINT8]   = &symt_new_pointer(module, cv_basic_types[T_INT8],   sizeof(void*))->symt;
    cv_basic_types[T_PUINT8]  = &symt_new_pointer(module, cv_basic_types[T_UINT8],  sizeof(void*))->symt;
256 257
}

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
static int leaf_as_variant(VARIANT* v, const unsigned short int* leaf)
{
    unsigned short int type = *leaf++;
    int length = 2;

    if (type < LF_NUMERIC)
    {
        v->n1.n2.vt = VT_UINT;
        v->n1.n2.n3.uintVal = type;
    }
    else
    {
        switch (type)
        {
        case LF_CHAR:
            length += 1;
            v->n1.n2.vt = VT_I1;
            v->n1.n2.n3.cVal = *(const char*)leaf;
            break;

        case LF_SHORT:
            length += 2;
            v->n1.n2.vt = VT_I2;
            v->n1.n2.n3.iVal = *(const short*)leaf;
            break;

        case LF_USHORT:
            length += 2;
            v->n1.n2.vt = VT_UI2;
            v->n1.n2.n3.uiVal = *leaf;
            break;

        case LF_LONG:
            length += 4;
            v->n1.n2.vt = VT_I4;
            v->n1.n2.n3.lVal = *(const int*)leaf;
            break;

        case LF_ULONG:
            length += 4;
            v->n1.n2.vt = VT_UI4;
            v->n1.n2.n3.uiVal = *(const unsigned int*)leaf;
            break;

        case LF_QUADWORD:
            length += 8;
            v->n1.n2.vt = VT_I8;
            v->n1.n2.n3.llVal = *(const long long int*)leaf;
            break;

        case LF_UQUADWORD:
            length += 8;
            v->n1.n2.vt = VT_UI8;
            v->n1.n2.n3.ullVal = *(const long long unsigned int*)leaf;
            break;

        case LF_REAL32:
            length += 4;
            v->n1.n2.vt = VT_R4;
            v->n1.n2.n3.fltVal = *(const float*)leaf;
            break;

        case LF_REAL48:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 6;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        case LF_REAL64:
            length += 8;
            v->n1.n2.vt = VT_R8;
            v->n1.n2.n3.fltVal = *(const double*)leaf;
            break;

        case LF_REAL80:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 10;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        case LF_REAL128:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 16;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        case LF_COMPLEX32:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 4;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        case LF_COMPLEX64:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 8;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        case LF_COMPLEX80:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 10;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        case LF_COMPLEX128:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 16;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        case LF_VARSTRING:
	    FIXME("Unsupported numeric leaf type %04x\n", type);
            length += 2 + *leaf;
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;

        default:
	    FIXME("Unknown numeric leaf type %04x\n", type);
            v->n1.n2.vt = VT_EMPTY;     /* FIXME */
            break;
        }
    }

    return length;
}

384 385 386 387 388 389 390 391 392 393 394 395 396 397 398
static int numeric_leaf(int* value, const unsigned short int* leaf)
{
    unsigned short int type = *leaf++;
    int length = 2;

    if (type < LF_NUMERIC)
    {
        *value = type;
    }
    else
    {
        switch (type)
        {
        case LF_CHAR:
            length += 1;
399
            *value = *(const char*)leaf;
400 401 402 403
            break;

        case LF_SHORT:
            length += 2;
404
            *value = *(const short*)leaf;
405 406 407 408
            break;

        case LF_USHORT:
            length += 2;
409
            *value = *leaf;
410 411 412 413
            break;

        case LF_LONG:
            length += 4;
414
            *value = *(const int*)leaf;
415 416 417 418
            break;

        case LF_ULONG:
            length += 4;
419
            *value = *(const unsigned int*)leaf;
420 421 422 423
            break;

        case LF_QUADWORD:
        case LF_UQUADWORD:
424
	    FIXME("Unsupported numeric leaf type %04x\n", type);
425 426 427 428 429
            length += 8;
            *value = 0;    /* FIXME */
            break;

        case LF_REAL32:
430
	    FIXME("Unsupported numeric leaf type %04x\n", type);
431 432 433 434 435
            length += 4;
            *value = 0;    /* FIXME */
            break;

        case LF_REAL48:
436
	    FIXME("Unsupported numeric leaf type %04x\n", type);
437 438 439 440 441
            length += 6;
            *value = 0;    /* FIXME */
            break;

        case LF_REAL64:
442
	    FIXME("Unsupported numeric leaf type %04x\n", type);
443 444 445 446 447
            length += 8;
            *value = 0;    /* FIXME */
            break;

        case LF_REAL80:
448
	    FIXME("Unsupported numeric leaf type %04x\n", type);
449 450 451 452 453
            length += 10;
            *value = 0;    /* FIXME */
            break;

        case LF_REAL128:
454
	    FIXME("Unsupported numeric leaf type %04x\n", type);
455 456 457 458 459
            length += 16;
            *value = 0;    /* FIXME */
            break;

        case LF_COMPLEX32:
460
	    FIXME("Unsupported numeric leaf type %04x\n", type);
461 462 463 464 465
            length += 4;
            *value = 0;    /* FIXME */
            break;

        case LF_COMPLEX64:
466
	    FIXME("Unsupported numeric leaf type %04x\n", type);
467 468 469 470 471
            length += 8;
            *value = 0;    /* FIXME */
            break;

        case LF_COMPLEX80:
472
	    FIXME("Unsupported numeric leaf type %04x\n", type);
473 474 475 476 477
            length += 10;
            *value = 0;    /* FIXME */
            break;

        case LF_COMPLEX128:
478
	    FIXME("Unsupported numeric leaf type %04x\n", type);
479 480 481 482 483
            length += 16;
            *value = 0;    /* FIXME */
            break;

        case LF_VARSTRING:
484
	    FIXME("Unsupported numeric leaf type %04x\n", type);
485 486 487 488 489 490 491 492 493 494 495 496 497 498
            length += 2 + *leaf;
            *value = 0;    /* FIXME */
            break;

        default:
	    FIXME("Unknown numeric leaf type %04x\n", type);
            *value = 0;
            break;
        }
    }

    return length;
}

499 500 501 502
/* convert a pascal string (as stored in debug information) into
 * a C string (null terminated).
 */
static const char* terminate_string(const struct p_string* p_name)
503 504 505
{
    static char symname[256];

506 507
    memcpy(symname, p_name->name, p_name->namelen);
    symname[p_name->namelen] = '\0';
508 509 510 511

    return (!*symname || strcmp(symname, "__unnamed") == 0) ? NULL : symname;
}

512
static struct symt*  codeview_get_type(unsigned int typeno, BOOL quiet)
513 514 515 516 517
{
    struct symt*        symt = NULL;

    /*
     * Convert Codeview type numbers into something we can grok internally.
518 519
     * Numbers < FIRST_DEFINABLE_TYPE are all fixed builtin types.
     * Numbers from FIRST_DEFINABLE_TYPE and up are all user defined (structs, etc).
520
     */
521
    if (typeno < FIRST_DEFINABLE_TYPE)
522 523 524 525 526 527
    {
        if (typeno < MAX_BUILTIN_TYPES)
	    symt = cv_basic_types[typeno];
    }
    else
    {
528 529 530 531 532 533 534 535 536 537 538 539 540
        unsigned        mod_index = typeno >> 24;
        unsigned        mod_typeno = typeno & 0x00FFFFFF;
        struct cv_defined_module*       mod;

        mod = (mod_index == 0) ? cv_current_module : &cv_zmodules[mod_index];

        if (mod_index >= CV_MAX_MODULES || !mod->allowed) 
            FIXME("Module of index %d isn't loaded yet (%x)\n", mod_index, typeno);
        else
        {
            if (mod_typeno - FIRST_DEFINABLE_TYPE < mod->num_defined_types)
                symt = mod->defined_types[mod_typeno - FIRST_DEFINABLE_TYPE];
        }
541
    }
542
    if (!quiet && !symt && typeno) FIXME("Returning NULL symt for type-id %x\n", typeno);
543 544 545
    return symt;
}

Eric Pouech's avatar
Eric Pouech committed
546 547 548 549 550 551 552 553
struct codeview_type_parse
{
    struct module*      module;
    const BYTE*         table;
    const DWORD*        offset;
    DWORD               num;
};

554
static inline const void* codeview_jump_to_type(const struct codeview_type_parse* ctp, DWORD idx)
Eric Pouech's avatar
Eric Pouech committed
555 556 557 558 559 560
{
    if (idx < FIRST_DEFINABLE_TYPE) return NULL;
    idx -= FIRST_DEFINABLE_TYPE;
    return (idx >= ctp->num) ? NULL : (ctp->table + ctp->offset[idx]); 
}

561 562
static int codeview_add_type(unsigned int typeno, struct symt* dt)
{
563 564 565
    if (typeno < FIRST_DEFINABLE_TYPE)
        FIXME("What the heck\n");
    if (!cv_current_module)
566
    {
567 568 569 570 571 572
        FIXME("Adding %x to non allowed module\n", typeno);
        return FALSE;
    }
    if ((typeno >> 24) != 0)
        FIXME("No module index while inserting type-id assumption is wrong %x\n",
              typeno);
573
    if (typeno - FIRST_DEFINABLE_TYPE >= cv_current_module->num_defined_types)
574 575
    {
        if (cv_current_module->defined_types)
576 577 578
        {
            cv_current_module->num_defined_types = max( cv_current_module->num_defined_types * 2,
                                                        typeno - FIRST_DEFINABLE_TYPE + 1 );
579 580
            cv_current_module->defined_types = HeapReAlloc(GetProcessHeap(),
                            HEAP_ZERO_MEMORY, cv_current_module->defined_types,
581
                            cv_current_module->num_defined_types * sizeof(struct symt*));
582
        }
583
        else
584 585
        {
            cv_current_module->num_defined_types = max( 256, typeno - FIRST_DEFINABLE_TYPE + 1 );
586 587 588
            cv_current_module->defined_types = HeapAlloc(GetProcessHeap(),
                            HEAP_ZERO_MEMORY,
                            cv_current_module->num_defined_types * sizeof(struct symt*));
589
        }
590
        if (cv_current_module->defined_types == NULL) return FALSE;
591
    }
592 593 594
    if (cv_current_module->defined_types[typeno - FIRST_DEFINABLE_TYPE])
    {
        if (cv_current_module->defined_types[typeno - FIRST_DEFINABLE_TYPE] != dt)
595
            FIXME("Overwriting at %x\n", typeno);
596
    }
597
    cv_current_module->defined_types[typeno - FIRST_DEFINABLE_TYPE] = dt;
598 599 600 601 602
    return TRUE;
}

static void codeview_clear_type_table(void)
{
603
    int i;
604

605 606
    for (i = 0; i < CV_MAX_MODULES; i++)
    {
607
        if (cv_zmodules[i].allowed)
608 609 610 611 612 613
            HeapFree(GetProcessHeap(), 0, cv_zmodules[i].defined_types);
        cv_zmodules[i].allowed = FALSE;
        cv_zmodules[i].defined_types = NULL;
        cv_zmodules[i].num_defined_types = 0;
    }
    cv_current_module = NULL;
614 615
}

616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
static struct symt* codeview_parse_one_type(struct codeview_type_parse* ctp,
                                            unsigned curr_type,
                                            const union codeview_type* type, BOOL details);

static void* codeview_cast_symt(struct symt* symt, enum SymTagEnum tag)
{
    if (symt->tag != tag)
    {
        FIXME("Bad tag. Expected %d, but got %d\n", tag, symt->tag);
        return NULL;
    }   
    return symt;
}

static struct symt* codeview_fetch_type(struct codeview_type_parse* ctp,
631
                                        unsigned typeno, BOOL details)
632
{
633 634 635 636 637 638 639 640 641 642 643 644
    struct symt*                symt;
    const union codeview_type*  p;

    if (!typeno) return NULL;
    if ((symt = codeview_get_type(typeno, TRUE))) return symt;

    /* forward declaration */
    if (!(p = codeview_jump_to_type(ctp, typeno)))
    {
        FIXME("Cannot locate type %x\n", typeno);
        return NULL;
    }
645
    symt = codeview_parse_one_type(ctp, typeno, p, details);
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
    if (!symt) FIXME("Couldn't load forward type %x\n", typeno);
    return symt;
}

static struct symt* codeview_add_type_pointer(struct codeview_type_parse* ctp,
                                              struct symt* existing,
                                              unsigned int pointee_type)
{
    struct symt* pointee;

    if (existing)
    {
        existing = codeview_cast_symt(existing, SymTagPointerType);
        return existing;
    }
661
    pointee = codeview_fetch_type(ctp, pointee_type, FALSE);
662
    return &symt_new_pointer(ctp->module, pointee, sizeof(void *))->symt;
663 664
}

665
static struct symt* codeview_add_type_array(struct codeview_type_parse* ctp, 
666 667 668 669
                                            const char* name,
                                            unsigned int elemtype,
                                            unsigned int indextype,
                                            unsigned int arr_len)
670
{
671 672
    struct symt*        elem = codeview_fetch_type(ctp, elemtype, FALSE);
    struct symt*        index = codeview_fetch_type(ctp, indextype, FALSE);
673

674
    return &symt_new_array(ctp->module, 0, -arr_len, elem, index)->symt;
675 676
}

677 678 679
static BOOL codeview_add_type_enum_field_list(struct module* module,
                                              struct symt_enum* symt,
                                              const union codeview_reftype* ref_type)
680
{
Eric Pouech's avatar
Eric Pouech committed
681 682 683
    const unsigned char*                ptr = ref_type->fieldlist.list;
    const unsigned char*                last = (const BYTE*)ref_type + ref_type->generic.len + 2;
    const union codeview_fieldtype*     type;
684

Eric Pouech's avatar
Eric Pouech committed
685
    while (ptr < last)
686 687 688 689 690 691 692
    {
        if (*ptr >= 0xf0)       /* LF_PAD... */
        {
            ptr += *ptr & 0x0f;
            continue;
        }

Eric Pouech's avatar
Eric Pouech committed
693 694
        type = (const union codeview_fieldtype*)ptr;

695 696
        switch (type->generic.id)
        {
697 698 699 700 701 702 703 704 705 706
        case LF_ENUMERATE_V1:
        {
            int value, vlen = numeric_leaf(&value, &type->enumerate_v1.value);
            const struct p_string* p_name = (const struct p_string*)((const unsigned char*)&type->enumerate_v1.value + vlen);

            symt_add_enum_element(module, symt, terminate_string(p_name), value);
            ptr += 2 + 2 + vlen + (1 + p_name->namelen);
            break;
        }
        case LF_ENUMERATE_V3:
707
        {
708 709
            int value, vlen = numeric_leaf(&value, &type->enumerate_v3.value);
            const char* name = (const char*)&type->enumerate_v3.value + vlen;
710

711 712
            symt_add_enum_element(module, symt, name, value);
            ptr += 2 + 2 + vlen + (1 + strlen(name));
713 714 715 716
            break;
        }

        default:
717
            FIXME("Unsupported type %04x in ENUM field list\n", type->generic.id);
718 719 720
            return FALSE;
        }
    }
Eric Pouech's avatar
Eric Pouech committed
721
    return TRUE;
722 723
}

724 725
static void codeview_add_udt_element(struct codeview_type_parse* ctp,
                                     struct symt_udt* symt, const char* name,
726
                                     int value, unsigned type)
727 728 729 730
{
    struct symt*                subtype;
    const union codeview_reftype*cv_type;

731
    if ((cv_type = codeview_jump_to_type(ctp, type)))
732 733 734 735 736
    {
        switch (cv_type->generic.id)
        {
        case LF_BITFIELD_V1:
            symt_add_udt_element(ctp->module, symt, name,
737
                                 codeview_fetch_type(ctp, cv_type->bitfield_v1.type, FALSE),
738
                                 (value << 3) + cv_type->bitfield_v1.bitoff,
739
                                 cv_type->bitfield_v1.nbits);
740
            return;
741 742
        case LF_BITFIELD_V2:
            symt_add_udt_element(ctp->module, symt, name,
743
                                 codeview_fetch_type(ctp, cv_type->bitfield_v2.type, FALSE),
744
                                 (value << 3) + cv_type->bitfield_v2.bitoff,
745
                                 cv_type->bitfield_v2.nbits);
746
            return;
747 748
        }
    }
749
    subtype = codeview_fetch_type(ctp, type, FALSE);
750 751 752 753

    if (subtype)
    {
        DWORD64 elem_size = 0;
754
        symt_get_info(ctp->module, subtype, TI_GET_LENGTH, &elem_size);
755 756 757
        symt_add_udt_element(ctp->module, symt, name, subtype,
                             value << 3, (DWORD)elem_size << 3);
    }
758 759 760
}

static int codeview_add_type_struct_field_list(struct codeview_type_parse* ctp,
Eric Pouech's avatar
Eric Pouech committed
761
                                               struct symt_udt* symt,
762
                                               unsigned fieldlistno)
763
{
764 765
    const unsigned char*        ptr;
    const unsigned char*        last;
766
    int                         value, leaf_len;
767 768
    const struct p_string*      p_name;
    const char*                 c_name;
769
    const union codeview_reftype*type_ref;
Eric Pouech's avatar
Eric Pouech committed
770
    const union codeview_fieldtype* type;
771

772 773 774 775 776
    if (!fieldlistno) return TRUE;
    type_ref = codeview_jump_to_type(ctp, fieldlistno);
    ptr = type_ref->fieldlist.list;
    last = (const BYTE*)type_ref + type_ref->generic.len + 2;

Eric Pouech's avatar
Eric Pouech committed
777
    while (ptr < last)
778 779 780
    {
        if (*ptr >= 0xf0)       /* LF_PAD... */
        {
Eric Pouech's avatar
Eric Pouech committed
781
            ptr += *ptr & 0x0f;
782 783 784
            continue;
        }

Eric Pouech's avatar
Eric Pouech committed
785 786
        type = (const union codeview_fieldtype*)ptr;

787 788
        switch (type->generic.id)
        {
789 790
        case LF_BCLASS_V1:
            leaf_len = numeric_leaf(&value, &type->bclass_v1.offset);
791 792 793

            /* FIXME: ignored for now */

794
            ptr += 2 + 2 + 2 + leaf_len;
795 796
            break;

797 798
        case LF_BCLASS_V2:
            leaf_len = numeric_leaf(&value, &type->bclass_v2.offset);
799 800 801

            /* FIXME: ignored for now */

802
            ptr += 2 + 2 + 4 + leaf_len;
803 804
            break;

805 806 807
        case LF_VBCLASS_V1:
        case LF_IVBCLASS_V1:
            {
808 809
                const unsigned short int* p_vboff;
                int vpoff, vplen;
810 811 812
                leaf_len = numeric_leaf(&value, &type->vbclass_v1.vbpoff);
                p_vboff = (const unsigned short int*)((const char*)&type->vbclass_v1.vbpoff + leaf_len);
                vplen = numeric_leaf(&vpoff, p_vboff);
813

814
                /* FIXME: ignored for now */
815

816 817
                ptr += 2 + 2 + 2 + 2 + leaf_len + vplen;
            }
818 819
            break;

820 821 822
        case LF_VBCLASS_V2:
        case LF_IVBCLASS_V2:
            {
823 824
                const unsigned short int* p_vboff;
                int vpoff, vplen;
825 826 827
                leaf_len = numeric_leaf(&value, &type->vbclass_v2.vbpoff);
                p_vboff = (const unsigned short int*)((const char*)&type->vbclass_v2.vbpoff + leaf_len);
                vplen = numeric_leaf(&vpoff, p_vboff);
828

829
                /* FIXME: ignored for now */
830

831 832
                ptr += 2 + 2 + 4 + 4 + leaf_len + vplen;
            }
833 834
            break;

835 836 837
        case LF_MEMBER_V1:
            leaf_len = numeric_leaf(&value, &type->member_v1.offset);
            p_name = (const struct p_string*)((const char*)&type->member_v1.offset + leaf_len);
838

839 840
            codeview_add_udt_element(ctp, symt, terminate_string(p_name), value, 
                                     type->member_v1.type);
841

842
            ptr += 2 + 2 + 2 + leaf_len + (1 + p_name->namelen);
843 844
            break;

845 846 847
        case LF_MEMBER_V2:
            leaf_len = numeric_leaf(&value, &type->member_v2.offset);
            p_name = (const struct p_string*)((const unsigned char*)&type->member_v2.offset + leaf_len);
848

849 850
            codeview_add_udt_element(ctp, symt, terminate_string(p_name), value, 
                                     type->member_v2.type);
851

852
            ptr += 2 + 2 + 4 + leaf_len + (1 + p_name->namelen);
853 854
            break;

855 856 857 858
        case LF_MEMBER_V3:
            leaf_len = numeric_leaf(&value, &type->member_v3.offset);
            c_name = (const char*)&type->member_v3.offset + leaf_len;

Eric Pouech's avatar
Eric Pouech committed
859
            codeview_add_udt_element(ctp, symt, c_name, value, type->member_v3.type);
860 861 862 863 864

            ptr += 2 + 2 + 4 + leaf_len + (strlen(c_name) + 1);
            break;

        case LF_STMEMBER_V1:
865
            /* FIXME: ignored for now */
866
            ptr += 2 + 2 + 2 + (1 + type->stmember_v1.p_name.namelen);
867 868
            break;

869
        case LF_STMEMBER_V2:
870
            /* FIXME: ignored for now */
871
            ptr += 2 + 4 + 2 + (1 + type->stmember_v2.p_name.namelen);
872 873
            break;

874 875 876 877 878
        case LF_STMEMBER_V3:
            /* FIXME: ignored for now */
            ptr += 2 + 4 + 2 + (strlen(type->stmember_v3.name) + 1);
            break;

879
        case LF_METHOD_V1:
880
            /* FIXME: ignored for now */
881
            ptr += 2 + 2 + 2 + (1 + type->method_v1.p_name.namelen);
882 883
            break;

884
        case LF_METHOD_V2:
885
            /* FIXME: ignored for now */
886
            ptr += 2 + 2 + 4 + (1 + type->method_v2.p_name.namelen);
887 888
            break;

889 890 891 892 893
        case LF_METHOD_V3:
            /* FIXME: ignored for now */
            ptr += 2 + 2 + 4 + (strlen(type->method_v3.name) + 1);
            break;

894
        case LF_NESTTYPE_V1:
895
            /* FIXME: ignored for now */
896
            ptr += 2 + 2 + (1 + type->nesttype_v1.p_name.namelen);
897 898
            break;

899
        case LF_NESTTYPE_V2:
900
            /* FIXME: ignored for now */
901
            ptr += 2 + 2 + 4 + (1 + type->nesttype_v2.p_name.namelen);
902 903
            break;

904 905 906 907 908
        case LF_NESTTYPE_V3:
            /* FIXME: ignored for now */
            ptr += 2 + 2 + 4 + (strlen(type->nesttype_v3.name) + 1);
            break;

909
        case LF_VFUNCTAB_V1:
910 911 912 913
            /* FIXME: ignored for now */
            ptr += 2 + 2;
            break;

914
        case LF_VFUNCTAB_V2:
915 916 917 918
            /* FIXME: ignored for now */
            ptr += 2 + 2 + 4;
            break;

919
        case LF_ONEMETHOD_V1:
920
            /* FIXME: ignored for now */
921
            switch ((type->onemethod_v1.attribute >> 2) & 7)
922 923
            {
            case 4: case 6: /* (pure) introducing virtual method */
924
                ptr += 2 + 2 + 2 + 4 + (1 + type->onemethod_virt_v1.p_name.namelen);
925 926 927
                break;

            default:
928
                ptr += 2 + 2 + 2 + (1 + type->onemethod_v1.p_name.namelen);
929 930 931 932
                break;
            }
            break;

933
        case LF_ONEMETHOD_V2:
934
            /* FIXME: ignored for now */
935
            switch ((type->onemethod_v2.attribute >> 2) & 7)
936 937
            {
            case 4: case 6: /* (pure) introducing virtual method */
938
                ptr += 2 + 2 + 4 + 4 + (1 + type->onemethod_virt_v2.p_name.namelen);
939 940 941
                break;

            default:
942
                ptr += 2 + 2 + 4 + (1 + type->onemethod_v2.p_name.namelen);
943
                break;
944 945 946 947 948 949 950 951 952 953 954 955 956 957
            }
            break;

        case LF_ONEMETHOD_V3:
            /* FIXME: ignored for now */
            switch ((type->onemethod_v3.attribute >> 2) & 7)
            {
            case 4: case 6: /* (pure) introducing virtual method */
                ptr += 2 + 2 + 4 + 4 + (strlen(type->onemethod_virt_v3.name) + 1);
                break;

            default:
                ptr += 2 + 2 + 4 + (strlen(type->onemethod_v3.name) + 1);
                break;
958 959 960
            }
            break;

961 962 963 964 965 966 967 968 969 970 971 972
        case LF_INDEX_V1:
            if (!codeview_add_type_struct_field_list(ctp, symt, type->index_v1.ref))
                return FALSE;
            ptr += 2 + 2;
            break;

        case LF_INDEX_V2:
            if (!codeview_add_type_struct_field_list(ctp, symt, type->index_v2.ref))
                return FALSE;
            ptr += 2 + 2 + 4;
            break;

973
        default:
974
            FIXME("Unsupported type %04x in STRUCT field list\n", type->generic.id);
975 976 977 978
            return FALSE;
        }
    }

Eric Pouech's avatar
Eric Pouech committed
979
    return TRUE;
980 981
}

982 983
static struct symt* codeview_add_type_enum(struct codeview_type_parse* ctp,
                                           struct symt* existing,
984
                                           const char* name,
985 986
                                           unsigned fieldlistno,
                                           unsigned basetype)
987
{
988
    struct symt_enum*   symt;
989

990 991 992 993 994 995 996
    if (existing)
    {
        if (!(symt = codeview_cast_symt(existing, SymTagEnum))) return NULL;
        /* should also check that all fields are the same */
    }
    else
    {
997 998
        symt = symt_new_enum(ctp->module, name,
                             codeview_fetch_type(ctp, basetype, FALSE));
999 1000 1001 1002 1003 1004 1005
        if (fieldlistno)
        {
            const union codeview_reftype* fieldlist;
            fieldlist = codeview_jump_to_type(ctp, fieldlistno);
            codeview_add_type_enum_field_list(ctp->module, symt, fieldlist);
        }
    }
1006
    return &symt->symt;
1007 1008
}

1009
static struct symt* codeview_add_type_struct(struct codeview_type_parse* ctp,
1010
                                             struct symt* existing,
1011 1012
                                             const char* name, int structlen,
                                             enum UdtKind kind, unsigned property)
1013
{
1014 1015
    struct symt_udt*    symt;

1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
    /* if we don't have an existing type, try to find one with same name
     * FIXME: what to do when several types in different CUs have same name ?
     */
    if (!existing)
    {
        void*                       ptr;
        struct symt_ht*             type;
        struct hash_table_iter      hti;

        hash_table_iter_init(&ctp->module->ht_types, &hti, name);
        while ((ptr = hash_table_iter_up(&hti)))
        {
1028
            type = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt);
1029 1030 1031 1032 1033 1034 1035 1036 1037

            if (type->symt.tag == SymTagUDT &&
                type->hash_elt.name && !strcmp(type->hash_elt.name, name))
            {
                existing = &type->symt;
                break;
            }
        }
    }
1038 1039 1040 1041
    if (existing)
    {
        if (!(symt = codeview_cast_symt(existing, SymTagUDT))) return NULL;
        /* should also check that all fields are the same */
1042 1043 1044 1045 1046 1047 1048
        if (!(property & 0x80)) /* 0x80 = forward declaration */
        {
            if (!symt->size) /* likely prior forward declaration, set UDT size */
                symt_set_udt_size(ctp->module, symt, structlen);
            else /* different UDT with same name, create a new type */
                existing = NULL;
        }
1049
    }
1050
    if (!existing) symt = symt_new_udt(ctp->module, name, structlen, kind);
1051

1052
    return &symt->symt;
1053 1054
}

1055 1056
static struct symt* codeview_new_func_signature(struct codeview_type_parse* ctp, 
                                                struct symt* existing,
1057
                                                enum CV_call_e call_conv)
1058
{
1059 1060
    struct symt_function_signature*     sym;

1061 1062 1063 1064 1065 1066 1067
    if (existing)
    {
        sym = codeview_cast_symt(existing, SymTagFunctionType);
        if (!sym) return NULL;
    }
    else
    {
1068
        sym = symt_new_function_signature(ctp->module, NULL, call_conv);
1069
    }
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
    return &sym->symt;
}

static void codeview_add_func_signature_args(struct codeview_type_parse* ctp,
                                             struct symt_function_signature* sym,
                                             unsigned ret_type,
                                             unsigned args_list)
{
    const union codeview_reftype*       reftype;

1080
    sym->rettype = codeview_fetch_type(ctp, ret_type, FALSE);
1081
    if (args_list && (reftype = codeview_jump_to_type(ctp, args_list)))
1082
    {
1083
        unsigned int i;
1084 1085 1086 1087 1088
        switch (reftype->generic.id)
        {
        case LF_ARGLIST_V1:
            for (i = 0; i < reftype->arglist_v1.num; i++)
                symt_add_function_signature_parameter(ctp->module, sym,
1089
                                                      codeview_fetch_type(ctp, reftype->arglist_v1.args[i], FALSE));
1090 1091 1092 1093
            break;
        case LF_ARGLIST_V2:
            for (i = 0; i < reftype->arglist_v2.num; i++)
                symt_add_function_signature_parameter(ctp->module, sym,
1094
                                                      codeview_fetch_type(ctp, reftype->arglist_v2.args[i], FALSE));
1095 1096 1097 1098 1099
            break;
        default:
            FIXME("Unexpected leaf %x for signature's pmt\n", reftype->generic.id);
        }
    }
1100 1101
}

1102 1103
static struct symt* codeview_parse_one_type(struct codeview_type_parse* ctp,
                                            unsigned curr_type,
1104
                                            const union codeview_type* type, BOOL details)
1105
{
1106
    struct symt*                symt;
1107 1108 1109
    int                         value, leaf_len;
    const struct p_string*      p_name;
    const char*                 c_name;
1110 1111 1112
    struct symt*                existing;

    existing = codeview_get_type(curr_type, TRUE);
1113 1114 1115 1116

    switch (type->generic.id)
    {
    case LF_MODIFIER_V1:
1117 1118
        /* FIXME: we don't handle modifiers,
         * but read previous type on the curr_type
1119 1120 1121 1122 1123 1124 1125
         */
        WARN("Modifier on %x: %s%s%s%s\n",
             type->modifier_v1.type,
             type->modifier_v1.attribute & 0x01 ? "const " : "",
             type->modifier_v1.attribute & 0x02 ? "volatile " : "",
             type->modifier_v1.attribute & 0x04 ? "unaligned " : "",
             type->modifier_v1.attribute & ~0x07 ? "unknown " : "");
1126
        symt = codeview_fetch_type(ctp, type->modifier_v1.type, details);
1127 1128 1129 1130 1131 1132 1133 1134 1135
        break;
    case LF_MODIFIER_V2:
        /* FIXME: we don't handle modifiers, but readd previous type on the curr_type */
        WARN("Modifier on %x: %s%s%s%s\n",
             type->modifier_v2.type,
             type->modifier_v2.attribute & 0x01 ? "const " : "",
             type->modifier_v2.attribute & 0x02 ? "volatile " : "",
             type->modifier_v2.attribute & 0x04 ? "unaligned " : "",
             type->modifier_v2.attribute & ~0x07 ? "unknown " : "");
1136
        symt = codeview_fetch_type(ctp, type->modifier_v2.type, details);
1137 1138 1139
        break;

    case LF_POINTER_V1:
1140
        symt = codeview_add_type_pointer(ctp, existing, type->pointer_v1.datatype);
1141 1142
        break;
    case LF_POINTER_V2:
1143
        symt = codeview_add_type_pointer(ctp, existing, type->pointer_v2.datatype);
1144 1145 1146
        break;

    case LF_ARRAY_V1:
1147 1148 1149 1150 1151 1152 1153 1154 1155
        if (existing) symt = codeview_cast_symt(existing, SymTagArrayType);
        else
        {
            leaf_len = numeric_leaf(&value, &type->array_v1.arrlen);
            p_name = (const struct p_string*)((const unsigned char*)&type->array_v1.arrlen + leaf_len);
            symt = codeview_add_type_array(ctp, terminate_string(p_name),
                                           type->array_v1.elemtype,
                                           type->array_v1.idxtype, value);
        }
1156 1157
        break;
    case LF_ARRAY_V2:
1158 1159 1160 1161 1162
        if (existing) symt = codeview_cast_symt(existing, SymTagArrayType);
        else
        {
            leaf_len = numeric_leaf(&value, &type->array_v2.arrlen);
            p_name = (const struct p_string*)((const unsigned char*)&type->array_v2.arrlen + leaf_len);
1163

1164 1165 1166 1167
            symt = codeview_add_type_array(ctp, terminate_string(p_name),
                                           type->array_v2.elemtype,
                                           type->array_v2.idxtype, value);
        }
1168 1169
        break;
    case LF_ARRAY_V3:
1170 1171 1172 1173 1174
        if (existing) symt = codeview_cast_symt(existing, SymTagArrayType);
        else
        {
            leaf_len = numeric_leaf(&value, &type->array_v3.arrlen);
            c_name = (const char*)&type->array_v3.arrlen + leaf_len;
1175

1176 1177 1178 1179
            symt = codeview_add_type_array(ctp, c_name,
                                           type->array_v3.elemtype,
                                           type->array_v3.idxtype, value);
        }
1180 1181 1182 1183 1184 1185
        break;

    case LF_STRUCTURE_V1:
    case LF_CLASS_V1:
        leaf_len = numeric_leaf(&value, &type->struct_v1.structlen);
        p_name = (const struct p_string*)((const unsigned char*)&type->struct_v1.structlen + leaf_len);
1186
        symt = codeview_add_type_struct(ctp, existing, terminate_string(p_name), value,
1187 1188
                                        type->generic.id == LF_CLASS_V1 ? UdtClass : UdtStruct,
                                        type->struct_v1.property);
1189 1190 1191
        if (details)
        {
            codeview_add_type(curr_type, symt);
1192 1193 1194
            if (!(type->struct_v1.property & 0x80)) /* 0x80 = forward declaration */
                codeview_add_type_struct_field_list(ctp, (struct symt_udt*)symt,
                                                    type->struct_v1.fieldlist);
1195
        }
1196 1197 1198 1199 1200 1201
        break;

    case LF_STRUCTURE_V2:
    case LF_CLASS_V2:
        leaf_len = numeric_leaf(&value, &type->struct_v2.structlen);
        p_name = (const struct p_string*)((const unsigned char*)&type->struct_v2.structlen + leaf_len);
1202
        symt = codeview_add_type_struct(ctp, existing, terminate_string(p_name), value,
1203 1204
                                        type->generic.id == LF_CLASS_V2 ? UdtClass : UdtStruct,
                                        type->struct_v2.property);
1205 1206 1207
        if (details)
        {
            codeview_add_type(curr_type, symt);
1208 1209 1210
            if (!(type->struct_v2.property & 0x80)) /* 0x80 = forward declaration */
                codeview_add_type_struct_field_list(ctp, (struct symt_udt*)symt,
                                                    type->struct_v2.fieldlist);
1211
        }
1212 1213 1214 1215 1216 1217
        break;

    case LF_STRUCTURE_V3:
    case LF_CLASS_V3:
        leaf_len = numeric_leaf(&value, &type->struct_v3.structlen);
        c_name = (const char*)&type->struct_v3.structlen + leaf_len;
1218
        symt = codeview_add_type_struct(ctp, existing, c_name, value,
1219 1220
                                        type->generic.id == LF_CLASS_V3 ? UdtClass : UdtStruct,
                                        type->struct_v3.property);
1221 1222 1223
        if (details)
        {
            codeview_add_type(curr_type, symt);
1224 1225 1226
            if (!(type->struct_v3.property & 0x80)) /* 0x80 = forward declaration */
                codeview_add_type_struct_field_list(ctp, (struct symt_udt*)symt,
                                                    type->struct_v3.fieldlist);
1227
        }
1228 1229 1230 1231 1232
        break;

    case LF_UNION_V1:
        leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
        p_name = (const struct p_string*)((const unsigned char*)&type->union_v1.un_len + leaf_len);
1233
        symt = codeview_add_type_struct(ctp, existing, terminate_string(p_name),
1234
                                        value, UdtUnion, type->union_v1.property);
1235 1236 1237 1238 1239 1240
        if (details)
        {
            codeview_add_type(curr_type, symt);
            codeview_add_type_struct_field_list(ctp, (struct symt_udt*)symt,
                                                type->union_v1.fieldlist);
        }
1241 1242 1243 1244 1245
        break;

    case LF_UNION_V2:
        leaf_len = numeric_leaf(&value, &type->union_v2.un_len);
        p_name = (const struct p_string*)((const unsigned char*)&type->union_v2.un_len + leaf_len);
1246
        symt = codeview_add_type_struct(ctp, existing, terminate_string(p_name),
1247
                                        value, UdtUnion, type->union_v2.property);
1248 1249 1250 1251 1252 1253
        if (details)
        {
            codeview_add_type(curr_type, symt);
            codeview_add_type_struct_field_list(ctp, (struct symt_udt*)symt,
                                                type->union_v2.fieldlist);
        }
1254
        break;
1255

1256 1257 1258
    case LF_UNION_V3:
        leaf_len = numeric_leaf(&value, &type->union_v3.un_len);
        c_name = (const char*)&type->union_v3.un_len + leaf_len;
1259
        symt = codeview_add_type_struct(ctp, existing, c_name,
1260
                                        value, UdtUnion, type->union_v3.property);
1261 1262 1263 1264 1265 1266
        if (details)
        {
            codeview_add_type(curr_type, symt);
            codeview_add_type_struct_field_list(ctp, (struct symt_udt*)symt,
                                                type->union_v3.fieldlist);
        }
1267 1268 1269
        break;

    case LF_ENUM_V1:
1270
        symt = codeview_add_type_enum(ctp, existing,
1271
                                      terminate_string(&type->enumeration_v1.p_name),
1272 1273
                                      type->enumeration_v1.fieldlist,
                                      type->enumeration_v1.type);
1274 1275 1276
        break;

    case LF_ENUM_V2:
1277
        symt = codeview_add_type_enum(ctp, existing,
1278
                                      terminate_string(&type->enumeration_v2.p_name),
1279 1280
                                      type->enumeration_v2.fieldlist,
                                      type->enumeration_v2.type);
1281 1282 1283
        break;

    case LF_ENUM_V3:
1284
        symt = codeview_add_type_enum(ctp, existing, type->enumeration_v3.name,
1285 1286
                                      type->enumeration_v3.fieldlist,
                                      type->enumeration_v3.type);
1287 1288 1289
        break;

    case LF_PROCEDURE_V1:
1290 1291 1292 1293 1294 1295 1296 1297 1298
        symt = codeview_new_func_signature(ctp, existing, type->procedure_v1.call);
        if (details)
        {
            codeview_add_type(curr_type, symt);
            codeview_add_func_signature_args(ctp,
                                             (struct symt_function_signature*)symt,
                                             type->procedure_v1.rvtype,
                                             type->procedure_v1.arglist);
        }
1299 1300
        break;
    case LF_PROCEDURE_V2:
1301 1302 1303 1304 1305 1306 1307 1308 1309
        symt = codeview_new_func_signature(ctp, existing,type->procedure_v2.call);
        if (details)
        {
            codeview_add_type(curr_type, symt);
            codeview_add_func_signature_args(ctp,
                                             (struct symt_function_signature*)symt,
                                             type->procedure_v2.rvtype,
                                             type->procedure_v2.arglist);
        }
1310
        break;
1311

1312 1313 1314 1315
    case LF_MFUNCTION_V1:
        /* FIXME: for C++, this is plain wrong, but as we don't use arg types
         * nor class information, this would just do for now
         */
1316 1317 1318 1319 1320 1321 1322 1323 1324
        symt = codeview_new_func_signature(ctp, existing, type->mfunction_v1.call);
        if (details)
        {
            codeview_add_type(curr_type, symt);
            codeview_add_func_signature_args(ctp,
                                             (struct symt_function_signature*)symt,
                                             type->mfunction_v1.rvtype,
                                             type->mfunction_v1.arglist);
        }
1325 1326 1327 1328 1329
        break;
    case LF_MFUNCTION_V2:
        /* FIXME: for C++, this is plain wrong, but as we don't use arg types
         * nor class information, this would just do for now
         */
1330 1331 1332 1333 1334 1335 1336 1337 1338
        symt = codeview_new_func_signature(ctp, existing, type->mfunction_v2.call);
        if (details)
        {
            codeview_add_type(curr_type, symt);
            codeview_add_func_signature_args(ctp,
                                             (struct symt_function_signature*)symt,
                                             type->mfunction_v2.rvtype,
                                             type->mfunction_v2.arglist);
        }
1339 1340
        break;

1341 1342 1343 1344 1345 1346 1347 1348 1349
    case LF_VTSHAPE_V1:
        /* this is an ugly hack... FIXME when we have C++ support */
        if (!(symt = existing))
        {
            char    buf[128];
            snprintf(buf, sizeof(buf), "__internal_vt_shape_%x\n", curr_type);
            symt = &symt_new_udt(ctp->module, buf, 0, UdtStruct)->symt;
        }
        break;
1350 1351 1352
    default:
        FIXME("Unsupported type-id leaf %x\n", type->generic.id);
        dump(type, 2 + type->generic.len);
1353
        return NULL;
1354
    }
1355
    return codeview_add_type(curr_type, symt) ? symt : NULL;
1356 1357
}

1358
static BOOL codeview_parse_type_table(struct codeview_type_parse* ctp)
1359 1360 1361
{
    unsigned int                curr_type = FIRST_DEFINABLE_TYPE;
    const union codeview_type*  type;
1362

1363
    for (curr_type = FIRST_DEFINABLE_TYPE; curr_type < FIRST_DEFINABLE_TYPE + ctp->num; curr_type++)
1364
    {
Eric Pouech's avatar
Eric Pouech committed
1365
        type = codeview_jump_to_type(ctp, curr_type);
1366

Eric Pouech's avatar
Eric Pouech committed
1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
        /* type records we're interested in are the ones referenced by symbols
         * The known ranges are (X mark the ones we want):
         *   X  0000-0016       for V1 types
         *      0200-020c       for V1 types referenced by other types
         *      0400-040f       for V1 types (complex lists & sets)
         *   X  1000-100f       for V2 types
         *      1200-120c       for V2 types referenced by other types
         *      1400-140f       for V1 types (complex lists & sets)
         *   X  1500-150d       for V3 types
         *      8000-8010       for numeric leafes
         */
1378 1379
        if (!(type->generic.id & 0x8600) || (type->generic.id & 0x0100))
            codeview_parse_one_type(ctp, curr_type, type, TRUE);
1380 1381
    }

1382
    return TRUE;
1383 1384 1385 1386 1387
}

/*========================================================================
 * Process CodeView line number information.
 */
1388 1389
static unsigned long codeview_get_address(const struct msc_debug_info* msc_dbg,
                                          unsigned seg, unsigned offset);
1390

1391 1392
static void codeview_snarf_linetab(const struct msc_debug_info* msc_dbg, const BYTE* linetab,
                                   int size, BOOL pascal_str)
1393
{
1394 1395
    const BYTE*                 ptr = linetab;
    int				nfile, nseg;
1396 1397
    int                         i, j;
    unsigned int                k;
1398
    const unsigned int*         filetab;
1399
    const unsigned int*         lt_ptr;
1400
    const unsigned short*       linenos;
1401
    const struct startend*      start;
1402
    unsigned                    source;
1403
    unsigned long               addr, func_addr0;
1404 1405
    struct symt_function*       func;
    const struct codeview_linetab_block* ltb;
1406

1407 1408
    nfile = *(const short*)linetab;
    filetab = (const unsigned int*)(linetab + 2 * sizeof(short));
1409 1410 1411

    for (i = 0; i < nfile; i++)
    {
1412 1413 1414 1415
        ptr = linetab + filetab[i];
        nseg = *(const short*)ptr;
        lt_ptr = (const unsigned int*)(ptr + 2 * sizeof(short));
        start = (const struct startend*)(lt_ptr + nseg);
1416 1417 1418 1419

        /*
         * Now snarf the filename for all of the segments for this file.
         */
1420
        if (pascal_str)
1421
            source = source_new(msc_dbg->module, NULL, terminate_string((const struct p_string*)(start + nseg)));
1422
        else
1423 1424 1425
            source = source_new(msc_dbg->module, NULL, (const char*)(start + nseg));

        for (j = 0; j < nseg; j++)
1426
	{
1427 1428 1429 1430 1431 1432 1433 1434
            ltb = (const struct codeview_linetab_block*)(linetab + *lt_ptr++);
            linenos = (const unsigned short*)&ltb->offsets[ltb->num_lines];
            func_addr0 = codeview_get_address(msc_dbg, ltb->seg, start[j].start);
            if (!func_addr0) continue;
            for (func = NULL, k = 0; k < ltb->num_lines; k++)
            {
                /* now locate function (if any) */
                addr = func_addr0 + ltb->offsets[k] - start[j].start;
1435
                /* unfortunately, we can have several functions in the same block, if there's no
1436 1437 1438 1439 1440 1441 1442 1443
                 * gap between them... find the new function if needed
                 */
                if (!func || addr >= func->address + func->size)
                {
                    func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr);
                    /* FIXME: at least labels support line numbers */
                    if (!func || func->symt.tag != SymTagFunction)
                    {
1444
                        WARN("--not a func at %04x:%08x %lx tag=%d\n",
1445 1446 1447 1448 1449 1450 1451 1452
                             ltb->seg, ltb->offsets[k], addr, func ? func->symt.tag : -1);
                        func = NULL;
                        break;
                    }
                }
                symt_add_func_line(msc_dbg->module, func, source,
                                   linenos[k], addr - func->address);
            }
1453 1454 1455 1456
	}
    }
}

1457
static void codeview_snarf_linetab2(const struct msc_debug_info* msc_dbg, const BYTE* linetab, DWORD size,
1458
                                    const char* strimage, DWORD strsize)
1459 1460
{
    unsigned    i;
1461
    DWORD_PTR       addr;
1462 1463 1464 1465
    const struct codeview_linetab2*     lt2;
    const struct codeview_linetab2*     lt2_files = NULL;
    const struct codeview_lt2blk_lines* lines_blk;
    const struct codeview_linetab2_file*fd;
1466 1467 1468
    unsigned    source;
    struct symt_function* func;

1469 1470 1471
    /* locate LT2_FILES_BLOCK (if any) */
    lt2 = (const struct codeview_linetab2*)linetab;
    while ((const BYTE*)(lt2 + 1) < linetab + size)
1472
    {
1473
        if (lt2->header == LT2_FILES_BLOCK)
1474
        {
1475
            lt2_files = lt2;
1476 1477
            break;
        }
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490
        lt2 = codeview_linetab2_next_block(lt2);
    }
    if (!lt2_files)
    {
        TRACE("No LT2_FILES_BLOCK found\n");
        return;
    }

    lt2 = (const struct codeview_linetab2*)linetab;
    while ((const BYTE*)(lt2 + 1) < linetab + size)
    {
        /* FIXME: should also check that whole lines_blk fits in linetab + size */
        switch (lt2->header)
1491
        {
1492
        case LT2_LINES_BLOCK:
1493 1494
            /* Skip blocks that are too small - Intel C Compiler generates these. */
            if (lt2->size_of_block < sizeof (struct codeview_lt2blk_lines)) break;
1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506
            lines_blk = (const struct codeview_lt2blk_lines*)lt2;
            /* FIXME: should check that file_offset is within the LT2_FILES_BLOCK we've seen */
            addr = codeview_get_address(msc_dbg, lines_blk->seg, lines_blk->start);
            TRACE("block from %04x:%08x #%x (%x lines)\n",
                  lines_blk->seg, lines_blk->start, lines_blk->size, lines_blk->nlines);
            fd = (const struct codeview_linetab2_file*)((const char*)lt2_files + 8 + lines_blk->file_offset);
            /* FIXME: should check that string is within strimage + strsize */
            source = source_new(msc_dbg->module, NULL, strimage + fd->offset);
            func = (struct symt_function*)symt_find_nearest(msc_dbg->module, addr);
            /* FIXME: at least labels support line numbers */
            if (!func || func->symt.tag != SymTagFunction)
            {
1507
                WARN("--not a func at %04x:%08x %lx tag=%d\n",
1508 1509 1510 1511 1512 1513 1514
                     lines_blk->seg, lines_blk->start, addr, func ? func->symt.tag : -1);
                break;
            }
            for (i = 0; i < lines_blk->nlines; i++)
            {
                symt_add_func_line(msc_dbg->module, func, source,
                                   lines_blk->l[i].lineno ^ 0x80000000,
1515
                                   lines_blk->l[i].offset);
1516 1517 1518 1519 1520 1521 1522
            }
            break;
        case LT2_FILES_BLOCK: /* skip */
            break;
        default:
            TRACE("Block end %x\n", lt2->header);
            lt2 = (const struct codeview_linetab2*)((const char*)linetab + size);
1523 1524
            continue;
        }
1525
        lt2 = codeview_linetab2_next_block(lt2);
1526 1527 1528
    }
}

1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549
/*========================================================================
 * Process CodeView symbol information.
 */

static unsigned int codeview_map_offset(const struct msc_debug_info* msc_dbg,
                                        unsigned int offset)
{
    int                 nomap = msc_dbg->nomap;
    const OMAP_DATA*    omapp = msc_dbg->omapp;
    int                 i;

    if (!nomap || !omapp) return offset;

    /* FIXME: use binary search */
    for (i = 0; i < nomap - 1; i++)
        if (omapp[i].from <= offset && omapp[i+1].from > offset)
            return !omapp[i].to ? 0 : omapp[i].to + (offset - omapp[i].from);

    return 0;
}

1550 1551
static unsigned long codeview_get_address(const struct msc_debug_info* msc_dbg,
                                          unsigned seg, unsigned offset)
1552 1553 1554 1555 1556 1557 1558 1559 1560
{
    int			        nsect = msc_dbg->nsect;
    const IMAGE_SECTION_HEADER* sectp = msc_dbg->sectp;

    if (!seg || seg > nsect) return 0;
    return msc_dbg->module->module.BaseOfImage +
        codeview_map_offset(msc_dbg, sectp[seg-1].VirtualAddress + offset);
}

1561 1562 1563 1564
static inline void codeview_add_variable(const struct msc_debug_info* msc_dbg,
                                         struct symt_compiland* compiland,
                                         const char* name,
                                         unsigned segment, unsigned offset,
1565
                                         unsigned symtype, BOOL is_local, BOOL in_tls, BOOL force)
1566 1567 1568
{
    if (name && *name)
    {
1569
        struct location loc;
1570

1571
        loc.kind = in_tls ? loc_tlsrel : loc_absolute;
1572
        loc.reg = 0;
1573 1574
        loc.offset = in_tls ? offset : codeview_get_address(msc_dbg, segment, offset);
        if (force || in_tls || !symt_find_nearest(msc_dbg->module, loc.offset))
1575 1576
        {
            symt_new_global_variable(msc_dbg->module, compiland,
1577
                                     name, is_local, loc, 0,
1578 1579 1580 1581 1582
                                     codeview_get_type(symtype, FALSE));
        }
    }
}

1583 1584
static BOOL codeview_snarf(const struct msc_debug_info* msc_dbg, const BYTE* root,
                           int offset, int size, BOOL do_globals)
1585 1586 1587
{
    struct symt_function*               curr_func = NULL;
    int                                 i, length;
1588 1589
    struct symt_block*                  block = NULL;
    struct symt*                        symt;
1590
    struct symt_compiland*              compiland = NULL;
1591
    struct location                     loc;
1592 1593 1594 1595 1596 1597 1598 1599 1600

    /*
     * Loop over the different types of records and whenever we
     * find something we are interested in, record it and move on.
     */
    for (i = offset; i < size; i += length)
    {
        const union codeview_symbol* sym = (const union codeview_symbol*)(root + i);
        length = sym->generic.len + 2;
1601
        if (i + length > size) break;
1602
        if (!sym->generic.id || length < 4) break;
1603
        if (length & 3) FIXME("unpadded len %u\n", length);
1604 1605 1606 1607 1608 1609 1610

        switch (sym->generic.id)
        {
        /*
         * Global and local data symbols.  We don't associate these
         * with any given source file.
         */
1611 1612
	case S_GDATA_V1:
	case S_LDATA_V1:
1613 1614 1615
            if (do_globals)
                codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->data_v1.p_name),
                                      sym->data_v1.segment, sym->data_v1.offset, sym->data_v1.symtype,
1616
                                      sym->generic.id == S_LDATA_V1, FALSE, TRUE);
1617
	    break;
1618 1619
	case S_GDATA_V2:
	case S_LDATA_V2:
1620 1621 1622
            if (do_globals)
                codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->data_v2.p_name),
                                      sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype,
1623
                                      sym->generic.id == S_LDATA_V2, FALSE, TRUE);
1624 1625 1626
	    break;
	case S_GDATA_V3:
	case S_LDATA_V3:
1627 1628 1629
            if (do_globals)
                codeview_add_variable(msc_dbg, compiland, sym->data_v3.name,
                                      sym->data_v3.segment, sym->data_v3.offset, sym->data_v3.symtype,
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
                                      sym->generic.id == S_LDATA_V3, FALSE, TRUE);
	    break;

        /* variables with thread storage */
	case S_GTHREAD_V1:
	case S_LTHREAD_V1:
            if (do_globals)
                codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->thread_v1.p_name),
                                      sym->thread_v1.segment, sym->thread_v1.offset, sym->thread_v1.symtype,
                                      sym->generic.id == S_LTHREAD_V1, TRUE, TRUE);
	    break;
	case S_GTHREAD_V2:
	case S_LTHREAD_V2:
            if (do_globals)
                codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->thread_v2.p_name),
                                      sym->thread_v2.segment, sym->thread_v2.offset, sym->thread_v2.symtype,
                                      sym->generic.id == S_LTHREAD_V2, TRUE, TRUE);
	    break;
	case S_GTHREAD_V3:
	case S_LTHREAD_V3:
            if (do_globals)
                codeview_add_variable(msc_dbg, compiland, sym->thread_v3.name,
                                      sym->thread_v3.segment, sym->thread_v3.offset, sym->thread_v3.symtype,
                                      sym->generic.id == S_LTHREAD_V3, TRUE, TRUE);
1654 1655
	    break;

1656 1657 1658 1659 1660 1661 1662
        /* Public symbols */
	case S_PUB_V1:
	case S_PUB_V2:
        case S_PUB_V3:
        case S_PUB_FUNC1_V3:
        case S_PUB_FUNC2_V3:
            /* will be handled later on in codeview_snarf_public */
1663
            break;
1664 1665 1666 1667 1668 1669

        /*
         * Sort of like a global function, but it just points
         * to a thunk, which is a stupid name for what amounts to
         * a PLT slot in the normal jargon that everyone else uses.
         */
1670
	case S_THUNK_V1:
1671
            symt_new_thunk(msc_dbg->module, compiland,
1672 1673 1674 1675 1676
                           terminate_string(&sym->thunk_v1.p_name), sym->thunk_v1.thtype,
                           codeview_get_address(msc_dbg, sym->thunk_v1.segment, sym->thunk_v1.offset),
                           sym->thunk_v1.thunk_len);
	    break;
	case S_THUNK_V3:
1677
            symt_new_thunk(msc_dbg->module, compiland,
1678 1679 1680
                           sym->thunk_v3.name, sym->thunk_v3.thtype,
                           codeview_get_address(msc_dbg, sym->thunk_v3.segment, sym->thunk_v3.offset),
                           sym->thunk_v3.thunk_len);
1681 1682 1683 1684 1685
	    break;

        /*
         * Global and static functions.
         */
1686 1687 1688
	case S_GPROC_V1:
	case S_LPROC_V1:
            if (curr_func) FIXME("nested function\n");
1689
            curr_func = symt_new_function(msc_dbg->module, compiland,
1690 1691 1692 1693
                                          terminate_string(&sym->proc_v1.p_name),
                                          codeview_get_address(msc_dbg, sym->proc_v1.segment, sym->proc_v1.offset),
                                          sym->proc_v1.proc_len,
                                          codeview_get_type(sym->proc_v1.proctype, FALSE));
1694 1695 1696 1697 1698
            loc.kind = loc_absolute;
            loc.offset = sym->proc_v1.debug_start;
            symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL);
            loc.offset = sym->proc_v1.debug_end;
            symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL);
1699 1700 1701 1702
	    break;
	case S_GPROC_V2:
	case S_LPROC_V2:
            if (curr_func) FIXME("nested function\n");
1703
            curr_func = symt_new_function(msc_dbg->module, compiland,
1704 1705 1706 1707
                                          terminate_string(&sym->proc_v2.p_name),
                                          codeview_get_address(msc_dbg, sym->proc_v2.segment, sym->proc_v2.offset),
                                          sym->proc_v2.proc_len,
                                          codeview_get_type(sym->proc_v2.proctype, FALSE));
1708 1709 1710 1711 1712
            loc.kind = loc_absolute;
            loc.offset = sym->proc_v2.debug_start;
            symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL);
            loc.offset = sym->proc_v2.debug_end;
            symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL);
1713
	    break;
1714 1715 1716
	case S_GPROC_V3:
	case S_LPROC_V3:
            if (curr_func) FIXME("nested function\n");
1717
            curr_func = symt_new_function(msc_dbg->module, compiland,
1718 1719 1720 1721
                                          sym->proc_v3.name,
                                          codeview_get_address(msc_dbg, sym->proc_v3.segment, sym->proc_v3.offset),
                                          sym->proc_v3.proc_len,
                                          codeview_get_type(sym->proc_v3.proctype, FALSE));
1722 1723 1724 1725 1726
            loc.kind = loc_absolute;
            loc.offset = sym->proc_v3.debug_start;
            symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugStart, &loc, NULL);
            loc.offset = sym->proc_v3.debug_end;
            symt_add_function_point(msc_dbg->module, curr_func, SymTagFuncDebugEnd, &loc, NULL);
1727 1728 1729 1730
	    break;
        /*
         * Function parameters and stack variables.
         */
1731
	case S_BPREL_V1:
1732
            loc.kind = loc_regrel;
1733 1734
            /* Yes, it's i386 dependent, but that's the symbol purpose. S_REGREL is used on other CPUs */
            loc.reg = CV_REG_EBP;
1735
            loc.offset = sym->stack_v1.offset;
1736 1737
            symt_add_func_local(msc_dbg->module, curr_func, 
                                sym->stack_v1.offset > 0 ? DataIsParam : DataIsLocal, 
1738
                                &loc, block,
1739 1740
                                codeview_get_type(sym->stack_v1.symtype, FALSE),
                                terminate_string(&sym->stack_v1.p_name));
1741 1742
            break;
	case S_BPREL_V2:
1743
            loc.kind = loc_regrel;
1744 1745
            /* Yes, it's i386 dependent, but that's the symbol purpose. S_REGREL is used on other CPUs */
            loc.reg = CV_REG_EBP;
1746
            loc.offset = sym->stack_v2.offset;
1747 1748
            symt_add_func_local(msc_dbg->module, curr_func, 
                                sym->stack_v2.offset > 0 ? DataIsParam : DataIsLocal, 
1749
                                &loc, block,
1750
                                codeview_get_type(sym->stack_v2.symtype, FALSE),
1751 1752 1753
                                terminate_string(&sym->stack_v2.p_name));
            break;
	case S_BPREL_V3:
1754
            loc.kind = loc_regrel;
1755 1756
            /* Yes, it's i386 dependent, but that's the symbol purpose. S_REGREL is used on other CPUs */
            loc.reg = CV_REG_EBP;
1757
            loc.offset = sym->stack_v3.offset;
1758 1759
            symt_add_func_local(msc_dbg->module, curr_func, 
                                sym->stack_v3.offset > 0 ? DataIsParam : DataIsLocal, 
1760
                                &loc, block,
1761
                                codeview_get_type(sym->stack_v3.symtype, FALSE),
1762 1763
                                sym->stack_v3.name);
            break;
1764
	case S_REGREL_V3:
1765
            loc.kind = loc_regrel;
1766 1767
            loc.reg = sym->regrel_v3.reg;
            loc.offset = sym->regrel_v3.offset;
1768
            symt_add_func_local(msc_dbg->module, curr_func,
1769 1770
                                /* FIXME this is wrong !!! */
                                sym->regrel_v3.offset > 0 ? DataIsParam : DataIsLocal,
1771
                                &loc, block,
1772 1773
                                codeview_get_type(sym->regrel_v3.symtype, FALSE),
                                sym->regrel_v3.name);
1774
            break;
1775 1776

        case S_REGISTER_V1:
1777 1778 1779
            loc.kind = loc_register;
            loc.reg = sym->register_v1.reg;
            loc.offset = 0;
1780
            symt_add_func_local(msc_dbg->module, curr_func, 
1781
                                DataIsLocal, &loc,
1782 1783 1784 1785
                                block, codeview_get_type(sym->register_v1.type, FALSE),
                                terminate_string(&sym->register_v1.p_name));
            break;
        case S_REGISTER_V2:
1786 1787 1788
            loc.kind = loc_register;
            loc.reg = sym->register_v2.reg;
            loc.offset = 0;
1789
            symt_add_func_local(msc_dbg->module, curr_func, 
1790
                                DataIsLocal, &loc,
1791 1792 1793
                                block, codeview_get_type(sym->register_v2.type, FALSE),
                                terminate_string(&sym->register_v2.p_name));
            break;
1794 1795 1796 1797 1798 1799 1800 1801 1802
        case S_REGISTER_V3:
            loc.kind = loc_register;
            loc.reg = sym->register_v3.reg;
            loc.offset = 0;
            symt_add_func_local(msc_dbg->module, curr_func,
                                DataIsLocal, &loc,
                                block, codeview_get_type(sym->register_v3.type, FALSE),
                                sym->register_v3.name);
            break;
1803 1804 1805 1806 1807 1808 1809

        case S_BLOCK_V1:
            block = symt_open_func_block(msc_dbg->module, curr_func, block, 
                                         codeview_get_address(msc_dbg, sym->block_v1.segment, sym->block_v1.offset),
                                         sym->block_v1.length);
            break;
        case S_BLOCK_V3:
1810
            block = symt_open_func_block(msc_dbg->module, curr_func, block, 
1811 1812
                                         codeview_get_address(msc_dbg, sym->block_v3.segment, sym->block_v3.offset),
                                         sym->block_v3.length);
1813 1814
            break;

1815
        case S_END_V1:
1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826
            if (block)
            {
                block = symt_close_func_block(msc_dbg->module, curr_func, block, 0);
            }
            else if (curr_func)
            {
                symt_normalize_function(msc_dbg->module, curr_func);
                curr_func = NULL;
            }
            break;

1827 1828 1829
        case S_COMPILAND_V1:
            TRACE("S-Compiland-V1 %x %s\n",
                  sym->compiland_v1.unknown, terminate_string(&sym->compiland_v1.p_name));
1830 1831
            break;

1832 1833
        case S_COMPILAND_V2:
            TRACE("S-Compiland-V2 %s\n", terminate_string(&sym->compiland_v2.p_name));
1834 1835
            if (TRACE_ON(dbghelp_msc))
            {
1836
                const char* ptr1 = sym->compiland_v2.p_name.name + sym->compiland_v2.p_name.namelen;
1837 1838 1839 1840
                const char* ptr2;
                while (*ptr1)
                {
                    ptr2 = ptr1 + strlen(ptr1) + 1;
1841
                    TRACE("\t%s => %s\n", ptr1, debugstr_a(ptr2));
1842 1843 1844 1845
                    ptr1 = ptr2 + strlen(ptr2) + 1;
                }
            }
            break;
1846 1847
        case S_COMPILAND_V3:
            TRACE("S-Compiland-V3 %s\n", sym->compiland_v3.name);
1848 1849
            if (TRACE_ON(dbghelp_msc))
            {
1850
                const char* ptr1 = sym->compiland_v3.name + strlen(sym->compiland_v3.name);
1851 1852 1853 1854
                const char* ptr2;
                while (*ptr1)
                {
                    ptr2 = ptr1 + strlen(ptr1) + 1;
1855
                    TRACE("\t%s => %s\n", ptr1, debugstr_a(ptr2));
1856 1857 1858
                    ptr1 = ptr2 + strlen(ptr2) + 1;
                }
            }
1859 1860
            break;

1861
        case S_OBJNAME_V1:
1862
            TRACE("S-ObjName %s\n", terminate_string(&sym->objname_v1.p_name));
1863
            compiland = symt_new_compiland(msc_dbg->module, 0 /* FIXME */,
1864 1865
                                           source_new(msc_dbg->module, NULL,
                                                      terminate_string(&sym->objname_v1.p_name)));
1866 1867
            break;

1868 1869 1870
        case S_LABEL_V1:
            if (curr_func)
            {
1871 1872 1873
                loc.kind = loc_absolute;
                loc.offset = codeview_get_address(msc_dbg, sym->label_v1.segment, sym->label_v1.offset) - curr_func->address;
                symt_add_function_point(msc_dbg->module, curr_func, SymTagLabel, &loc,
1874 1875
                                        terminate_string(&sym->label_v1.p_name));
            }
1876 1877 1878
            else symt_new_label(msc_dbg->module, compiland,
                                terminate_string(&sym->label_v1.p_name),
                                codeview_get_address(msc_dbg, sym->label_v1.segment, sym->label_v1.offset));
1879 1880
            break;
        case S_LABEL_V3:
1881 1882
            if (curr_func)
            {
1883 1884
                loc.kind = loc_absolute;
                loc.offset = codeview_get_address(msc_dbg, sym->label_v3.segment, sym->label_v3.offset) - curr_func->address;
1885
                symt_add_function_point(msc_dbg->module, curr_func, SymTagLabel, 
1886
                                        &loc, sym->label_v3.name);
1887
            }
1888 1889
            else symt_new_label(msc_dbg->module, compiland, sym->label_v3.name,
                                codeview_get_address(msc_dbg, sym->label_v3.segment, sym->label_v3.offset));
1890 1891
            break;

1892
        case S_CONSTANT_V1:
1893
            {
1894
                int                     vlen;
1895 1896
                const struct p_string*  name;
                struct symt*            se;
1897
                VARIANT                 v;
1898

1899
                vlen = leaf_as_variant(&v, &sym->constant_v1.cvalue);
1900 1901
                name = (const struct p_string*)((const char*)&sym->constant_v1.cvalue + vlen);
                se = codeview_get_type(sym->constant_v1.type, FALSE);
1902 1903 1904 1905 1906

                TRACE("S-Constant-V1 %u %s %x\n",
                      v.n1.n2.n3.intVal, terminate_string(name), sym->constant_v1.type);
                symt_new_constant(msc_dbg->module, compiland, terminate_string(name),
                                  se, &v);
1907 1908
            }
            break;
1909 1910
        case S_CONSTANT_V2:
            {
1911
                int                     vlen;
1912 1913
                const struct p_string*  name;
                struct symt*            se;
1914
                VARIANT                 v;
1915

1916
                vlen = leaf_as_variant(&v, &sym->constant_v2.cvalue);
1917 1918
                name = (const struct p_string*)((const char*)&sym->constant_v2.cvalue + vlen);
                se = codeview_get_type(sym->constant_v2.type, FALSE);
1919 1920 1921 1922 1923

                TRACE("S-Constant-V2 %u %s %x\n",
                      v.n1.n2.n3.intVal, terminate_string(name), sym->constant_v2.type);
                symt_new_constant(msc_dbg->module, compiland, terminate_string(name),
                                  se, &v);
1924 1925 1926
            }
            break;
        case S_CONSTANT_V3:
1927
            {
1928
                int                     vlen;
1929 1930
                const char*             name;
                struct symt*            se;
1931
                VARIANT                 v;
1932

1933
                vlen = leaf_as_variant(&v, &sym->constant_v3.cvalue);
1934 1935
                name = (const char*)&sym->constant_v3.cvalue + vlen;
                se = codeview_get_type(sym->constant_v3.type, FALSE);
1936 1937 1938

                TRACE("S-Constant-V3 %u %s %x\n",
                      v.n1.n2.n3.intVal, name, sym->constant_v3.type);
1939
                /* FIXME: we should add this as a constant value */
1940
                symt_new_constant(msc_dbg->module, compiland, name, se, &v);
1941 1942 1943
            }
            break;

1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967
        case S_UDT_V1:
            if (sym->udt_v1.type)
            {
                if ((symt = codeview_get_type(sym->udt_v1.type, FALSE)))
                    symt_new_typedef(msc_dbg->module, symt, 
                                     terminate_string(&sym->udt_v1.p_name));
                else
                    FIXME("S-Udt %s: couldn't find type 0x%x\n", 
                          terminate_string(&sym->udt_v1.p_name), sym->udt_v1.type);
            }
            break;
        case S_UDT_V2:
            if (sym->udt_v2.type)
            {
                if ((symt = codeview_get_type(sym->udt_v2.type, FALSE)))
                    symt_new_typedef(msc_dbg->module, symt, 
                                     terminate_string(&sym->udt_v2.p_name));
                else
                    FIXME("S-Udt %s: couldn't find type 0x%x\n", 
                          terminate_string(&sym->udt_v2.p_name), sym->udt_v2.type);
            }
            break;
        case S_UDT_V3:
            if (sym->udt_v3.type)
1968
            {
1969 1970 1971 1972 1973
                if ((symt = codeview_get_type(sym->udt_v3.type, FALSE)))
                    symt_new_typedef(msc_dbg->module, symt, sym->udt_v3.name);
                else
                    FIXME("S-Udt %s: couldn't find type 0x%x\n", 
                          sym->udt_v3.name, sym->udt_v3.type);
1974 1975 1976
            }
            break;

1977
         /*
1978 1979 1980 1981
         * These are special, in that they are always followed by an
         * additional length-prefixed string which is *not* included
         * into the symbol length count.  We need to skip it.
         */
1982 1983 1984
	case S_PROCREF_V1:
	case S_DATAREF_V1:
	case S_LPROCREF_V1:
1985 1986 1987 1988 1989 1990 1991
            {
                const char* name;

                name = (const char*)sym + length;
                length += (*name + 1 + 3) & ~3;
                break;
            }
1992 1993

        case S_MSTOOL_V3: /* just to silence a few warnings */
1994
        case S_MSTOOLINFO_V3:
1995
        case S_MSTOOLENV_V3:
1996 1997
            break;

Eric Pouech's avatar
Eric Pouech committed
1998 1999 2000 2001 2002
        case S_SSEARCH_V1:
            TRACE("Start search: seg=0x%x at offset 0x%08x\n",
                  sym->ssearch_v1.segment, sym->ssearch_v1.offset);
            break;

2003 2004 2005 2006
        case S_ALIGN_V1:
            TRACE("S-Align V1\n");
            break;

2007
        /* the symbols we can safely ignore for now */
2008
        case S_TRAMPOLINE:
2009
        case S_FRAMEINFO_V2:
2010
        case S_SECUCOOKIE_V3:
2011 2012
        case S_SECTINFO_V3:
        case S_SUBSECTINFO_V3:
2013
        case S_ENTRYPOINT_V3:
2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025
        case S_LOCAL_VS2013:
        case S_CALLSITEINFO:
        case S_DEFRANGE_REGISTER:
        case S_DEFRANGE_FRAMEPOINTER_REL:
        case S_DEFRANGE_SUBFIELD_REGISTER:
        case S_FPOFF_VS2013:
        case S_DEFRANGE_REGISTER_REL:
        case S_BUILDINFO:
        case S_INLINESITE:
        case S_INLINESITE_END:
        case S_FILESTATIC:
        case S_CALLEES:
2026 2027 2028
            TRACE("Unsupported symbol id %x\n", sym->generic.id);
            break;

2029
        default:
2030 2031 2032
            FIXME("Unsupported symbol id %x\n", sym->generic.id);
            dump(sym, 2 + sym->generic.len);
            break;
2033 2034 2035 2036 2037 2038 2039 2040
        }
    }

    if (curr_func) symt_normalize_function(msc_dbg->module, curr_func);

    return TRUE;
}

2041 2042
static BOOL codeview_snarf_public(const struct msc_debug_info* msc_dbg, const BYTE* root,
                                  int offset, int size)
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066

{
    int                                 i, length;
    struct symt_compiland*              compiland = NULL;

    /*
     * Loop over the different types of records and whenever we
     * find something we are interested in, record it and move on.
     */
    for (i = offset; i < size; i += length)
    {
        const union codeview_symbol* sym = (const union codeview_symbol*)(root + i);
        length = sym->generic.len + 2;
        if (i + length > size) break;
        if (!sym->generic.id || length < 4) break;
        if (length & 3) FIXME("unpadded len %u\n", length);

        switch (sym->generic.id)
        {
	case S_PUB_V1: /* FIXME is this really a 'data_v1' structure ?? */
            if (!(dbghelp_options & SYMOPT_NO_PUBLICS))
            {
                symt_new_public(msc_dbg->module, compiland,
                                terminate_string(&sym->data_v1.p_name),
2067
                                codeview_get_address(msc_dbg, sym->data_v1.segment, sym->data_v1.offset), 1);
2068 2069 2070 2071 2072 2073 2074
            }
            break;
	case S_PUB_V2: /* FIXME is this really a 'data_v2' structure ?? */
            if (!(dbghelp_options & SYMOPT_NO_PUBLICS))
            {
                symt_new_public(msc_dbg->module, compiland,
                                terminate_string(&sym->data_v2.p_name),
2075
                                codeview_get_address(msc_dbg, sym->data_v2.segment, sym->data_v2.offset), 1);
2076 2077 2078 2079 2080 2081 2082 2083
            }
	    break;

        case S_PUB_V3:
            if (!(dbghelp_options & SYMOPT_NO_PUBLICS))
            {
                symt_new_public(msc_dbg->module, compiland,
                                sym->data_v3.name,
2084
                                codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1);
2085 2086 2087 2088 2089 2090 2091 2092 2093 2094
            }
            break;
        case S_PUB_FUNC1_V3:
        case S_PUB_FUNC2_V3: /* using a data_v3 isn't what we'd expect */
#if 0
            /* FIXME: this is plain wrong (from a simple test) */
            if (!(dbghelp_options & SYMOPT_NO_PUBLICS))
            {
                symt_new_public(msc_dbg->module, compiland,
                                sym->data_v3.name,
2095
                                codeview_get_address(msc_dbg, sym->data_v3.segment, sym->data_v3.offset), 1);
2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
            }
#endif
            break;
        /*
         * Global and local data symbols.  We don't associate these
         * with any given source file.
         */
	case S_GDATA_V1:
	case S_LDATA_V1:
            codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->data_v1.p_name),
                                  sym->data_v1.segment, sym->data_v1.offset, sym->data_v1.symtype,
2107
                                  sym->generic.id == S_LDATA_V1, FALSE, FALSE);
2108 2109 2110 2111 2112
	    break;
	case S_GDATA_V2:
	case S_LDATA_V2:
            codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->data_v2.p_name),
                                  sym->data_v2.segment, sym->data_v2.offset, sym->data_v2.symtype,
2113
                                  sym->generic.id == S_LDATA_V2, FALSE, FALSE);
2114 2115 2116 2117 2118
	    break;
	case S_GDATA_V3:
	case S_LDATA_V3:
            codeview_add_variable(msc_dbg, compiland, sym->data_v3.name,
                                  sym->data_v3.segment, sym->data_v3.offset, sym->data_v3.symtype,
2119 2120 2121 2122 2123 2124 2125 2126 2127
                                  sym->generic.id == S_LDATA_V3, FALSE, FALSE);
	    break;

        /* variables with thread storage */
	case S_GTHREAD_V1:
	case S_LTHREAD_V1:
            codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->thread_v1.p_name),
                                  sym->thread_v1.segment, sym->thread_v1.offset, sym->thread_v1.symtype,
                                  sym->generic.id == S_LTHREAD_V1, TRUE, FALSE);
2128
	    break;
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141
	case S_GTHREAD_V2:
	case S_LTHREAD_V2:
            codeview_add_variable(msc_dbg, compiland, terminate_string(&sym->thread_v2.p_name),
                                  sym->thread_v2.segment, sym->thread_v2.offset, sym->thread_v2.symtype,
                                  sym->generic.id == S_LTHREAD_V2, TRUE, FALSE);
	    break;
	case S_GTHREAD_V3:
	case S_LTHREAD_V3:
            codeview_add_variable(msc_dbg, compiland, sym->thread_v3.name,
                                  sym->thread_v3.segment, sym->thread_v3.offset, sym->thread_v3.symtype,
                                  sym->generic.id == S_LTHREAD_V3, TRUE, FALSE);
	    break;

2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158
        /*
         * These are special, in that they are always followed by an
         * additional length-prefixed string which is *not* included
         * into the symbol length count.  We need to skip it.
         */
	case S_PROCREF_V1:
	case S_DATAREF_V1:
	case S_LPROCREF_V1:
            length += (((const char*)sym)[length] + 1 + 3) & ~3;
            break;
        }
        msc_dbg->module->sortlist_valid = TRUE;
    }
    msc_dbg->module->sortlist_valid = FALSE;
    return TRUE;
}

2159 2160 2161 2162
/*========================================================================
 * Process PDB file.
 */

2163 2164
static void* pdb_jg_read(const struct PDB_JG_HEADER* pdb, const WORD* block_list,
                         int size)
2165
{
2166 2167
    int                         i, num_blocks;
    BYTE*                       buffer;
2168

2169
    if (!size) return NULL;
2170

2171 2172
    num_blocks = (size + pdb->block_size - 1) / pdb->block_size;
    buffer = HeapAlloc(GetProcessHeap(), 0, num_blocks * pdb->block_size);
2173

2174 2175 2176
    for (i = 0; i < num_blocks; i++)
        memcpy(buffer + i * pdb->block_size,
               (const char*)pdb + block_list[i] * pdb->block_size, pdb->block_size);
2177

2178 2179 2180 2181 2182
    return buffer;
}

static void* pdb_ds_read(const struct PDB_DS_HEADER* pdb, const DWORD* block_list,
                         int size)
2183
{
2184 2185
    int                         i, num_blocks;
    BYTE*                       buffer;
2186 2187 2188

    if (!size) return NULL;

2189 2190
    num_blocks = (size + pdb->block_size - 1) / pdb->block_size;
    buffer = HeapAlloc(GetProcessHeap(), 0, num_blocks * pdb->block_size);
2191

2192 2193 2194
    for (i = 0; i < num_blocks; i++)
        memcpy(buffer + i * pdb->block_size,
               (const char*)pdb + block_list[i] * pdb->block_size, pdb->block_size);
2195 2196 2197 2198

    return buffer;
}

2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215
static void* pdb_read_jg_file(const struct PDB_JG_HEADER* pdb,
                              const struct PDB_JG_TOC* toc, DWORD file_nr)
{
    const WORD*                 block_list;
    DWORD                       i;

    if (!toc || file_nr >= toc->num_files) return NULL;

    block_list = (const WORD*) &toc->file[toc->num_files];
    for (i = 0; i < file_nr; i++)
        block_list += (toc->file[i].size + pdb->block_size - 1) / pdb->block_size;

    return pdb_jg_read(pdb, block_list, toc->file[file_nr].size);
}

static void* pdb_read_ds_file(const struct PDB_DS_HEADER* pdb,
                              const struct PDB_DS_TOC* toc, DWORD file_nr)
2216
{
2217 2218 2219 2220
    const DWORD*                block_list;
    DWORD                       i;

    if (!toc || file_nr >= toc->num_files) return NULL;
2221
    if (toc->file_size[file_nr] == 0 || toc->file_size[file_nr] == 0xFFFFFFFF) return NULL;
2222 2223 2224 2225

    block_list = &toc->file_size[toc->num_files];
    for (i = 0; i < file_nr; i++)
        block_list += (toc->file_size[i] + pdb->block_size - 1) / pdb->block_size;
2226

2227 2228
    return pdb_ds_read(pdb, block_list, toc->file_size[file_nr]);
}
2229

2230
static void* pdb_read_file(const struct pdb_file_info* pdb_file,
2231 2232
                           DWORD file_nr)
{
2233
    switch (pdb_file->kind)
2234 2235
    {
    case PDB_JG:
2236
        return pdb_read_jg_file((const struct PDB_JG_HEADER*)pdb_file->image,
2237
                                pdb_file->u.jg.toc, file_nr);
2238
    case PDB_DS:
2239
        return pdb_read_ds_file((const struct PDB_DS_HEADER*)pdb_file->image,
2240
                                pdb_file->u.ds.toc, file_nr);
2241 2242 2243
    }
    return NULL;
}
2244

2245
static unsigned pdb_get_file_size(const struct pdb_file_info* pdb_file, DWORD file_nr)
2246
{
2247
    switch (pdb_file->kind)
2248
    {
2249 2250
    case PDB_JG: return pdb_file->u.jg.toc->file[file_nr].size;
    case PDB_DS: return pdb_file->u.ds.toc->file_size[file_nr];
2251 2252
    }
    return 0;
2253 2254 2255 2256 2257 2258 2259
}

static void pdb_free(void* buffer)
{
    HeapFree(GetProcessHeap(), 0, buffer);
}

2260
static void pdb_free_file(struct pdb_file_info* pdb_file)
2261
{
2262
    switch (pdb_file->kind)
2263 2264
    {
    case PDB_JG:
2265 2266
        pdb_free(pdb_file->u.jg.toc);
        pdb_file->u.jg.toc = NULL;
2267 2268
        break;
    case PDB_DS:
2269 2270
        pdb_free(pdb_file->u.ds.toc);
        pdb_file->u.ds.toc = NULL;
2271 2272
        break;
    }
2273 2274 2275
    HeapFree(GetProcessHeap(), 0, pdb_file->stream_dict);
}

2276
static void pdb_load_stream_name_table(struct pdb_file_info* pdb_file, const char* str, unsigned cb)
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288
{
    DWORD*      pdw;
    DWORD*      ok_bits;
    DWORD       count, numok;
    unsigned    i, j;
    char*       cpstr;

    pdw = (DWORD*)(str + cb);
    numok = *pdw++;
    count = *pdw++;

    pdb_file->stream_dict = HeapAlloc(GetProcessHeap(), 0, (numok + 1) * sizeof(struct pdb_stream_name) + cb);
2289
    if (!pdb_file->stream_dict) return;
2290 2291 2292 2293 2294 2295 2296 2297 2298
    cpstr = (char*)(pdb_file->stream_dict + numok + 1);
    memcpy(cpstr, str, cb);

    /* bitfield: first dword is len (in dword), then data */
    ok_bits = pdw;
    pdw += *ok_bits++ + 1;
    if (*pdw++ != 0)
    {
        FIXME("unexpected value\n");
2299
        return;
2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313
    }

    for (i = j = 0; i < count; i++)
    {
        if (ok_bits[i / 32] & (1 << (i % 32)))
        {
            if (j >= numok) break;
            pdb_file->stream_dict[j].name = &cpstr[*pdw++];
            pdb_file->stream_dict[j].index = *pdw++;
            j++;
        }
    }
    /* add sentinel */
    pdb_file->stream_dict[numok].name = NULL;
2314
    pdb_file->fpoext_stream = -1;
2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325
}

static unsigned pdb_get_stream_by_name(const struct pdb_file_info* pdb_file, const char* name)
{
    struct pdb_stream_name*     psn;

    for (psn = pdb_file->stream_dict; psn && psn->name; psn++)
    {
        if (!strcmp(psn->name, name)) return psn->index;
    }
    return -1;
2326
}
2327

2328 2329
static void* pdb_read_strings(const struct pdb_file_info* pdb_file)
{
2330
    unsigned idx;
2331 2332
    void *ret;

2333 2334 2335 2336 2337 2338 2339
    idx = pdb_get_stream_by_name(pdb_file, "/names");
    if (idx != -1)
    {
        ret = pdb_read_file( pdb_file, idx );
        if (ret && *(const DWORD *)ret == 0xeffeeffe) return ret;
        pdb_free( ret );
    }
2340 2341 2342 2343
    WARN("string table not found\n");
    return NULL;
}

2344 2345 2346 2347 2348
static void pdb_module_remove(struct process* pcsn, struct module_format* modfmt)
{
    unsigned    i;

    for (i = 0; i < modfmt->u.pdb_info->used_subfiles; i++)
2349
    {
2350
        pdb_free_file(&modfmt->u.pdb_info->pdb_files[i]);
2351 2352 2353 2354 2355
        if (modfmt->u.pdb_info->pdb_files[i].image)
            UnmapViewOfFile(modfmt->u.pdb_info->pdb_files[i].image);
        if (modfmt->u.pdb_info->pdb_files[i].hMap)
            CloseHandle(modfmt->u.pdb_info->pdb_files[i].hMap);
    }
2356 2357 2358
    HeapFree(GetProcessHeap(), 0, modfmt);
}

2359 2360 2361 2362 2363
static void pdb_convert_types_header(PDB_TYPES* types, const BYTE* image)
{
    memset(types, 0, sizeof(PDB_TYPES));
    if (!image) return;

2364
    if (*(const DWORD*)image < 19960000)   /* FIXME: correct version? */
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387
    {
        /* Old version of the types record header */
        const PDB_TYPES_OLD*    old = (const PDB_TYPES_OLD*)image;
        types->version     = old->version;
        types->type_offset = sizeof(PDB_TYPES_OLD);
        types->type_size   = old->type_size;
        types->first_index = old->first_index;
        types->last_index  = old->last_index;
        types->file        = old->file;
    }
    else
    {
        /* New version of the types record header */
        *types = *(const PDB_TYPES*)image;
    }
}

static void pdb_convert_symbols_header(PDB_SYMBOLS* symbols,
                                       int* header_size, const BYTE* image)
{
    memset(symbols, 0, sizeof(PDB_SYMBOLS));
    if (!image) return;

2388
    if (*(const DWORD*)image != 0xffffffff)
2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411
    {
        /* Old version of the symbols record header */
        const PDB_SYMBOLS_OLD*  old = (const PDB_SYMBOLS_OLD*)image;
        symbols->version         = 0;
        symbols->module_size     = old->module_size;
        symbols->offset_size     = old->offset_size;
        symbols->hash_size       = old->hash_size;
        symbols->srcmodule_size  = old->srcmodule_size;
        symbols->pdbimport_size  = 0;
        symbols->hash1_file      = old->hash1_file;
        symbols->hash2_file      = old->hash2_file;
        symbols->gsym_file       = old->gsym_file;

        *header_size = sizeof(PDB_SYMBOLS_OLD);
    }
    else
    {
        /* New version of the symbols record header */
        *symbols = *(const PDB_SYMBOLS*)image;
        *header_size = sizeof(PDB_SYMBOLS);
    }
}

2412 2413 2414 2415 2416 2417 2418
static void pdb_convert_symbol_file(const PDB_SYMBOLS* symbols, 
                                    PDB_SYMBOL_FILE_EX* sfile, 
                                    unsigned* size, const void* image)

{
    if (symbols->version < 19970000)
    {
2419
        const PDB_SYMBOL_FILE *sym_file = image;
2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433
        memset(sfile, 0, sizeof(*sfile));
        sfile->file        = sym_file->file;
        sfile->range.index = sym_file->range.index;
        sfile->symbol_size = sym_file->symbol_size;
        sfile->lineno_size = sym_file->lineno_size;
        *size = sizeof(PDB_SYMBOL_FILE) - 1;
    }
    else
    {
        memcpy(sfile, image, sizeof(PDB_SYMBOL_FILE_EX));
        *size = sizeof(PDB_SYMBOL_FILE_EX) - 1;
    }
}

2434 2435 2436
static HANDLE map_pdb_file(const struct process* pcs,
                           const struct pdb_lookup* lookup,
                           struct module* module)
2437
{
2438
    HANDLE      hFile, hMap = NULL;
2439
    char        dbg_file_path[MAX_PATH];
2440
    BOOL        ret = FALSE;
2441

2442
    switch (lookup->kind)
2443
    {
2444
    case PDB_JG:
2445
        ret = path_find_symbol_file(pcs, lookup->filename, NULL, lookup->timestamp,
2446
                                    lookup->age, dbg_file_path, &module->module.PdbUnmatched);
2447 2448
        break;
    case PDB_DS:
2449
        ret = path_find_symbol_file(pcs, lookup->filename, &lookup->guid, 0,
2450
                                    lookup->age, dbg_file_path, &module->module.PdbUnmatched);
2451 2452 2453 2454 2455 2456
        break;
    }
    if (!ret)
    {
        WARN("\tCouldn't find %s\n", lookup->filename);
        return NULL;
2457
    }
2458 2459 2460 2461 2462 2463 2464
    if ((hFile = CreateFileA(dbg_file_path, GENERIC_READ, FILE_SHARE_READ, NULL,
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) != INVALID_HANDLE_VALUE)
    {
        hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
        CloseHandle(hFile);
    }
    return hMap;
2465 2466
}

2467 2468
static void pdb_process_types(const struct msc_debug_info* msc_dbg,
                              const struct pdb_file_info* pdb_file)
2469
{
Mike McCormack's avatar
Mike McCormack committed
2470
    BYTE*       types_image = NULL;
2471

2472
    types_image = pdb_read_file(pdb_file, 2);
2473
    if (types_image)
2474
    {
Eric Pouech's avatar
Eric Pouech committed
2475
        PDB_TYPES               types;
Eric Pouech's avatar
Eric Pouech committed
2476 2477
        struct codeview_type_parse      ctp;
        DWORD                   total;
Eric Pouech's avatar
Eric Pouech committed
2478
        const BYTE*             ptr;
Eric Pouech's avatar
Eric Pouech committed
2479
        DWORD*                  offset;
Eric Pouech's avatar
Eric Pouech committed
2480

2481
        pdb_convert_types_header(&types, types_image);
2482

2483 2484 2485
        /* Check for unknown versions */
        switch (types.version)
        {
2486 2487 2488
        case 19950410:      /* VC 4.0 */
        case 19951122:
        case 19961031:      /* VC 5.0 / 6.0 */
2489 2490
        case 19990903:      /* VC 7.0 */
        case 20040203:      /* VC 8.0 */
2491 2492
            break;
        default:
2493
            ERR("-Unknown type info version %d\n", types.version);
2494 2495
        }

Eric Pouech's avatar
Eric Pouech committed
2496
        ctp.module = msc_dbg->module;
Eric Pouech's avatar
Eric Pouech committed
2497 2498 2499 2500 2501
        /* reconstruct the types offset...
         * FIXME: maybe it's present in the newest PDB_TYPES structures
         */
        total = types.last_index - types.first_index + 1;
        offset = HeapAlloc(GetProcessHeap(), 0, sizeof(DWORD) * total);
Eric Pouech's avatar
Eric Pouech committed
2502 2503 2504
        ctp.table = ptr = types_image + types.type_offset;
        ctp.num = 0;
        while (ptr < ctp.table + types.type_size && ctp.num < total)
Eric Pouech's avatar
Eric Pouech committed
2505
        {
Eric Pouech's avatar
Eric Pouech committed
2506
            offset[ctp.num++] = ptr - ctp.table;
Eric Pouech's avatar
Eric Pouech committed
2507 2508
            ptr += ((const union codeview_type*)ptr)->generic.len + 2;
        }
Eric Pouech's avatar
Eric Pouech committed
2509
        ctp.offset = offset;
Eric Pouech's avatar
Eric Pouech committed
2510

2511
        /* Read type table */
Eric Pouech's avatar
Eric Pouech committed
2512
        codeview_parse_type_table(&ctp);
Eric Pouech's avatar
Eric Pouech committed
2513
        HeapFree(GetProcessHeap(), 0, offset);
2514
        pdb_free(types_image);
2515
    }
2516 2517 2518 2519
}

static const char       PDB_JG_IDENT[] = "Microsoft C/C++ program database 2.00\r\n\032JG\0";
static const char       PDB_DS_IDENT[] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0";
2520

2521 2522 2523 2524
/******************************************************************
 *		pdb_init
 *
 * Tries to load a pdb file
2525 2526 2527 2528
 * 'matched' is filled with the number of correct matches for this file:
 *      - age counts for one
 *      - timestamp or guid depending on kind counts for one
 * a wrong kind of file returns FALSE (FIXME ?)
2529
 */
2530 2531
static BOOL pdb_init(const struct pdb_lookup* pdb_lookup, struct pdb_file_info* pdb_file,
                     const char* image, unsigned* matched)
2532
{
2533 2534
    BOOL        ret = TRUE;

2535 2536
    /* check the file header, and if ok, load the TOC */
    TRACE("PDB(%s): %.40s\n", pdb_lookup->filename, debugstr_an(image, 40));
2537

2538
    *matched = 0;
2539
    if (!memcmp(image, PDB_JG_IDENT, sizeof(PDB_JG_IDENT)))
2540
    {
2541 2542 2543
        const struct PDB_JG_HEADER* pdb = (const struct PDB_JG_HEADER*)image;
        struct PDB_JG_ROOT*         root;

2544 2545
        pdb_file->u.jg.toc = pdb_jg_read(pdb, pdb->toc_block, pdb->toc.size);
        root = pdb_read_jg_file(pdb, pdb_file->u.jg.toc, 1);
2546
        if (!root)
2547
        {
2548
            ERR("-Unable to get root from .PDB in %s\n", pdb_lookup->filename);
2549 2550
            return FALSE;
        }
2551
        switch (root->Version)
2552
        {
2553 2554 2555 2556 2557 2558
        case 19950623:      /* VC 4.0 */
        case 19950814:
        case 19960307:      /* VC 5.0 */
        case 19970604:      /* VC 6.0 */
            break;
        default:
2559
            ERR("-Unknown root block version %d\n", root->Version);
2560
        }
2561
        if (pdb_lookup->kind != PDB_JG)
2562
        {
2563
            WARN("Found %s, but wrong PDB kind\n", pdb_lookup->filename);
2564
            pdb_free(root);
2565
            return FALSE;
2566
        }
2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
        pdb_file->kind = PDB_JG;
        pdb_file->u.jg.timestamp = root->TimeDateStamp;
        pdb_file->age = root->Age;
        if (root->TimeDateStamp == pdb_lookup->timestamp) (*matched)++;
        else WARN("Found %s, but wrong signature: %08x %08x\n",
                  pdb_lookup->filename, root->TimeDateStamp, pdb_lookup->timestamp);
        if (root->Age == pdb_lookup->age) (*matched)++;
        else WARN("Found %s, but wrong age: %08x %08x\n",
                  pdb_lookup->filename, root->Age, pdb_lookup->age);
        TRACE("found JG for %s: age=%x timestamp=%x\n",
              pdb_lookup->filename, root->Age, root->TimeDateStamp);
2578 2579
        pdb_load_stream_name_table(pdb_file, &root->names[0], root->cbNames);

2580 2581 2582 2583 2584 2585 2586
        pdb_free(root);
    }
    else if (!memcmp(image, PDB_DS_IDENT, sizeof(PDB_DS_IDENT)))
    {
        const struct PDB_DS_HEADER* pdb = (const struct PDB_DS_HEADER*)image;
        struct PDB_DS_ROOT*         root;

2587
        pdb_file->u.ds.toc =
2588 2589 2590
            pdb_ds_read(pdb, 
                        (const DWORD*)((const char*)pdb + pdb->toc_page * pdb->block_size), 
                        pdb->toc_size);
2591
        root = pdb_read_ds_file(pdb, pdb_file->u.ds.toc, 1);
2592
        if (!root)
2593
        {
2594
            ERR("-Unable to get root from .PDB in %s\n", pdb_lookup->filename);
2595 2596
            return FALSE;
        }
2597
        switch (root->Version)
2598
        {
2599 2600 2601
        case 20000404:
            break;
        default:
2602
            ERR("-Unknown root block version %d\n", root->Version);
2603
        }
2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615
        pdb_file->kind = PDB_DS;
        pdb_file->u.ds.guid = root->guid;
        pdb_file->age = root->Age;
        if (!memcmp(&root->guid, &pdb_lookup->guid, sizeof(GUID))) (*matched)++;
        else WARN("Found %s, but wrong GUID: %s %s\n",
                  pdb_lookup->filename, debugstr_guid(&root->guid),
                     debugstr_guid(&pdb_lookup->guid));
        if (root->Age == pdb_lookup->age) (*matched)++;
        else WARN("Found %s, but wrong age: %08x %08x\n",
                  pdb_lookup->filename, root->Age, pdb_lookup->age);
        TRACE("found DS for %s: age=%x guid=%s\n",
              pdb_lookup->filename, root->Age, debugstr_guid(&root->guid));
2616 2617
        pdb_load_stream_name_table(pdb_file, &root->names[0], root->cbNames);

2618
        pdb_free(root);
2619
    }
2620

2621
    if (0) /* some tool to dump the internal files from a PDB file */
2622
    {
2623 2624
        int     i, num_files;
        
2625
        switch (pdb_file->kind)
2626
        {
2627 2628
        case PDB_JG: num_files = pdb_file->u.jg.toc->num_files; break;
        case PDB_DS: num_files = pdb_file->u.ds.toc->num_files; break;
2629 2630 2631 2632
        }

        for (i = 1; i < num_files; i++)
        {
2633
            unsigned char* x = pdb_read_file(pdb_file, i);
2634
            FIXME("********************** [%u]: size=%08x\n",
2635 2636
                  i, pdb_get_file_size(pdb_file, i));
            dump(x, pdb_get_file_size(pdb_file, i));
2637 2638
            pdb_free(x);
        }
2639
    }
2640
    return ret;
2641
}
2642

2643 2644
static BOOL pdb_process_internal(const struct process* pcs, 
                                 const struct msc_debug_info* msc_dbg,
2645
                                 const struct pdb_lookup* pdb_lookup,
2646
                                 struct pdb_module_info* pdb_module_info,
2647 2648 2649 2650
                                 unsigned module_index);

static void pdb_process_symbol_imports(const struct process* pcs, 
                                       const struct msc_debug_info* msc_dbg,
2651
                                       const PDB_SYMBOLS* symbols,
2652
                                       const void* symbols_image,
2653 2654
                                       const char* image,
                                       const struct pdb_lookup* pdb_lookup,
2655
                                       struct pdb_module_info* pdb_module_info,
2656 2657 2658 2659 2660 2661 2662 2663 2664
                                       unsigned module_index)
{
    if (module_index == -1 && symbols && symbols->pdbimport_size)
    {
        const PDB_SYMBOL_IMPORT*imp;
        const void*             first;
        const void*             last;
        const char*             ptr;
        int                     i = 0;
2665
        struct pdb_file_info    sf0 = pdb_module_info->pdb_files[0];
2666 2667 2668 2669

        imp = (const PDB_SYMBOL_IMPORT*)((const char*)symbols_image + sizeof(PDB_SYMBOLS) + 
                                         symbols->module_size + symbols->offset_size + 
                                         symbols->hash_size + symbols->srcmodule_size);
2670
        first = imp;
2671 2672 2673 2674
        last = (const char*)imp + symbols->pdbimport_size;
        while (imp < (const PDB_SYMBOL_IMPORT*)last)
        {
            ptr = (const char*)imp + sizeof(*imp) + strlen(imp->filename);
2675
            if (i >= CV_MAX_MODULES) FIXME("Out of bounds!!!\n");
2676 2677 2678 2679
            if (!strcasecmp(pdb_lookup->filename, imp->filename))
            {
                if (module_index != -1) FIXME("Twice the entry\n");
                else module_index = i;
2680
                pdb_module_info->pdb_files[i] = sf0;
2681 2682 2683 2684
            }
            else
            {
                struct pdb_lookup       imp_pdb_lookup;
2685

2686 2687 2688
                /* FIXME: this is an import of a JG PDB file
                 * how's a DS PDB handled ?
                 */
2689 2690
                imp_pdb_lookup.filename = imp->filename;
                imp_pdb_lookup.kind = PDB_JG;
2691
                imp_pdb_lookup.timestamp = imp->TimeDateStamp;
2692
                imp_pdb_lookup.age = imp->Age;
2693
                TRACE("got for %s: age=%u ts=%x\n",
2694
                      imp->filename, imp->Age, imp->TimeDateStamp);
2695
                pdb_process_internal(pcs, msc_dbg, &imp_pdb_lookup, pdb_module_info, i);
2696 2697 2698 2699
            }
            i++;
            imp = (const PDB_SYMBOL_IMPORT*)((const char*)first + ((ptr - (const char*)first + strlen(ptr) + 1 + 3) & ~3));
        }
2700 2701 2702 2703 2704 2705
        pdb_module_info->used_subfiles = i;
    }
    if (module_index == -1)
    {
        module_index = 0;
        pdb_module_info->used_subfiles = 1;
2706
    }
2707
    cv_current_module = &cv_zmodules[module_index];
2708
    if (cv_current_module->allowed) FIXME("Already allowed??\n");
2709 2710 2711 2712 2713
    cv_current_module->allowed = TRUE;
}

static BOOL pdb_process_internal(const struct process* pcs, 
                                 const struct msc_debug_info* msc_dbg,
2714
                                 const struct pdb_lookup* pdb_lookup,
2715
                                 struct pdb_module_info* pdb_module_info,
2716 2717
                                 unsigned module_index)
{
2718
    HANDLE      hMap = NULL;
2719
    char*       image = NULL;
Mike McCormack's avatar
Mike McCormack committed
2720
    BYTE*       symbols_image = NULL;
2721 2722
    char*       files_image = NULL;
    DWORD       files_size = 0;
2723
    unsigned    matched;
2724
    struct pdb_file_info* pdb_file;
2725 2726

    TRACE("Processing PDB file %s\n", pdb_lookup->filename);
2727

2728
    pdb_file = &pdb_module_info->pdb_files[module_index == -1 ? 0 : module_index];
2729
    /* Open and map() .PDB file */
2730
    if ((hMap = map_pdb_file(pcs, pdb_lookup, msc_dbg->module)) == NULL ||
2731
        ((image = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) == NULL))
2732
    {
Mike Hearn's avatar
Mike Hearn committed
2733
        WARN("Unable to open .PDB file: %s\n", pdb_lookup->filename);
2734 2735
        CloseHandle(hMap);
        return FALSE;
2736
    }
2737 2738
    if (!pdb_init(pdb_lookup, pdb_file, image, &matched) || matched != 2)
    {
2739 2740 2741
        CloseHandle(hMap);
        UnmapViewOfFile(image);
        return FALSE;
2742
    }
2743

2744 2745 2746
    pdb_file->hMap = hMap;
    pdb_file->image = image;
    symbols_image = pdb_read_file(pdb_file, 3);
2747
    if (symbols_image)
2748
    {
2749
        PDB_SYMBOLS symbols;
2750
        BYTE*       globalimage;
Mike McCormack's avatar
Mike McCormack committed
2751 2752
        BYTE*       modimage;
        BYTE*       file;
2753
        int         header_size = 0;
2754 2755
        PDB_STREAM_INDEXES* psi;

2756 2757
        pdb_convert_symbols_header(&symbols, &header_size, symbols_image);
        switch (symbols.version)
2758
        {
2759 2760 2761 2762 2763 2764
        case 0:            /* VC 4.0 */
        case 19960307:     /* VC 5.0 */
        case 19970606:     /* VC 6.0 */
        case 19990903:
            break;
        default:
2765
            ERR("-Unknown symbol info version %d %08x\n",
2766
                symbols.version, symbols.version);
2767
        }
2768

2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785
        switch (symbols.stream_index_size)
        {
        case 0:
        case sizeof(PDB_STREAM_INDEXES_OLD):
            /* no fpo ext stream in this case */
            break;
        case sizeof(PDB_STREAM_INDEXES):
            psi = (PDB_STREAM_INDEXES*)((const char*)symbols_image + sizeof(PDB_SYMBOLS) +
                                        symbols.module_size + symbols.offset_size +
                                        symbols.hash_size + symbols.srcmodule_size +
                                        symbols.pdbimport_size + symbols.unknown2_size);
            pdb_file->fpoext_stream = psi->FPO_EXT;
            break;
        default:
            FIXME("Unknown PDB_STREAM_INDEXES size (%d)\n", symbols.stream_index_size);
            break;
        }
2786 2787
        files_image = pdb_read_strings(pdb_file);
        if (files_image) files_size = *(const DWORD*)(files_image + 8);
2788

2789 2790
        pdb_process_symbol_imports(pcs, msc_dbg, &symbols, symbols_image, image,
                                   pdb_lookup, pdb_module_info, module_index);
2791
        pdb_process_types(msc_dbg, pdb_file);
2792 2793

        /* Read global symbol table */
2794
        globalimage = pdb_read_file(pdb_file, symbols.gsym_file);
2795
        if (globalimage)
2796
        {
2797
            codeview_snarf(msc_dbg, globalimage, 0,
2798
                           pdb_get_file_size(pdb_file, symbols.gsym_file), FALSE);
2799 2800
        }

2801
        /* Read per-module symbols' tables */
2802 2803
        file = symbols_image + header_size;
        while (file - symbols_image < header_size + symbols.module_size)
2804
        {
2805 2806 2807
            PDB_SYMBOL_FILE_EX          sfile;
            const char*                 file_name;
            unsigned                    size;
2808

2809 2810
            HeapValidate(GetProcessHeap(), 0, NULL);
            pdb_convert_symbol_file(&symbols, &sfile, &size, file);
2811

2812
            modimage = pdb_read_file(pdb_file, sfile.file);
2813 2814 2815 2816
            if (modimage)
            {
                if (sfile.symbol_size)
                    codeview_snarf(msc_dbg, modimage, sizeof(DWORD),
2817 2818 2819 2820 2821 2822
                                   sfile.symbol_size, TRUE);

                if (sfile.lineno_size)
                    codeview_snarf_linetab(msc_dbg,
                                           modimage + sfile.symbol_size,
                                           sfile.lineno_size,
2823
                                           pdb_file->kind == PDB_JG);
2824 2825
                if (files_image)
                    codeview_snarf_linetab2(msc_dbg, modimage + sfile.symbol_size + sfile.lineno_size,
2826
                                   pdb_get_file_size(pdb_file, sfile.file) - sfile.symbol_size - sfile.lineno_size,
2827
                                   files_image + 12, files_size);
2828

2829 2830 2831 2832
                pdb_free(modimage);
            }
            file_name = (const char*)file + size;
            file_name += strlen(file_name) + 1;
2833
            file = (BYTE*)((DWORD_PTR)(file_name + strlen(file_name) + 1 + 3) & ~3);
2834
        }
2835 2836 2837 2838
        /* finish the remaining public and global information */
        if (globalimage)
        {
            codeview_snarf_public(msc_dbg, globalimage, 0,
2839
                                  pdb_get_file_size(pdb_file, symbols.gsym_file));
2840 2841
            pdb_free(globalimage);
        }
2842 2843
    }
    else
2844 2845
        pdb_process_symbol_imports(pcs, msc_dbg, NULL, NULL, image,
                                   pdb_lookup, pdb_module_info, module_index);
2846

2847
    pdb_free(symbols_image);
2848
    pdb_free(files_image);
2849

2850
    return TRUE;
2851 2852
}

2853 2854 2855 2856
static BOOL pdb_process_file(const struct process* pcs, 
                             const struct msc_debug_info* msc_dbg,
                             struct pdb_lookup* pdb_lookup)
{
2857
    BOOL                        ret;
2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870
    struct module_format*       modfmt;
    struct pdb_module_info*     pdb_module_info;

    modfmt = HeapAlloc(GetProcessHeap(), 0,
                       sizeof(struct module_format) + sizeof(struct pdb_module_info));
    if (!modfmt) return FALSE;

    pdb_module_info = (void*)(modfmt + 1);
    msc_dbg->module->format_info[DFI_PDB] = modfmt;
    modfmt->module      = msc_dbg->module;
    modfmt->remove      = pdb_module_remove;
    modfmt->loc_compute = NULL;
    modfmt->u.pdb_info  = pdb_module_info;
2871 2872 2873

    memset(cv_zmodules, 0, sizeof(cv_zmodules));
    codeview_init_basic_types(msc_dbg->module);
2874 2875
    ret = pdb_process_internal(pcs, msc_dbg, pdb_lookup,
                               msc_dbg->module->format_info[DFI_PDB]->u.pdb_info, -1);
2876
    codeview_clear_type_table();
Eric Pouech's avatar
Eric Pouech committed
2877 2878
    if (ret)
    {
2879
        struct pdb_module_info*     pdb_info = msc_dbg->module->format_info[DFI_PDB]->u.pdb_info;
Eric Pouech's avatar
Eric Pouech committed
2880
        msc_dbg->module->module.SymType = SymCv;
2881 2882
        if (pdb_info->pdb_files[0].kind == PDB_JG)
            msc_dbg->module->module.PdbSig = pdb_info->pdb_files[0].u.jg.timestamp;
Eric Pouech's avatar
Eric Pouech committed
2883
        else
2884 2885
            msc_dbg->module->module.PdbSig70 = pdb_info->pdb_files[0].u.ds.guid;
        msc_dbg->module->module.PdbAge = pdb_info->pdb_files[0].age;
2886 2887 2888
        MultiByteToWideChar(CP_ACP, 0, pdb_lookup->filename, -1,
                            msc_dbg->module->module.LoadedPdbName,
                            sizeof(msc_dbg->module->module.LoadedPdbName) / sizeof(WCHAR));
Eric Pouech's avatar
Eric Pouech committed
2889 2890 2891 2892 2893 2894 2895
        /* 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 = TRUE;
        msc_dbg->module->module.SourceIndexed = TRUE;
        msc_dbg->module->module.Publics = TRUE;
    }
2896 2897 2898 2899 2900
    else
    {
        msc_dbg->module->format_info[DFI_PDB] = NULL;
        HeapFree(GetProcessHeap(), 0, modfmt);
    }
2901 2902 2903
    return ret;
}

2904
BOOL pdb_fetch_file_info(const struct pdb_lookup* pdb_lookup, unsigned* matched)
2905 2906 2907
{
    HANDLE              hFile, hMap = NULL;
    char*               image = NULL;
2908
    BOOL                ret;
2909
    struct pdb_file_info pdb_file;
2910

2911
    if ((hFile = CreateFileA(pdb_lookup->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
2912
                             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE ||
2913
        ((hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == NULL) ||
2914 2915 2916 2917 2918 2919 2920
        ((image = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) == NULL))
    {
        WARN("Unable to open .PDB file: %s\n", pdb_lookup->filename);
        ret = FALSE;
    }
    else
    {
2921 2922
        ret = pdb_init(pdb_lookup, &pdb_file, image, matched);
        pdb_free_file(&pdb_file);
2923 2924 2925 2926
    }

    if (image) UnmapViewOfFile(image);
    if (hMap) CloseHandle(hMap);
2927
    if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
2928 2929 2930 2931

    return ret;
}

2932 2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955
/*========================================================================
 * FPO unwinding code
 */

/* Stack unwinding is based on postfixed operations.
 * Let's define our Postfix EValuator
 */
#define PEV_MAX_LEN      32
struct pevaluator
{
    struct cpu_stack_walk*  csw;
    struct pool             pool;
    struct vector           stack;
    unsigned                stk_index;
    struct hash_table       values;
    char                    error[64];
};

struct zvalue
{
    DWORD_PTR                   value;
    struct hash_table_elt       elt;
};

2956 2957
#define PEV_ERROR(pev, msg)       snprintf((pev)->error, sizeof((pev)->error), "%s", (msg))
#define PEV_ERROR1(pev, msg, pmt) snprintf((pev)->error, sizeof((pev)->error), (msg), (pmt))
2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982

#if 0
static void pev_dump_stack(struct pevaluator* pev)
{
    unsigned i;
    FIXME("stack #%d\n", pev->stk_index);
    for (i = 0; i < pev->stk_index; i++)
    {
        FIXME("\t%d) %s\n", i, *(char**)vector_at(&pev->stack, i));
    }
}
#endif

/* get the value out of an operand (variable or literal) */
static BOOL  pev_get_val(struct pevaluator* pev, const char* str, DWORD_PTR* val)
{
    char*                       n;
    struct hash_table_iter      hti;
    void*                       ptr;

    switch (str[0])
    {
    case '$':
    case '.':
        hash_table_iter_init(&pev->values, &hti, str);
2983 2984
        while ((ptr = hash_table_iter_up(&hti)))
        {
2985
            if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, str))
2986
            {
2987
                *val = CONTAINING_RECORD(ptr, struct zvalue, elt)->value;
2988 2989 2990 2991
                return TRUE;
            }
        }
        return PEV_ERROR1(pev, "get_zvalue: no value found (%s)", str);
2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037
    default:
        *val = strtol(str, &n, 10);
        if (n == str || *n != '\0')
            return PEV_ERROR1(pev, "get_val: not a literal (%s)", str);
        return TRUE;
    }
}

/* push an operand onto the stack */
static BOOL  pev_push(struct pevaluator* pev, const char* elt)
{
    char**      at;
    if (pev->stk_index < vector_length(&pev->stack))
        at = vector_at(&pev->stack, pev->stk_index);
    else
        at = vector_add(&pev->stack, &pev->pool);
    if (!at) return PEV_ERROR(pev, "push: out of memory");
    *at = pool_strdup(&pev->pool, elt);
    pev->stk_index++;
    return TRUE;
}

/* pop an operand from the stack */
static BOOL  pev_pop(struct pevaluator* pev, char* elt)
{
    char**      at = vector_at(&pev->stack, --pev->stk_index);
    if (!at) return PEV_ERROR(pev, "pop: stack empty");
    strcpy(elt, *at);
    return TRUE;
}

/* pop an operand from the stack, and gets its value */
static BOOL  pev_pop_val(struct pevaluator* pev, DWORD_PTR* val)
{
    char        p[PEV_MAX_LEN];

    return pev_pop(pev, p) && pev_get_val(pev, p, val);
}

/* set var 'name' a new value (creates the var if it doesn't exist) */
static BOOL  pev_set_value(struct pevaluator* pev, const char* name, DWORD_PTR val)
{
    struct hash_table_iter      hti;
    void*                       ptr;

    hash_table_iter_init(&pev->values, &hti, name);
3038 3039
    while ((ptr = hash_table_iter_up(&hti)))
    {
3040
        if (!strcmp(CONTAINING_RECORD(ptr, struct zvalue, elt)->elt.name, name))
3041
        {
3042
            CONTAINING_RECORD(ptr, struct zvalue, elt)->value = val;
3043 3044 3045 3046
            break;
        }
    }
    if (!ptr)
3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209
    {
        struct zvalue* zv = pool_alloc(&pev->pool, sizeof(*zv));
        if (!zv) return PEV_ERROR(pev, "set_value: out of memory");
        zv->value = val;

        zv->elt.name = pool_strdup(&pev->pool, name);
        hash_table_add(&pev->values, &zv->elt);
    }
    return TRUE;
}

/* execute a binary operand from the two top most values on the stack.
 * puts result on top of the stack */
static BOOL  pev_binop(struct pevaluator* pev, char op)
{
    char        res[PEV_MAX_LEN];
    DWORD_PTR   v1, v2, c;

    if (!pev_pop_val(pev, &v1) || !pev_pop_val(pev, &v2)) return FALSE;
    switch (op)
    {
    case '+': c = v1 + v2; break;
    case '-': c = v1 - v2; break;
    case '*': c = v1 * v2; break;
    case '/': c = v1 / v2; break;
    case '%': c = v1 % v2; break;
    default: return PEV_ERROR1(pev, "binop: unknown op (%c)", op);
    }
    snprintf(res, sizeof(res), "%ld", c);
    pev_push(pev, res);
    return TRUE;
}

/* pops top most operand, dereference it, on pushes the result on top of the stack */
static BOOL  pev_deref(struct pevaluator* pev)
{
    char        res[PEV_MAX_LEN];
    DWORD_PTR   v1, v2;

    if (!pev_pop_val(pev, &v1)) return FALSE;
    if (!sw_read_mem(pev->csw, v1, &v2, sizeof(v2)))
        return PEV_ERROR1(pev, "deref: cannot read mem at %lx\n", v1);
    snprintf(res, sizeof(res), "%ld", v2);
    pev_push(pev, res);
    return TRUE;
}

/* assign value to variable (from two top most operands) */
static BOOL  pev_assign(struct pevaluator* pev)
{
    char                p2[PEV_MAX_LEN];
    DWORD_PTR           v1;

    if (!pev_pop_val(pev, &v1) || !pev_pop(pev, p2)) return FALSE;
    if (p2[0] != '$') return PEV_ERROR1(pev, "assign: %s isn't a variable", p2);
    pev_set_value(pev, p2, v1);

    return TRUE;
}

/* initializes the postfix evaluator */
static void  pev_init(struct pevaluator* pev, struct cpu_stack_walk* csw,
                      PDB_FPO_DATA* fpoext, struct pdb_cmd_pair* cpair)
{
    pev->csw = csw;
    pool_init(&pev->pool, 512);
    vector_init(&pev->stack, sizeof(char*), 8);
    pev->stk_index = 0;
    hash_table_init(&pev->pool, &pev->values, 8);
    pev->error[0] = '\0';
    for (; cpair->name; cpair++)
        pev_set_value(pev, cpair->name, *cpair->pvalue);
    pev_set_value(pev, ".raSearchStart", fpoext->start);
    pev_set_value(pev, ".cbLocals",      fpoext->locals_size);
    pev_set_value(pev, ".cbParams",      fpoext->params_size);
    pev_set_value(pev, ".cbSavedRegs",   fpoext->savedregs_size);
}

static BOOL  pev_free(struct pevaluator* pev, struct pdb_cmd_pair* cpair)
{
    DWORD_PTR   val;

    if (cpair) for (; cpair->name; cpair++)
    {
        if (pev_get_val(pev, cpair->name, &val))
            *cpair->pvalue = val;
    }
    pool_destroy(&pev->pool);
    return TRUE;
}

static BOOL  pdb_parse_cmd_string(struct cpu_stack_walk* csw, PDB_FPO_DATA* fpoext,
                                  const char* cmd, struct pdb_cmd_pair* cpair)
{
    char                token[PEV_MAX_LEN];
    char*               ptok = token;
    const char*         ptr;
    BOOL                over = FALSE;
    struct pevaluator   pev;

    pev_init(&pev, csw, fpoext, cpair);
    for (ptr = cmd; !over; ptr++)
    {
        if (*ptr == ' ' || (over = *ptr == '\0'))
        {
            *ptok = '\0';

            if (!strcmp(token, "+") || !strcmp(token, "-") || !strcmp(token, "*") ||
                !strcmp(token, "/") || !strcmp(token, "%"))
            {
                if (!pev_binop(&pev, token[0])) goto done;
            }
            else if (!strcmp(token, "^"))
            {
                if (!pev_deref(&pev)) goto done;
            }
            else if (!strcmp(token, "="))
            {
                if (!pev_assign(&pev)) goto done;
            }
            else
            {
                if (!pev_push(&pev, token)) goto done;
            }
            ptok = token;
        }
        else
        {
            if (ptok - token >= PEV_MAX_LEN - 1)
            {
                PEV_ERROR1(&pev, "parse: token too long (%s)", ptr - (ptok - token));
                goto done;
            }
            *ptok++ = *ptr;
        }
    }
    pev_free(&pev, cpair);
    return TRUE;
done:
    FIXME("Couldn't evaluate %s => %s\n", wine_dbgstr_a(cmd), pev.error);
    pev_free(&pev, NULL);
    return FALSE;
}

BOOL         pdb_virtual_unwind(struct cpu_stack_walk* csw, DWORD_PTR ip,
                                CONTEXT* context, struct pdb_cmd_pair* cpair)
{
    struct module_pair          pair;
    struct pdb_module_info*     pdb_info;
    PDB_FPO_DATA*               fpoext;
    unsigned                    i, size, strsize;
    char*                       strbase;
    BOOL                        ret = TRUE;

    if (!(pair.pcs = process_find_by_handle(csw->hProcess)) ||
        !(pair.requested = module_find_by_addr(pair.pcs, ip, DMT_UNKNOWN)) ||
        !module_get_debug(&pair))
        return FALSE;
    if (!pair.effective->format_info[DFI_PDB]) return FALSE;
    pdb_info = pair.effective->format_info[DFI_PDB]->u.pdb_info;
    TRACE("searching %lx => %lx\n", ip, ip - (DWORD_PTR)pair.effective->module.BaseOfImage);
    ip -= (DWORD_PTR)pair.effective->module.BaseOfImage;

3210
    strbase = pdb_read_strings(&pdb_info->pdb_files[0]);
3211 3212
    if (!strbase) return FALSE;
    strsize = *(const DWORD*)(strbase + 8);
3213 3214
    fpoext = pdb_read_file(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream);
    size = pdb_get_file_size(&pdb_info->pdb_files[0], pdb_info->pdb_files[0].fpoext_stream);
3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228
    if (fpoext && (size % sizeof(*fpoext)) == 0)
    {
        size /= sizeof(*fpoext);
        for (i = 0; i < size; i++)
        {
            if (fpoext[i].start <= ip && ip < fpoext[i].start + fpoext[i].func_size)
            {
                TRACE("\t%08x %08x %8x %8x %4x %4x %4x %08x %s\n",
                      fpoext[i].start, fpoext[i].func_size, fpoext[i].locals_size,
                      fpoext[i].params_size, fpoext[i].maxstack_size, fpoext[i].prolog_size,
                      fpoext[i].savedregs_size, fpoext[i].flags,
                      fpoext[i].str_offset < strsize ?
                          wine_dbgstr_a(strbase + 12 + fpoext[i].str_offset) : "<out of bounds>");
                if (fpoext[i].str_offset < strsize)
3229
                    ret = pdb_parse_cmd_string(csw, &fpoext[i], strbase + 12 + fpoext[i].str_offset, cpair);
3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242
                else
                    ret = FALSE;
                break;
            }
        }
    }
    else ret = FALSE;
    pdb_free(fpoext);
    pdb_free(strbase);

    return ret;
}

3243 3244 3245 3246
/*========================================================================
 * Process CodeView debug information.
 */

3247 3248 3249 3250 3251
#define MAKESIG(a,b,c,d)        ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
#define CODEVIEW_NB09_SIG       MAKESIG('N','B','0','9')
#define CODEVIEW_NB10_SIG       MAKESIG('N','B','1','0')
#define CODEVIEW_NB11_SIG       MAKESIG('N','B','1','1')
#define CODEVIEW_RSDS_SIG       MAKESIG('R','S','D','S')
3252

3253 3254
static BOOL codeview_process_info(const struct process* pcs, 
                                  const struct msc_debug_info* msc_dbg)
3255
{
3256
    const DWORD*                signature = (const DWORD*)msc_dbg->root;
3257
    BOOL                        ret = FALSE;
3258
    struct pdb_lookup           pdb_lookup;
3259

3260
    TRACE("Processing signature %.4s\n", (const char*)signature);
3261

3262
    switch (*signature)
3263 3264 3265 3266
    {
    case CODEVIEW_NB09_SIG:
    case CODEVIEW_NB11_SIG:
    {
3267 3268 3269 3270 3271
        const OMFSignature*     cv = (const OMFSignature*)msc_dbg->root;
        const OMFDirHeader*     hdr = (const OMFDirHeader*)(msc_dbg->root + cv->filepos);
        const OMFDirEntry*      ent;
        const OMFDirEntry*      prev;
        const OMFDirEntry*      next;
3272 3273 3274
        unsigned int                    i;

        codeview_init_basic_types(msc_dbg->module);
3275 3276 3277

        for (i = 0; i < hdr->cDir; i++)
        {
3278 3279
            ent = (const OMFDirEntry*)((const BYTE*)hdr + hdr->cbDirHeader + i * hdr->cbDirEntry);
            if (ent->SubSection == sstGlobalTypes)
3280
            {
3281
                const OMFGlobalTypes*           types;
3282 3283
                struct codeview_type_parse      ctp;

3284
                types = (const OMFGlobalTypes*)(msc_dbg->root + ent->lfo);
3285 3286 3287 3288 3289 3290
                ctp.module = msc_dbg->module;
                ctp.offset = (const DWORD*)(types + 1);
                ctp.num    = types->cTypes;
                ctp.table  = (const BYTE*)(ctp.offset + types->cTypes);

                cv_current_module = &cv_zmodules[0];
3291
                if (cv_current_module->allowed) FIXME("Already allowed??\n");
3292 3293 3294 3295 3296 3297 3298
                cv_current_module->allowed = TRUE;

                codeview_parse_type_table(&ctp);
                break;
            }
        }

3299
        ent = (const OMFDirEntry*)((const BYTE*)hdr + hdr->cbDirHeader);
3300 3301
        for (i = 0; i < hdr->cDir; i++, ent = next)
        {
3302
            next = (i == hdr->cDir-1) ? NULL :
3303
                   (const OMFDirEntry*)((const BYTE*)ent + hdr->cbDirEntry);
3304
            prev = (i == 0) ? NULL :
3305
                   (const OMFDirEntry*)((const BYTE*)ent - hdr->cbDirEntry);
3306

3307
            if (ent->SubSection == sstAlignSym)
3308
            {
3309 3310 3311
                codeview_snarf(msc_dbg, msc_dbg->root + ent->lfo, sizeof(DWORD),
                               ent->cb, TRUE);

3312 3313 3314 3315 3316 3317 3318
                /*
                 * Check the next and previous entry.  If either is a
                 * sstSrcModule, it contains the line number info for
                 * this file.
                 *
                 * FIXME: This is not a general solution!
                 */
3319 3320 3321
                if (next && next->iMod == ent->iMod && next->SubSection == sstSrcModule)
                    codeview_snarf_linetab(msc_dbg, msc_dbg->root + next->lfo,
                                           next->cb, TRUE);
3322

3323 3324 3325
                if (prev && prev->iMod == ent->iMod && prev->SubSection == sstSrcModule)
                    codeview_snarf_linetab(msc_dbg, msc_dbg->root + prev->lfo,
                                           prev->cb, TRUE);
3326 3327 3328 3329

            }
        }

3330
        msc_dbg->module->module.SymType = SymCv;
Eric Pouech's avatar
Eric Pouech committed
3331 3332 3333 3334 3335 3336
        /* 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 = TRUE;
        msc_dbg->module->module.SourceIndexed = TRUE;
        msc_dbg->module->module.Publics = TRUE;
3337
        codeview_clear_type_table();
3338
        ret = TRUE;
3339 3340 3341 3342 3343
        break;
    }

    case CODEVIEW_NB10_SIG:
    {
3344
        const CODEVIEW_PDB_DATA* pdb = (const CODEVIEW_PDB_DATA*)msc_dbg->root;
3345 3346
        pdb_lookup.filename = pdb->name;
        pdb_lookup.kind = PDB_JG;
3347
        pdb_lookup.timestamp = pdb->timestamp;
3348
        pdb_lookup.age = pdb->age;
3349 3350 3351 3352 3353
        ret = pdb_process_file(pcs, msc_dbg, &pdb_lookup);
        break;
    }
    case CODEVIEW_RSDS_SIG:
    {
3354
        const OMFSignatureRSDS* rsds = (const OMFSignatureRSDS*)msc_dbg->root;
3355

3356 3357
        TRACE("Got RSDS type of PDB file: guid=%s age=%08x name=%s\n",
              wine_dbgstr_guid(&rsds->guid), rsds->age, rsds->name);
3358 3359
        pdb_lookup.filename = rsds->name;
        pdb_lookup.kind = PDB_DS;
3360
        pdb_lookup.guid = rsds->guid;
3361
        pdb_lookup.age = rsds->age;
3362
        ret = pdb_process_file(pcs, msc_dbg, &pdb_lookup);
3363 3364 3365
        break;
    }
    default:
3366 3367
        ERR("Unknown CODEVIEW signature %08x in module %s\n",
            *signature, debugstr_w(msc_dbg->module->module.ModuleName));
3368 3369
        break;
    }
Eric Pouech's avatar
Eric Pouech committed
3370 3371
    if (ret)
    {
3372 3373
        msc_dbg->module->module.CVSig = *signature;
        memcpy(msc_dbg->module->module.CVData, msc_dbg->root,
Eric Pouech's avatar
Eric Pouech committed
3374 3375
               sizeof(msc_dbg->module->module.CVData));
    }
3376
    return ret;
3377 3378 3379 3380 3381
}

/*========================================================================
 * Process debug directory.
 */
3382
BOOL pe_load_debug_directory(const struct process* pcs, struct module* module, 
3383 3384 3385
                             const BYTE* mapping,
                             const IMAGE_SECTION_HEADER* sectp, DWORD nsect,
                             const IMAGE_DEBUG_DIRECTORY* dbg, int nDbg)
3386
{
3387
    BOOL                        ret;
3388 3389 3390 3391
    int                         i;
    struct msc_debug_info       msc_dbg;

    msc_dbg.module = module;
3392 3393
    msc_dbg.nsect  = nsect;
    msc_dbg.sectp  = sectp;
3394 3395 3396 3397 3398
    msc_dbg.nomap  = 0;
    msc_dbg.omapp  = NULL;

    __TRY
    {
3399
        ret = FALSE;
3400 3401 3402 3403 3404 3405 3406

        /* First, watch out for OMAP data */
        for (i = 0; i < nDbg; i++)
        {
            if (dbg[i].Type == IMAGE_DEBUG_TYPE_OMAP_FROM_SRC)
            {
                msc_dbg.nomap = dbg[i].SizeOfData / sizeof(OMAP_DATA);
3407
                msc_dbg.omapp = (const OMAP_DATA*)(mapping + dbg[i].PointerToRawData);
3408 3409 3410 3411 3412 3413 3414 3415 3416 3417
                break;
            }
        }
  
        /* Now, try to parse CodeView debug info */
        for (i = 0; i < nDbg; i++)
        {
            if (dbg[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW)
            {
                msc_dbg.root = mapping + dbg[i].PointerToRawData;
3418
                if ((ret = codeview_process_info(pcs, &msc_dbg))) goto done;
3419 3420 3421 3422 3423 3424 3425 3426 3427
            }
        }
    
        /* If not found, try to parse COFF debug info */
        for (i = 0; i < nDbg; i++)
        {
            if (dbg[i].Type == IMAGE_DEBUG_TYPE_COFF)
            {
                msc_dbg.root = mapping + dbg[i].PointerToRawData;
3428
                if ((ret = coff_process_info(&msc_dbg))) goto done;
3429 3430 3431 3432 3433 3434 3435 3436 3437
            }
        }
    done:
	 /* FIXME: this should be supported... this is the debug information for
	  * functions compiled without a frame pointer (FPO = frame pointer omission)
	  * the associated data helps finding out the relevant information
	  */
        for (i = 0; i < nDbg; i++)
            if (dbg[i].Type == IMAGE_DEBUG_TYPE_FPO)
3438 3439
                FIXME("This guy has FPO information\n");
#if 0
3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459

#define FRAME_FPO   0
#define FRAME_TRAP  1
#define FRAME_TSS   2

typedef struct _FPO_DATA 
{
	DWORD       ulOffStart;            /* offset 1st byte of function code */
	DWORD       cbProcSize;            /* # bytes in function */
	DWORD       cdwLocals;             /* # bytes in locals/4 */
	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
3460

3461
    }
3462
    __EXCEPT_PAGE_FAULT
3463 3464
    {
        ERR("Got a page fault while loading symbols\n");
3465
        ret = FALSE;
3466 3467
    }
    __ENDTRY
3468
    return ret;
3469
}