cpu_x86_64.c 37.2 KB
Newer Older
1 2 3
/*
 * File cpu_x86_64.c
 *
4
 * Copyright (C) 1999, 2005 Alexandre Julliard
5
 * Copyright (C) 2009, 2011 Eric Pouech.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <assert.h>

24 25
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
26 27 28 29 30 31 32 33
#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "dbghelp_private.h"
#include "winternl.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dbghelp);

34 35 36 37 38 39 40 41 42 43
/* x86-64 unwind information, for PE modules, as described on MSDN */

typedef enum _UNWIND_OP_CODES
{
    UWOP_PUSH_NONVOL = 0,
    UWOP_ALLOC_LARGE,
    UWOP_ALLOC_SMALL,
    UWOP_SET_FPREG,
    UWOP_SAVE_NONVOL,
    UWOP_SAVE_NONVOL_FAR,
44 45
    UWOP_EPILOG,
    UWOP_SAVE_XMM128 = 8,
46 47 48 49 50 51 52 53 54 55 56
    UWOP_SAVE_XMM128_FAR,
    UWOP_PUSH_MACHFRAME
} UNWIND_CODE_OPS;

typedef union _UNWIND_CODE
{
    struct
    {
        BYTE CodeOffset;
        BYTE UnwindOp : 4;
        BYTE OpInfo   : 4;
57
    } u;
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
    USHORT FrameOffset;
} UNWIND_CODE, *PUNWIND_CODE;

typedef struct _UNWIND_INFO
{
    BYTE Version       : 3;
    BYTE Flags         : 5;
    BYTE SizeOfProlog;
    BYTE CountOfCodes;
    BYTE FrameRegister : 4;
    BYTE FrameOffset   : 4;
    UNWIND_CODE UnwindCode[1]; /* actually CountOfCodes (aligned) */
/*
 *  union
 *  {
 *      OPTIONAL ULONG ExceptionHandler;
 *      OPTIONAL ULONG FunctionEntry;
 *  };
 *  OPTIONAL ULONG ExceptionData[];
 */
} UNWIND_INFO, *PUNWIND_INFO;

80 81
static BOOL x86_64_get_addr(HANDLE hThread, const CONTEXT* ctx,
                            enum cpu_addr ca, ADDRESS64* addr)
82 83 84 85 86 87 88 89 90 91 92 93 94 95
{
    addr->Mode = AddrModeFlat;
    switch (ca)
    {
#ifdef __x86_64__
    case cpu_addr_pc:    addr->Segment = ctx->SegCs; addr->Offset = ctx->Rip; return TRUE;
    case cpu_addr_stack: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rsp; return TRUE;
    case cpu_addr_frame: addr->Segment = ctx->SegSs; addr->Offset = ctx->Rbp; return TRUE;
#endif
    default: addr->Mode = -1;
        return FALSE;
    }
}

96 97
#ifdef __x86_64__

98 99 100 101
enum st_mode {stm_start, stm_64bit, stm_done};

/* indexes in Reserved array */
#define __CurrentMode     0
102 103
#define __CurrentCount    1
/* #define __     2 (unused) */
104 105

#define curr_mode   (frame->Reserved[__CurrentMode])
106 107
#define curr_count  (frame->Reserved[__CurrentCount])
/* #define ??? (frame->Reserved[__]) (unused) */
108

109 110 111 112 113 114
union handler_data
{
    RUNTIME_FUNCTION chain;
    ULONG handler;
};

115
static void dump_unwind_info(struct cpu_stack_walk* csw, ULONG64 base, RUNTIME_FUNCTION *function)
116 117 118 119 120
{
    static const char * const reg_names[16] =
        { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
          "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15" };

121
    union handler_data handler_data;
122 123 124
    char buffer[sizeof(UNWIND_INFO) + 256 * sizeof(UNWIND_CODE)];
    UNWIND_INFO* info = (UNWIND_INFO*)buffer;
    unsigned int i, count;
125 126
    RUNTIME_FUNCTION snext;
    ULONG64 addr;
127

128
    TRACE("**** func %lx-%lx\n", function->BeginAddress, function->EndAddress);
129 130 131 132
    for (;;)
    {
        if (function->UnwindData & 1)
        {
133 134
            if (!sw_read_mem(csw, base + function->UnwindData, &snext, sizeof(snext)))
            {
135
                TRACE("Couldn't unwind RUNTIME_INFO at %Ix\n", base + function->UnwindData);
136 137
                return;
            }
138 139
            TRACE("unwind info for function %p-%p chained to function %p-%p\n",
                  (char*)base + function->BeginAddress, (char*)base + function->EndAddress,
140 141
                  (char*)base + snext.BeginAddress, (char*)base + snext.EndAddress);
            function = &snext;
142 143
            continue;
        }
144 145 146 147 148
        addr = base + function->UnwindData;
        if (!sw_read_mem(csw, addr, info, FIELD_OFFSET(UNWIND_INFO, UnwindCode)) ||
            !sw_read_mem(csw, addr + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
                         info->UnwindCode, info->CountOfCodes * sizeof(UNWIND_CODE)))
        {
149
            FIXME("couldn't read memory for UNWIND_INFO at %Ix\n", addr);
150 151
            return;
        }
152
        TRACE("unwind info at %p flags %x prolog 0x%x bytes function %p-%p\n",
153
              (char*)addr, info->Flags, info->SizeOfProlog,
154 155 156 157 158 159 160 161
              (char*)base + function->BeginAddress, (char*)base + function->EndAddress);

        if (info->FrameRegister)
            TRACE("    frame register %s offset 0x%x(%%rsp)\n",
                  reg_names[info->FrameRegister], info->FrameOffset * 16);

        for (i = 0; i < info->CountOfCodes; i++)
        {
162 163
            TRACE("    0x%x: ", info->UnwindCode[i].u.CodeOffset);
            switch (info->UnwindCode[i].u.UnwindOp)
164 165
            {
            case UWOP_PUSH_NONVOL:
166
                TRACE("pushq %%%s\n", reg_names[info->UnwindCode[i].u.OpInfo]);
167 168
                break;
            case UWOP_ALLOC_LARGE:
169
                if (info->UnwindCode[i].u.OpInfo)
170 171 172 173 174 175 176 177 178 179 180 181
                {
                    count = *(DWORD*)&info->UnwindCode[i+1];
                    i += 2;
                }
                else
                {
                    count = *(USHORT*)&info->UnwindCode[i+1] * 8;
                    i++;
                }
                TRACE("subq $0x%x,%%rsp\n", count);
                break;
            case UWOP_ALLOC_SMALL:
182
                count = (info->UnwindCode[i].u.OpInfo + 1) * 8;
183 184 185 186 187 188 189 190
                TRACE("subq $0x%x,%%rsp\n", count);
                break;
            case UWOP_SET_FPREG:
                TRACE("leaq 0x%x(%%rsp),%s\n",
                      info->FrameOffset * 16, reg_names[info->FrameRegister]);
                break;
            case UWOP_SAVE_NONVOL:
                count = *(USHORT*)&info->UnwindCode[i+1] * 8;
191
                TRACE("movq %%%s,0x%x(%%rsp)\n", reg_names[info->UnwindCode[i].u.OpInfo], count);
192 193 194 195
                i++;
                break;
            case UWOP_SAVE_NONVOL_FAR:
                count = *(DWORD*)&info->UnwindCode[i+1];
196
                TRACE("movq %%%s,0x%x(%%rsp)\n", reg_names[info->UnwindCode[i].u.OpInfo], count);
197 198 199 200
                i += 2;
                break;
            case UWOP_SAVE_XMM128:
                count = *(USHORT*)&info->UnwindCode[i+1] * 16;
201
                TRACE("movaps %%xmm%u,0x%x(%%rsp)\n", info->UnwindCode[i].u.OpInfo, count);
202 203 204 205
                i++;
                break;
            case UWOP_SAVE_XMM128_FAR:
                count = *(DWORD*)&info->UnwindCode[i+1];
206
                TRACE("movaps %%xmm%u,0x%x(%%rsp)\n", info->UnwindCode[i].u.OpInfo, count);
207 208 209
                i += 2;
                break;
            case UWOP_PUSH_MACHFRAME:
210
                TRACE("PUSH_MACHFRAME %u\n", info->UnwindCode[i].u.OpInfo);
211
                break;
212 213 214 215 216 217 218 219 220 221 222 223 224
            case UWOP_EPILOG:
                if (info->Version == 2)
                {
                    unsigned int offset;
                    if (info->UnwindCode[i].u.OpInfo)
                        offset = info->UnwindCode[i].u.CodeOffset;
                    else
                        offset = (info->UnwindCode[i+1].u.OpInfo << 8) + info->UnwindCode[i+1].u.CodeOffset;
                    TRACE("UWOP_EPILOG %u offset %u\n", info->UnwindCode[i].u.OpInfo, offset);
                    i += 1;
                    break;
                }
                /* Fall through */
225
            default:
226
                FIXME("unknown code %u\n", info->UnwindCode[i].u.UnwindOp);
227 228 229 230
                break;
            }
        }

231 232
        addr += FIELD_OFFSET(UNWIND_INFO, UnwindCode) +
            ((info->CountOfCodes + 1) & ~1) * sizeof(UNWIND_CODE);
233 234
        if (info->Flags & UNW_FLAG_CHAININFO)
        {
235 236 237 238 239
            if (!sw_read_mem(csw, addr, &handler_data, sizeof(handler_data.chain)))
            {
                FIXME("couldn't read memory for handler_data.chain\n");
                return;
            }
240
            TRACE("    chained to function %p-%p\n",
241 242 243
                  (char*)base + handler_data.chain.BeginAddress,
                  (char*)base + handler_data.chain.EndAddress);
            function = &handler_data.chain;
244 245 246
            continue;
        }
        if (info->Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
247 248 249 250 251 252
        {
            if (!sw_read_mem(csw, addr, &handler_data, sizeof(handler_data.handler)))
            {
                FIXME("couldn't read memory for handler_data.handler\n");
                return;
            }
253
            TRACE("    handler %p data at %p\n",
254 255
                  (char*)base + handler_data.handler, (char*)addr + sizeof(handler_data.handler));
        }
256 257 258 259
        break;
    }
}

260
/* highly derived from dlls/ntdll/signal_x86_64.c */
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
static ULONG64 get_int_reg(CONTEXT *context, int reg)
{
    return *(&context->Rax + reg);
}

static void set_int_reg(CONTEXT *context, int reg, ULONG64 val)
{
    *(&context->Rax + reg) = val;
}

static void set_float_reg(CONTEXT *context, int reg, M128A val)
{
    *(&context->u.s.Xmm0 + reg) = val;
}

static int get_opcode_size(UNWIND_CODE op)
277
{
278
    switch (op.u.UnwindOp)
279 280
    {
    case UWOP_ALLOC_LARGE:
281
        return 2 + (op.u.OpInfo != 0);
282 283 284 285 286 287 288 289 290 291 292
    case UWOP_SAVE_NONVOL:
    case UWOP_SAVE_XMM128:
        return 2;
    case UWOP_SAVE_NONVOL_FAR:
    case UWOP_SAVE_XMM128_FAR:
        return 3;
    default:
        return 1;
    }
}

293 294
static BOOL is_inside_epilog(struct cpu_stack_walk* csw, DWORD64 pc,
                             DWORD64 base, const RUNTIME_FUNCTION *function )
295
{
296 297
    BYTE op0, op1, op2;
    LONG val32;
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315

    if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;

    /* add or lea must be the first instruction, and it must have a rex.W prefix */
    if ((op0 & 0xf8) == 0x48)
    {
        if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
        switch (op1)
        {
        case 0x81: /* add $nnnn,%rsp */
            if (!sw_read_mem(csw, pc + 2, &op2, 1)) return FALSE;
            if (op0 == 0x48 && op2 == 0xc4)
            {
                pc += 7;
                break;
            }
            return FALSE;
        case 0x83: /* add $n,%rsp */
316
            if (!sw_read_mem(csw, pc + 2, &op2, 1)) return FALSE;
317 318 319 320 321 322 323
            if (op0 == 0x48 && op2 == 0xc4)
            {
                pc += 4;
                break;
            }
            return FALSE;
        case 0x8d: /* lea n(reg),%rsp */
324
            if (!sw_read_mem(csw, pc + 2, &op2, 1)) return FALSE;
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
            if (op0 & 0x06) return FALSE;  /* rex.RX must be cleared */
            if (((op2 >> 3) & 7) != 4) return FALSE;  /* dest reg mus be %rsp */
            if ((op2 & 7) == 4) return FALSE;  /* no SIB byte allowed */
            if ((op2 >> 6) == 1)  /* 8-bit offset */
            {
                pc += 4;
                break;
            }
            if ((op2 >> 6) == 2)  /* 32-bit offset */
            {
                pc += 7;
                break;
            }
            return FALSE;
        }
    }

    /* now check for various pop instructions */
    for (;;)
    {
        if (!sw_read_mem(csw, pc, &op0, 1)) return FALSE;
346
        if ((op0 & 0xf0) == 0x40)  /* rex prefix */
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365
        {
            if (!sw_read_mem(csw, ++pc, &op0, 1)) return FALSE;
        }

        switch (op0)
        {
        case 0x58: /* pop %rax/%r8 */
        case 0x59: /* pop %rcx/%r9 */
        case 0x5a: /* pop %rdx/%r10 */
        case 0x5b: /* pop %rbx/%r11 */
        case 0x5c: /* pop %rsp/%r12 */
        case 0x5d: /* pop %rbp/%r13 */
        case 0x5e: /* pop %rsi/%r14 */
        case 0x5f: /* pop %rdi/%r15 */
            pc++;
            continue;
        case 0xc2: /* ret $nn */
        case 0xc3: /* ret */
            return TRUE;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
        case 0xe9: /* jmp nnnn */
            if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE;
            pc += 5 + val32;
            if (pc - base >= function->BeginAddress && pc - base < function->EndAddress)
                continue;
            break;
        case 0xeb: /* jmp n */
            if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
            pc += 2 + (signed char)op1;
            if (pc - base >= function->BeginAddress && pc - base < function->EndAddress)
                continue;
            break;
        case 0xf3: /* rep; ret (for amd64 prediction bug) */
            if (!sw_read_mem(csw, pc + 1, &op1, 1)) return FALSE;
            return op1 == 0xc3;
381 382 383 384 385
        }
        return FALSE;
    }
}

386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419
static BOOL interpret_epilog(struct cpu_stack_walk* csw, ULONG64 pc, CONTEXT *context )
{
    BYTE        insn, val8;
    WORD        val16;
    LONG        val32;
    DWORD64     val64;

    for (;;)
    {
        BYTE rex = 0;

        if (!sw_read_mem(csw, pc, &insn, 1)) return FALSE;
        if ((insn & 0xf0) == 0x40)
        {
            rex = insn & 0x0f;  /* rex prefix */
            if (!sw_read_mem(csw, ++pc, &insn, 1)) return FALSE;
        }

        switch (insn)
        {
        case 0x58: /* pop %rax/r8 */
        case 0x59: /* pop %rcx/r9 */
        case 0x5a: /* pop %rdx/r10 */
        case 0x5b: /* pop %rbx/r11 */
        case 0x5c: /* pop %rsp/r12 */
        case 0x5d: /* pop %rbp/r13 */
        case 0x5e: /* pop %rsi/r14 */
        case 0x5f: /* pop %rdi/r15 */
            if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
            set_int_reg(context, insn - 0x58 + (rex & 1) * 8, val64);
            context->Rsp += sizeof(ULONG64);
            pc++;
            continue;
        case 0x81: /* add $nnnn,%rsp */
420 421
            if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE;
            context->Rsp += val32;
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
            pc += 2 + sizeof(LONG);
            continue;
        case 0x83: /* add $n,%rsp */
            if (!sw_read_mem(csw, pc + 2, &val8, sizeof(BYTE))) return FALSE;
            context->Rsp += (signed char)val8;
            pc += 3;
            continue;
        case 0x8d:
            if (!sw_read_mem(csw, pc + 1, &insn, sizeof(BYTE))) return FALSE;
            if ((insn >> 6) == 1)  /* lea n(reg),%rsp */
            {
                if (!sw_read_mem(csw, pc + 2, &val8, sizeof(BYTE))) return FALSE;
                context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + (signed char)val8;
                pc += 3;
            }
            else  /* lea nnnn(reg),%rsp */
            {
439 440
                if (!sw_read_mem(csw, pc + 2, &val32, sizeof(LONG))) return FALSE;
                context->Rsp = get_int_reg( context, (insn & 7) + (rex & 1) * 8 ) + val32;
441 442 443 444 445 446 447 448 449 450
                pc += 2 + sizeof(LONG);
            }
            continue;
        case 0xc2: /* ret $nn */
            if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
            if (!sw_read_mem(csw, pc + 1, &val16, sizeof(WORD))) return FALSE;
            context->Rip = val64;
            context->Rsp += sizeof(ULONG64) + val16;
            return TRUE;
        case 0xc3: /* ret */
451
        case 0xf3: /* rep; ret */
452 453 454 455
            if (!sw_read_mem(csw, context->Rsp, &val64, sizeof(DWORD64))) return FALSE;
            context->Rip = val64;
            context->Rsp += sizeof(ULONG64);
            return TRUE;
456 457 458 459 460 461 462 463
        case 0xe9: /* jmp nnnn */
            if (!sw_read_mem(csw, pc + 1, &val32, sizeof(LONG))) return FALSE;
            pc += 5 + val32;
            continue;
        case 0xeb: /* jmp n */
            if (!sw_read_mem(csw, pc + 1, &val8, sizeof(BYTE))) return FALSE;
            pc += 2 + (signed char)val8;
            continue;
464 465 466 467 468 469
        }
        FIXME("unsupported insn %x\n", insn);
        return FALSE;
    }
}

470
static BOOL default_unwind(struct cpu_stack_walk* csw, CONTEXT* context)
471
{
472
    if (!sw_read_mem(csw, context->Rsp, &context->Rip, sizeof(DWORD64)))
473
    {
474
        WARN("Cannot read new frame offset %s\n", wine_dbgstr_longlong(context->Rsp));
475 476 477 478 479 480
        return FALSE;
    }
    context->Rsp += sizeof(DWORD64);
    return TRUE;
}

481
static BOOL interpret_function_table_entry(struct cpu_stack_walk* csw,
482 483 484 485 486 487 488 489
                                           CONTEXT* context, RUNTIME_FUNCTION* function, DWORD64 base)
{
    char                buffer[sizeof(UNWIND_INFO) + 256 * sizeof(UNWIND_CODE)];
    UNWIND_INFO*        info = (UNWIND_INFO*)buffer;
    unsigned            i;
    DWORD64             newframe, prolog_offset, off, value;
    M128A               floatvalue;
    union handler_data  handler_data;
490
    BOOL                mach_frame = FALSE;
491 492 493

    /* FIXME: we have some assumptions here */
    assert(context);
494
    dump_unwind_info(csw, sw_module_base(csw, context->Rip), function);
495 496 497 498 499 500 501
    newframe = context->Rsp;
    for (;;)
    {
        if (!sw_read_mem(csw, base + function->UnwindData, info, sizeof(*info)) ||
            !sw_read_mem(csw, base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode),
                         info->UnwindCode, info->CountOfCodes * sizeof(UNWIND_CODE)))
        {
502
            WARN("Couldn't read unwind_code at %Ix\n", base + function->UnwindData);
503 504 505
            return FALSE;
        }

506
        if (info->Version != 1 && info->Version != 2)
507
        {
508
            WARN("unknown unwind info version %u at %Ix\n", info->Version, base + function->UnwindData);
509 510 511 512 513 514 515
            return FALSE;
        }

        if (info->FrameRegister)
            newframe = get_int_reg(context, info->FrameRegister) - info->FrameOffset * 16;

        /* check if in prolog */
516 517
        if (context->Rip >= base + function->BeginAddress &&
            context->Rip < base + function->BeginAddress + info->SizeOfProlog)
518
        {
519
            prolog_offset = context->Rip - base - function->BeginAddress;
520 521 522 523
        }
        else
        {
            prolog_offset = ~0;
524
            if (is_inside_epilog(csw, context->Rip, base, function))
525
            {
526
                interpret_epilog(csw, context->Rip, context);
527 528 529 530 531 532
                return TRUE;
            }
        }

        for (i = 0; i < info->CountOfCodes; i += get_opcode_size(info->UnwindCode[i]))
        {
533
            if (prolog_offset < info->UnwindCode[i].u.CodeOffset) continue; /* skip it */
534

535
            switch (info->UnwindCode[i].u.UnwindOp)
536 537 538
            {
            case UWOP_PUSH_NONVOL:  /* pushq %reg */
                if (!sw_read_mem(csw, context->Rsp, &value, sizeof(DWORD64))) return FALSE;
539
                set_int_reg(context, info->UnwindCode[i].u.OpInfo, value);
540 541 542
                context->Rsp += sizeof(ULONG64);
                break;
            case UWOP_ALLOC_LARGE:  /* subq $nn,%rsp */
543
                if (info->UnwindCode[i].u.OpInfo) context->Rsp += *(DWORD*)&info->UnwindCode[i+1];
544 545 546
                else context->Rsp += *(USHORT*)&info->UnwindCode[i+1] * 8;
                break;
            case UWOP_ALLOC_SMALL:  /* subq $n,%rsp */
547
                context->Rsp += (info->UnwindCode[i].u.OpInfo + 1) * 8;
548 549 550 551 552 553
                break;
            case UWOP_SET_FPREG:  /* leaq nn(%rsp),%framereg */
                context->Rsp = newframe;
                break;
            case UWOP_SAVE_NONVOL:  /* movq %reg,n(%rsp) */
                off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 8;
554
                if (!sw_read_mem(csw, off, &value, sizeof(DWORD64))) return FALSE;
555
                set_int_reg(context, info->UnwindCode[i].u.OpInfo, value);
556 557 558
                break;
            case UWOP_SAVE_NONVOL_FAR:  /* movq %reg,nn(%rsp) */
                off = newframe + *(DWORD*)&info->UnwindCode[i+1];
559
                if (!sw_read_mem(csw, off, &value, sizeof(DWORD64))) return FALSE;
560
                set_int_reg(context, info->UnwindCode[i].u.OpInfo, value);
561 562 563
                break;
            case UWOP_SAVE_XMM128:  /* movaps %xmmreg,n(%rsp) */
                off = newframe + *(USHORT*)&info->UnwindCode[i+1] * 16;
564
                if (!sw_read_mem(csw, off, &floatvalue, sizeof(M128A))) return FALSE;
565
                set_float_reg(context, info->UnwindCode[i].u.OpInfo, floatvalue);
566 567 568
                break;
            case UWOP_SAVE_XMM128_FAR:  /* movaps %xmmreg,nn(%rsp) */
                off = newframe + *(DWORD*)&info->UnwindCode[i+1];
569
                if (!sw_read_mem(csw, off, &floatvalue, sizeof(M128A))) return FALSE;
570
                set_float_reg(context, info->UnwindCode[i].u.OpInfo, floatvalue);
571 572
                break;
            case UWOP_PUSH_MACHFRAME:
573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589
                if (info->Flags & UNW_FLAG_CHAININFO)
                {
                    FIXME("PUSH_MACHFRAME with chained unwind info.\n");
                    break;
                }
                if (i + get_opcode_size(info->UnwindCode[i]) < info->CountOfCodes)
                {
                    FIXME("PUSH_MACHFRAME is not the last opcode.\n");
                    break;
                }

                if (info->UnwindCode[i].u.OpInfo)
                    context->Rsp += 0x8;

                if (!sw_read_mem(csw, context->Rsp, &context->Rip, sizeof(DWORD64))) return FALSE;
                if (!sw_read_mem(csw, context->Rsp + 24, &context->Rsp, sizeof(DWORD64))) return FALSE;
                mach_frame = TRUE;
590 591
                break;
            default:
592
                FIXME("unknown code %u\n", info->UnwindCode[i].u.UnwindOp);
593 594 595 596 597 598 599 600 601
                break;
            }
        }
        if (!(info->Flags & UNW_FLAG_CHAININFO)) break;
        if (!sw_read_mem(csw, base + function->UnwindData + FIELD_OFFSET(UNWIND_INFO, UnwindCode) +
                                   ((info->CountOfCodes + 1) & ~1) * sizeof(UNWIND_CODE),
                         &handler_data, sizeof(handler_data))) return FALSE;
        function = &handler_data.chain;  /* restart with the chained info */
    }
602
    return mach_frame ? TRUE : default_unwind(csw, context);
603 604
}

605 606 607 608 609
/* fetch_next_frame()
 *
 * modify (at least) context.{rip, rsp, rbp} using unwind information
 * either out of PE exception handlers, debug info (dwarf), or simple stack unwind
 */
610
static BOOL fetch_next_frame(struct cpu_stack_walk *csw, union ctx *pcontext,
611 612
                             DWORD_PTR curr_pc, void** prtf)
{
613
    DWORD64 cfa;
614 615
    RUNTIME_FUNCTION*       rtf;
    DWORD64                 base;
616
    CONTEXT *context = &pcontext->ctx;
617 618 619 620 621 622 623 624

    if (!curr_pc || !(base = sw_module_base(csw, curr_pc))) return FALSE;
    rtf = sw_table_access(csw, curr_pc);
    if (prtf) *prtf = rtf;
    if (rtf)
    {
        return interpret_function_table_entry(csw, context, rtf, base);
    }
625
    else if (dwarf2_virtual_unwind(csw, curr_pc, pcontext, &cfa))
626 627
    {
        context->Rsp = cfa;
628 629
        TRACE("next function rip=%016Ix\n", context->Rip);
        TRACE("  rax=%016Ix rbx=%016Ix rcx=%016Ix rdx=%016Ix\n",
630
              context->Rax, context->Rbx, context->Rcx, context->Rdx);
631
        TRACE("  rsi=%016Ix rdi=%016Ix rbp=%016Ix rsp=%016Ix\n",
632
              context->Rsi, context->Rdi, context->Rbp, context->Rsp);
633
        TRACE("   r8=%016Ix  r9=%016Ix r10=%016Ix r11=%016Ix\n",
634
              context->R8, context->R9, context->R10, context->R11);
635
        TRACE("  r12=%016Ix r13=%016Ix r14=%016Ix r15=%016Ix\n",
636 637 638 639 640 641 642
              context->R12, context->R13, context->R14, context->R15);
        return TRUE;
    }
    else
        return default_unwind(csw, context);
}

643 644
static BOOL x86_64_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame,
    union ctx *context)
645
{
646
    unsigned    deltapc = curr_count <= 1 ? 0 : 1;
647

648 649 650 651
    /* sanity check */
    if (curr_mode >= stm_done) return FALSE;
    assert(!csw->is32);

652
    TRACE("Enter: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s\n",
653 654 655 656
          wine_dbgstr_addr(&frame->AddrPC),
          wine_dbgstr_addr(&frame->AddrFrame),
          wine_dbgstr_addr(&frame->AddrReturn),
          wine_dbgstr_addr(&frame->AddrStack),
657 658
          curr_mode == stm_start ? "start" : "64bit",
          wine_dbgstr_longlong(curr_count));
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678

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

        /* Init done */
        curr_mode = stm_64bit;
        frame->AddrReturn.Mode = frame->AddrStack.Mode = AddrModeFlat;
        /* don't set up AddrStack on first call. Either the caller has set it up, or
         * we will get it in the next frame
         */
        memset(&frame->AddrBStore, 0, sizeof(frame->AddrBStore));
    }
    else
    {
679 680
        if (context->ctx.Rsp != frame->AddrStack.Offset) FIXME("inconsistent Stack Pointer\n");
        if (context->ctx.Rip != frame->AddrPC.Offset) FIXME("inconsistent Instruction Pointer\n");
681

682
        if (frame->AddrReturn.Offset == 0) goto done_err;
683
        if (!fetch_next_frame(csw, context, frame->AddrPC.Offset - deltapc, &frame->FuncTableEntry))
684
            goto done_err;
685
        deltapc = 1;
686
    }
687

688 689
    memset(&frame->Params, 0, sizeof(frame->Params));

690
    /* set frame information */
691 692 693
    frame->AddrStack.Offset = context->ctx.Rsp;
    frame->AddrFrame.Offset = context->ctx.Rbp;
    frame->AddrPC.Offset = context->ctx.Rip;
694 695
    if (1)
    {
696
        union ctx newctx = *context;
697 698 699 700

        if (!fetch_next_frame(csw, &newctx, frame->AddrPC.Offset - deltapc, NULL))
            goto done_err;
        frame->AddrReturn.Mode = AddrModeFlat;
701
        frame->AddrReturn.Offset = newctx.ctx.Rip;
702
    }
703

704 705
    frame->Far = TRUE;
    frame->Virtual = TRUE;
706
    curr_count++;
707

708
    TRACE("Leave: PC=%s Frame=%s Return=%s Stack=%s Mode=%s Count=%s FuncTable=%p\n",
709 710 711 712 713
          wine_dbgstr_addr(&frame->AddrPC),
          wine_dbgstr_addr(&frame->AddrFrame),
          wine_dbgstr_addr(&frame->AddrReturn),
          wine_dbgstr_addr(&frame->AddrStack),
          curr_mode == stm_start ? "start" : "64bit",
714
          wine_dbgstr_longlong(curr_count),
715 716 717 718 719 720 721
          frame->FuncTableEntry);

    return TRUE;
done_err:
    curr_mode = stm_done;
    return FALSE;
}
722
#else
723 724
static BOOL x86_64_stack_walk(struct cpu_stack_walk *csw, STACKFRAME64 *frame,
    union ctx *ctx)
725 726 727 728
{
    return FALSE;
}
#endif
729

730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
static void*    x86_64_find_runtime_function(struct module* module, DWORD64 addr)
{
#ifdef __x86_64__
    RUNTIME_FUNCTION*   rtf;
    ULONG               size;
    int                 min, max;

    rtf = (RUNTIME_FUNCTION*)pe_map_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size);
    if (rtf) for (min = 0, max = size / sizeof(*rtf); min <= max; )
    {
        int pos = (min + max) / 2;
        if (addr < module->module.BaseOfImage + rtf[pos].BeginAddress) max = pos - 1;
        else if (addr >= module->module.BaseOfImage + rtf[pos].EndAddress) min = pos + 1;
        else
        {
            rtf += pos;
            while (rtf->UnwindData & 1)  /* follow chained entry */
            {
                FIXME("RunTime_Function outside IMAGE_DIRECTORY_ENTRY_EXCEPTION unimplemented yet!\n");
749
                return NULL;
750 751 752 753 754 755 756 757 758 759
                /* we need to read into the other process */
                /* rtf = (RUNTIME_FUNCTION*)(module->module.BaseOfImage + (rtf->UnwindData & ~1)); */
            }
            return rtf;
        }
    }
#endif
    return NULL;
}

760
static unsigned x86_64_map_dwarf_register(unsigned regno, const struct module* module, BOOL eh_frame)
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
{
    unsigned    reg;

    if (regno >= 17 && regno <= 24)
        reg = CV_AMD64_XMM0 + regno - 17;
    else if (regno >= 25 && regno <= 32)
        reg = CV_AMD64_XMM8 + regno - 25;
    else if (regno >= 33 && regno <= 40)
        reg = CV_AMD64_ST0 + regno - 33;
    else switch (regno)
    {
    case  0: reg = CV_AMD64_RAX;    break;
    case  1: reg = CV_AMD64_RDX;    break;
    case  2: reg = CV_AMD64_RCX;    break;
    case  3: reg = CV_AMD64_RBX;    break;
    case  4: reg = CV_AMD64_RSI;    break;
    case  5: reg = CV_AMD64_RDI;    break;
    case  6: reg = CV_AMD64_RBP;    break;
    case  7: reg = CV_AMD64_RSP;    break;
    case  8: reg = CV_AMD64_R8;     break;
    case  9: reg = CV_AMD64_R9;     break;
    case 10: reg = CV_AMD64_R10;    break;
    case 11: reg = CV_AMD64_R11;    break;
    case 12: reg = CV_AMD64_R12;    break;
    case 13: reg = CV_AMD64_R13;    break;
    case 14: reg = CV_AMD64_R14;    break;
    case 15: reg = CV_AMD64_R15;    break;
    case 16: reg = CV_AMD64_RIP;    break;
    case 49: reg = CV_AMD64_EFLAGS; break;
    case 50: reg = CV_AMD64_ES;     break;
    case 51: reg = CV_AMD64_CS;     break;
    case 52: reg = CV_AMD64_SS;     break;
    case 53: reg = CV_AMD64_DS;     break;
    case 54: reg = CV_AMD64_FS;     break;
    case 55: reg = CV_AMD64_GS;     break;
    case 62: reg = CV_AMD64_TR;     break;
    case 63: reg = CV_AMD64_LDTR;   break;
    case 64: reg = CV_AMD64_MXCSR;  break;
    case 65: reg = CV_AMD64_CTRL;   break;
    case 66: reg = CV_AMD64_STAT;   break;
/*
 * 56-57 reserved
 * 58 %fs.base
 * 59 %gs.base
 * 60-61 reserved
 */
    default:
        FIXME("Don't know how to map register %d\n", regno);
        return 0;
    }
    return reg;
}

814
static void *x86_64_fetch_context_reg(union ctx *pctx, unsigned regno, unsigned *size)
815 816
{
#ifdef __x86_64__
817 818
    CONTEXT *ctx = &pctx->ctx;

819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
    switch (regno)
    {
    case CV_AMD64_RAX: *size = sizeof(ctx->Rax); return &ctx->Rax;
    case CV_AMD64_RDX: *size = sizeof(ctx->Rdx); return &ctx->Rdx;
    case CV_AMD64_RCX: *size = sizeof(ctx->Rcx); return &ctx->Rcx;
    case CV_AMD64_RBX: *size = sizeof(ctx->Rbx); return &ctx->Rbx;
    case CV_AMD64_RSI: *size = sizeof(ctx->Rsi); return &ctx->Rsi;
    case CV_AMD64_RDI: *size = sizeof(ctx->Rdi); return &ctx->Rdi;
    case CV_AMD64_RBP: *size = sizeof(ctx->Rbp); return &ctx->Rbp;
    case CV_AMD64_RSP: *size = sizeof(ctx->Rsp); return &ctx->Rsp;
    case CV_AMD64_R8:  *size = sizeof(ctx->R8);  return &ctx->R8;
    case CV_AMD64_R9:  *size = sizeof(ctx->R9);  return &ctx->R9;
    case CV_AMD64_R10: *size = sizeof(ctx->R10); return &ctx->R10;
    case CV_AMD64_R11: *size = sizeof(ctx->R11); return &ctx->R11;
    case CV_AMD64_R12: *size = sizeof(ctx->R12); return &ctx->R12;
    case CV_AMD64_R13: *size = sizeof(ctx->R13); return &ctx->R13;
    case CV_AMD64_R14: *size = sizeof(ctx->R14); return &ctx->R14;
    case CV_AMD64_R15: *size = sizeof(ctx->R15); return &ctx->R15;
    case CV_AMD64_RIP: *size = sizeof(ctx->Rip); return &ctx->Rip;

    case CV_AMD64_XMM0 + 0: *size = sizeof(ctx->u.s.Xmm0 ); return &ctx->u.s.Xmm0;
    case CV_AMD64_XMM0 + 1: *size = sizeof(ctx->u.s.Xmm1 ); return &ctx->u.s.Xmm1;
    case CV_AMD64_XMM0 + 2: *size = sizeof(ctx->u.s.Xmm2 ); return &ctx->u.s.Xmm2;
    case CV_AMD64_XMM0 + 3: *size = sizeof(ctx->u.s.Xmm3 ); return &ctx->u.s.Xmm3;
    case CV_AMD64_XMM0 + 4: *size = sizeof(ctx->u.s.Xmm4 ); return &ctx->u.s.Xmm4;
    case CV_AMD64_XMM0 + 5: *size = sizeof(ctx->u.s.Xmm5 ); return &ctx->u.s.Xmm5;
    case CV_AMD64_XMM0 + 6: *size = sizeof(ctx->u.s.Xmm6 ); return &ctx->u.s.Xmm6;
    case CV_AMD64_XMM0 + 7: *size = sizeof(ctx->u.s.Xmm7 ); return &ctx->u.s.Xmm7;
    case CV_AMD64_XMM8 + 0: *size = sizeof(ctx->u.s.Xmm8 ); return &ctx->u.s.Xmm8;
    case CV_AMD64_XMM8 + 1: *size = sizeof(ctx->u.s.Xmm9 ); return &ctx->u.s.Xmm9;
    case CV_AMD64_XMM8 + 2: *size = sizeof(ctx->u.s.Xmm10); return &ctx->u.s.Xmm10;
    case CV_AMD64_XMM8 + 3: *size = sizeof(ctx->u.s.Xmm11); return &ctx->u.s.Xmm11;
    case CV_AMD64_XMM8 + 4: *size = sizeof(ctx->u.s.Xmm12); return &ctx->u.s.Xmm12;
    case CV_AMD64_XMM8 + 5: *size = sizeof(ctx->u.s.Xmm13); return &ctx->u.s.Xmm13;
    case CV_AMD64_XMM8 + 6: *size = sizeof(ctx->u.s.Xmm14); return &ctx->u.s.Xmm14;
    case CV_AMD64_XMM8 + 7: *size = sizeof(ctx->u.s.Xmm15); return &ctx->u.s.Xmm15;

    case CV_AMD64_ST0 + 0: *size = sizeof(ctx->u.s.Legacy[0]); return &ctx->u.s.Legacy[0];
    case CV_AMD64_ST0 + 1: *size = sizeof(ctx->u.s.Legacy[1]); return &ctx->u.s.Legacy[1];
    case CV_AMD64_ST0 + 2: *size = sizeof(ctx->u.s.Legacy[2]); return &ctx->u.s.Legacy[2];
    case CV_AMD64_ST0 + 3: *size = sizeof(ctx->u.s.Legacy[3]); return &ctx->u.s.Legacy[3];
    case CV_AMD64_ST0 + 4: *size = sizeof(ctx->u.s.Legacy[4]); return &ctx->u.s.Legacy[4];
    case CV_AMD64_ST0 + 5: *size = sizeof(ctx->u.s.Legacy[5]); return &ctx->u.s.Legacy[5];
    case CV_AMD64_ST0 + 6: *size = sizeof(ctx->u.s.Legacy[6]); return &ctx->u.s.Legacy[6];
    case CV_AMD64_ST0 + 7: *size = sizeof(ctx->u.s.Legacy[7]); return &ctx->u.s.Legacy[7];

    case CV_AMD64_EFLAGS: *size = sizeof(ctx->EFlags); return &ctx->EFlags;
    case CV_AMD64_ES: *size = sizeof(ctx->SegEs); return &ctx->SegEs;
    case CV_AMD64_CS: *size = sizeof(ctx->SegCs); return &ctx->SegCs;
    case CV_AMD64_SS: *size = sizeof(ctx->SegSs); return &ctx->SegSs;
    case CV_AMD64_DS: *size = sizeof(ctx->SegDs); return &ctx->SegDs;
    case CV_AMD64_FS: *size = sizeof(ctx->SegFs); return &ctx->SegFs;
    case CV_AMD64_GS: *size = sizeof(ctx->SegGs); return &ctx->SegGs;

    }
#endif
    FIXME("Unknown register %x\n", regno);
    return NULL;
}

static const char* x86_64_fetch_regname(unsigned regno)
{
    switch (regno)
    {
    case CV_AMD64_RAX:          return "rax";
    case CV_AMD64_RDX:          return "rdx";
    case CV_AMD64_RCX:          return "rcx";
    case CV_AMD64_RBX:          return "rbx";
    case CV_AMD64_RSI:          return "rsi";
    case CV_AMD64_RDI:          return "rdi";
    case CV_AMD64_RBP:          return "rbp";
    case CV_AMD64_RSP:          return "rsp";
    case CV_AMD64_R8:           return "r8";
    case CV_AMD64_R9:           return "r9";
    case CV_AMD64_R10:          return "r10";
    case CV_AMD64_R11:          return "r11";
    case CV_AMD64_R12:          return "r12";
    case CV_AMD64_R13:          return "r13";
    case CV_AMD64_R14:          return "r14";
    case CV_AMD64_R15:          return "r15";
    case CV_AMD64_RIP:          return "rip";

    case CV_AMD64_XMM0 + 0:     return "xmm0";
    case CV_AMD64_XMM0 + 1:     return "xmm1";
    case CV_AMD64_XMM0 + 2:     return "xmm2";
    case CV_AMD64_XMM0 + 3:     return "xmm3";
    case CV_AMD64_XMM0 + 4:     return "xmm4";
    case CV_AMD64_XMM0 + 5:     return "xmm5";
    case CV_AMD64_XMM0 + 6:     return "xmm6";
    case CV_AMD64_XMM0 + 7:     return "xmm7";
    case CV_AMD64_XMM8 + 0:     return "xmm8";
    case CV_AMD64_XMM8 + 1:     return "xmm9";
    case CV_AMD64_XMM8 + 2:     return "xmm10";
    case CV_AMD64_XMM8 + 3:     return "xmm11";
    case CV_AMD64_XMM8 + 4:     return "xmm12";
    case CV_AMD64_XMM8 + 5:     return "xmm13";
    case CV_AMD64_XMM8 + 6:     return "xmm14";
    case CV_AMD64_XMM8 + 7:     return "xmm15";

    case CV_AMD64_ST0 + 0:      return "st0";
    case CV_AMD64_ST0 + 1:      return "st1";
    case CV_AMD64_ST0 + 2:      return "st2";
    case CV_AMD64_ST0 + 3:      return "st3";
    case CV_AMD64_ST0 + 4:      return "st4";
    case CV_AMD64_ST0 + 5:      return "st5";
    case CV_AMD64_ST0 + 6:      return "st6";
    case CV_AMD64_ST0 + 7:      return "st7";

    case CV_AMD64_EFLAGS:       return "eflags";
    case CV_AMD64_ES:           return "es";
    case CV_AMD64_CS:           return "cs";
    case CV_AMD64_SS:           return "ss";
    case CV_AMD64_DS:           return "ds";
    case CV_AMD64_FS:           return "fs";
    case CV_AMD64_GS:           return "gs";
    }
    FIXME("Unknown register %x\n", regno);
    return NULL;
}
938

939 940 941 942 943 944 945 946 947 948 949 950 951 952
static BOOL x86_64_fetch_minidump_thread(struct dump_context* dc, unsigned index, unsigned flags, const CONTEXT* ctx)
{
    if (ctx->ContextFlags && (flags & ThreadWriteInstructionWindow))
    {
        /* FIXME: crop values across module boundaries, */
#ifdef __x86_64__
        ULONG64 base = ctx->Rip <= 0x80 ? 0 : ctx->Rip - 0x80;
        minidump_add_memory_block(dc, base, ctx->Rip + 0x80 - base, 0);
#endif
    }

    return TRUE;
}

953 954 955 956 957 958 959 960 961 962 963 964
static BOOL x86_64_fetch_minidump_module(struct dump_context* dc, unsigned index, unsigned flags)
{
    /* FIXME: not sure about the flags... */
    if (1)
    {
        /* FIXME: crop values across module boundaries, */
#ifdef __x86_64__
        struct process*         pcs;
        struct module*          module;
        const RUNTIME_FUNCTION* rtf;
        ULONG                   size;

965
        if (!(pcs = process_find_by_handle(dc->process->handle)) ||
966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
            !(module = module_find_by_addr(pcs, dc->modules[index].base, DMT_UNKNOWN)))
            return FALSE;
        rtf = (const RUNTIME_FUNCTION*)pe_map_directory(module, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size);
        if (rtf)
        {
            const RUNTIME_FUNCTION* end = (const RUNTIME_FUNCTION*)((const char*)rtf + size);
            UNWIND_INFO ui;

            while (rtf + 1 < end)
            {
                while (rtf->UnwindData & 1)  /* follow chained entry */
                {
                    FIXME("RunTime_Function outside IMAGE_DIRECTORY_ENTRY_EXCEPTION unimplemented yet!\n");
                    return FALSE;
                    /* we need to read into the other process */
                    /* rtf = (RUNTIME_FUNCTION*)(module->module.BaseOfImage + (rtf->UnwindData & ~1)); */
                }
983
                if (read_process_memory(dc->process, dc->modules[index].base + rtf->UnwindData, &ui, sizeof(ui)))
984 985 986 987 988 989 990 991 992 993 994
                    minidump_add_memory_block(dc, dc->modules[index].base + rtf->UnwindData,
                                              FIELD_OFFSET(UNWIND_INFO, UnwindCode) + ui.CountOfCodes * sizeof(UNWIND_CODE), 0);
                rtf++;
            }
        }
#endif
    }

    return TRUE;
}

995
DECLSPEC_HIDDEN struct cpu cpu_x86_64 = {
996
    IMAGE_FILE_MACHINE_AMD64,
997
    8,
998
    CV_AMD64_RSP,
999
    x86_64_get_addr,
1000
    x86_64_stack_walk,
1001
    x86_64_find_runtime_function,
1002
    x86_64_map_dwarf_register,
1003 1004
    x86_64_fetch_context_reg,
    x86_64_fetch_regname,
1005
    x86_64_fetch_minidump_thread,
1006
    x86_64_fetch_minidump_module,
1007
};