1 /* 2 * File symbol.c - management of symbols (lexical tree) 3 * 4 * Copyright (C) 1993, Eric Youngdale. 5 * 2004, Eric Pouech 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 */ 21 22 #define NONAMELESSUNION 23 24 #include "config.h" 25 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <limits.h> 30 #include <sys/types.h> 31 #include <assert.h> 32 #ifndef DBGHELP_STATIC_LIB 33 #include "wine/debug.h" 34 #endif 35 #include "dbghelp_private.h" 36 #ifndef DBGHELP_STATIC_LIB 37 #include "winnls.h" 38 #endif 39 40 WINE_DEFAULT_DEBUG_CHANNEL(dbghelp); 41 WINE_DECLARE_DEBUG_CHANNEL(dbghelp_symt); 42 43 static const WCHAR starW[] = {'*','\0'}; 44 45 static inline int cmp_addr(ULONG64 a1, ULONG64 a2) 46 { 47 if (a1 > a2) return 1; 48 if (a1 < a2) return -1; 49 return 0; 50 } 51 52 static inline int cmp_sorttab_addr(struct module* module, int idx, ULONG64 addr) 53 { 54 ULONG64 ref; 55 symt_get_address(&module->addr_sorttab[idx]->symt, &ref); 56 return cmp_addr(ref, addr); 57 } 58 59 int symt_cmp_addr(const void* p1, const void* p2) 60 { 61 const struct symt* sym1 = *(const struct symt* const *)p1; 62 const struct symt* sym2 = *(const struct symt* const *)p2; 63 ULONG64 a1, a2; 64 65 symt_get_address(sym1, &a1); 66 symt_get_address(sym2, &a2); 67 return cmp_addr(a1, a2); 68 } 69 70 DWORD symt_ptr2index(struct module* module, const struct symt* sym) 71 { 72 #ifdef __x86_64__ 73 const struct symt** c; 74 int len = vector_length(&module->vsymt); 75 struct hash_table_iter hti; 76 void *ptr; 77 struct symt_idx_to_ptr *idx_to_ptr; 78 /* place enough storage on the stack to represent a pointer in %p form */ 79 char ptrbuf[3 + (sizeof(void *) * 2)]; 80 81 /* make a string representation of the pointer to use as a hash key */ 82 sprintf(ptrbuf, "%p", sym); 83 hash_table_iter_init(&module->ht_symaddr, &hti, ptrbuf); 84 85 /* try to find the pointer in our ht */ 86 while ((ptr = hash_table_iter_up(&hti))) { 87 idx_to_ptr = CONTAINING_RECORD(ptr, struct symt_idx_to_ptr, hash_elt); 88 if (idx_to_ptr->sym == sym) 89 return idx_to_ptr->idx; 90 } 91 92 /* not found */ 93 /* add the symbol to our symbol vector */ 94 c = vector_add(&module->vsymt, &module->pool); 95 96 /* add an idx to ptr mapping so we can find it again by address */ 97 if ((idx_to_ptr = pool_alloc(&module->pool, sizeof(*idx_to_ptr)))) 98 { 99 idx_to_ptr->hash_elt.name = pool_strdup(&module->pool, ptrbuf); 100 idx_to_ptr->sym = sym; 101 idx_to_ptr->idx = len + 1; 102 hash_table_add(&module->ht_symaddr, &idx_to_ptr->hash_elt); 103 } 104 105 if (c) *c = sym; 106 return len + 1; 107 #else 108 return (DWORD)sym; 109 #endif 110 } 111 112 struct symt* symt_index2ptr(struct module* module, DWORD id) 113 { 114 #ifdef __x86_64__ 115 if (!id-- || id >= vector_length(&module->vsymt)) return NULL; 116 return *(struct symt**)vector_at(&module->vsymt, id); 117 #else 118 return (struct symt*)id; 119 #endif 120 } 121 122 static BOOL symt_grow_sorttab(struct module* module, unsigned sz) 123 { 124 struct symt_ht** new; 125 unsigned int size; 126 127 if (sz <= module->sorttab_size) return TRUE; 128 if (module->addr_sorttab) 129 { 130 size = module->sorttab_size * 2; 131 new = HeapReAlloc(GetProcessHeap(), 0, module->addr_sorttab, 132 size * sizeof(struct symt_ht*)); 133 } 134 else 135 { 136 size = 64; 137 new = HeapAlloc(GetProcessHeap(), 0, size * sizeof(struct symt_ht*)); 138 } 139 if (!new) return FALSE; 140 module->sorttab_size = size; 141 module->addr_sorttab = new; 142 return TRUE; 143 } 144 145 static void symt_add_module_ht(struct module* module, struct symt_ht* ht) 146 { 147 ULONG64 addr; 148 149 hash_table_add(&module->ht_symbols, &ht->hash_elt); 150 /* Don't store in sorttab a symbol without address, they are of 151 * no use here (e.g. constant values) 152 */ 153 if (symt_get_address(&ht->symt, &addr) && 154 symt_grow_sorttab(module, module->num_symbols + 1)) 155 { 156 module->addr_sorttab[module->num_symbols++] = ht; 157 module->sortlist_valid = FALSE; 158 } 159 } 160 161 static WCHAR* file_regex(const char* srcfile) 162 { 163 WCHAR* mask; 164 WCHAR* p; 165 166 if (!srcfile || !*srcfile) 167 { 168 if (!(p = mask = HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(WCHAR)))) return NULL; 169 *p++ = '?'; 170 *p++ = '#'; 171 } 172 else 173 { 174 DWORD sz = MultiByteToWideChar(CP_ACP, 0, srcfile, -1, NULL, 0); 175 WCHAR* srcfileW; 176 177 /* FIXME: we use here the largest conversion for every char... could be optimized */ 178 p = mask = HeapAlloc(GetProcessHeap(), 0, (5 * strlen(srcfile) + 1 + sz) * sizeof(WCHAR)); 179 if (!mask) return NULL; 180 srcfileW = mask + 5 * strlen(srcfile) + 1; 181 MultiByteToWideChar(CP_ACP, 0, srcfile, -1, srcfileW, sz); 182 183 while (*srcfileW) 184 { 185 switch (*srcfileW) 186 { 187 case '\\': 188 case '/': 189 *p++ = '['; 190 *p++ = '\\'; 191 *p++ = '\\'; 192 *p++ = '/'; 193 *p++ = ']'; 194 break; 195 case '.': 196 *p++ = '?'; 197 break; 198 default: 199 *p++ = *srcfileW; 200 break; 201 } 202 srcfileW++; 203 } 204 } 205 *p = 0; 206 return mask; 207 } 208 209 struct symt_compiland* symt_new_compiland(struct module* module, 210 unsigned long address, unsigned src_idx) 211 { 212 struct symt_compiland* sym; 213 214 TRACE_(dbghelp_symt)("Adding compiland symbol %s:%s\n", 215 debugstr_w(module->module.ModuleName), source_get(module, src_idx)); 216 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 217 { 218 sym->symt.tag = SymTagCompiland; 219 sym->address = address; 220 sym->source = src_idx; 221 vector_init(&sym->vchildren, sizeof(struct symt*), 32); 222 } 223 return sym; 224 } 225 226 struct symt_public* symt_new_public(struct module* module, 227 struct symt_compiland* compiland, 228 const char* name, 229 BOOL is_function, 230 unsigned long address, unsigned size) 231 { 232 struct symt_public* sym; 233 struct symt** p; 234 235 TRACE_(dbghelp_symt)("Adding public symbol %s:%s @%lx\n", 236 debugstr_w(module->module.ModuleName), name, address); 237 if ((dbghelp_options & SYMOPT_AUTO_PUBLICS) && 238 symt_find_nearest(module, address) != NULL) 239 return NULL; 240 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 241 { 242 sym->symt.tag = SymTagPublicSymbol; 243 sym->hash_elt.name = pool_strdup(&module->pool, name); 244 sym->container = compiland ? &compiland->symt : NULL; 245 sym->is_function = is_function; 246 sym->address = address; 247 sym->size = size; 248 symt_add_module_ht(module, (struct symt_ht*)sym); 249 if (compiland) 250 { 251 p = vector_add(&compiland->vchildren, &module->pool); 252 *p = &sym->symt; 253 } 254 } 255 return sym; 256 } 257 258 struct symt_data* symt_new_global_variable(struct module* module, 259 struct symt_compiland* compiland, 260 const char* name, unsigned is_static, 261 struct location loc, unsigned long size, 262 struct symt* type) 263 { 264 struct symt_data* sym; 265 struct symt** p; 266 DWORD64 tsz; 267 268 TRACE_(dbghelp_symt)("Adding global symbol %s:%s %d@%lx %p\n", 269 debugstr_w(module->module.ModuleName), name, loc.kind, loc.offset, type); 270 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 271 { 272 sym->symt.tag = SymTagData; 273 sym->hash_elt.name = pool_strdup(&module->pool, name); 274 sym->kind = is_static ? DataIsFileStatic : DataIsGlobal; 275 sym->container = compiland ? &compiland->symt : NULL; 276 sym->type = type; 277 sym->u.var = loc; 278 if (type && size && symt_get_info(module, type, TI_GET_LENGTH, &tsz)) 279 { 280 if (tsz != size) 281 FIXME("Size mismatch for %s.%s between type (%s) and src (%lu)\n", 282 debugstr_w(module->module.ModuleName), name, 283 wine_dbgstr_longlong(tsz), size); 284 } 285 symt_add_module_ht(module, (struct symt_ht*)sym); 286 if (compiland) 287 { 288 p = vector_add(&compiland->vchildren, &module->pool); 289 *p = &sym->symt; 290 } 291 } 292 return sym; 293 } 294 295 struct symt_function* symt_new_function(struct module* module, 296 struct symt_compiland* compiland, 297 const char* name, 298 unsigned long addr, unsigned long size, 299 struct symt* sig_type) 300 { 301 struct symt_function* sym; 302 struct symt** p; 303 304 TRACE_(dbghelp_symt)("Adding global function %s:%s @%lx-%lx\n", 305 debugstr_w(module->module.ModuleName), name, addr, addr + size - 1); 306 307 assert(!sig_type || sig_type->tag == SymTagFunctionType); 308 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 309 { 310 sym->symt.tag = SymTagFunction; 311 sym->hash_elt.name = pool_strdup(&module->pool, name); 312 sym->container = &compiland->symt; 313 sym->address = addr; 314 sym->type = sig_type; 315 sym->size = size; 316 vector_init(&sym->vlines, sizeof(struct line_info), 64); 317 vector_init(&sym->vchildren, sizeof(struct symt*), 8); 318 symt_add_module_ht(module, (struct symt_ht*)sym); 319 if (compiland) 320 { 321 p = vector_add(&compiland->vchildren, &module->pool); 322 *p = &sym->symt; 323 } 324 } 325 return sym; 326 } 327 328 void symt_add_func_line(struct module* module, struct symt_function* func, 329 unsigned source_idx, int line_num, unsigned long offset) 330 { 331 struct line_info* dli; 332 BOOL last_matches = FALSE; 333 int i; 334 335 if (func == NULL || !(dbghelp_options & SYMOPT_LOAD_LINES)) return; 336 337 TRACE_(dbghelp_symt)("(%p)%s:%lx %s:%u\n", 338 func, func->hash_elt.name, offset, 339 source_get(module, source_idx), line_num); 340 341 assert(func->symt.tag == SymTagFunction); 342 343 for (i=vector_length(&func->vlines)-1; i>=0; i--) 344 { 345 dli = vector_at(&func->vlines, i); 346 if (dli->is_source_file) 347 { 348 last_matches = (source_idx == dli->u.source_file); 349 break; 350 } 351 } 352 353 if (!last_matches) 354 { 355 /* we shouldn't have line changes on first line of function */ 356 dli = vector_add(&func->vlines, &module->pool); 357 dli->is_source_file = 1; 358 dli->is_first = dli->is_last = 0; 359 dli->line_number = 0; 360 dli->u.source_file = source_idx; 361 } 362 dli = vector_add(&func->vlines, &module->pool); 363 dli->is_source_file = 0; 364 dli->is_first = dli->is_last = 0; 365 dli->line_number = line_num; 366 dli->u.pc_offset = func->address + offset; 367 } 368 369 /****************************************************************** 370 * symt_add_func_local 371 * 372 * Adds a new local/parameter to a given function: 373 * In any cases, dt tells whether it's a local variable or a parameter 374 * If regno it's not 0: 375 * - then variable is stored in a register 376 * - otherwise, value is referenced by register + offset 377 * Otherwise, the variable is stored on the stack: 378 * - offset is then the offset from the frame register 379 */ 380 struct symt_data* symt_add_func_local(struct module* module, 381 struct symt_function* func, 382 enum DataKind dt, 383 const struct location* loc, 384 struct symt_block* block, 385 struct symt* type, const char* name) 386 { 387 struct symt_data* locsym; 388 struct symt** p; 389 390 TRACE_(dbghelp_symt)("Adding local symbol (%s:%s): %s %p\n", 391 debugstr_w(module->module.ModuleName), func->hash_elt.name, 392 name, type); 393 394 assert(func); 395 assert(func->symt.tag == SymTagFunction); 396 assert(dt == DataIsParam || dt == DataIsLocal); 397 398 locsym = pool_alloc(&module->pool, sizeof(*locsym)); 399 locsym->symt.tag = SymTagData; 400 locsym->hash_elt.name = pool_strdup(&module->pool, name); 401 locsym->hash_elt.next = NULL; 402 locsym->kind = dt; 403 locsym->container = block ? &block->symt : &func->symt; 404 locsym->type = type; 405 locsym->u.var = *loc; 406 if (block) 407 p = vector_add(&block->vchildren, &module->pool); 408 else 409 p = vector_add(&func->vchildren, &module->pool); 410 *p = &locsym->symt; 411 return locsym; 412 } 413 414 415 struct symt_block* symt_open_func_block(struct module* module, 416 struct symt_function* func, 417 struct symt_block* parent_block, 418 unsigned pc, unsigned len) 419 { 420 struct symt_block* block; 421 struct symt** p; 422 423 assert(func); 424 assert(func->symt.tag == SymTagFunction); 425 426 assert(!parent_block || parent_block->symt.tag == SymTagBlock); 427 block = pool_alloc(&module->pool, sizeof(*block)); 428 block->symt.tag = SymTagBlock; 429 block->address = func->address + pc; 430 block->size = len; 431 block->container = parent_block ? &parent_block->symt : &func->symt; 432 vector_init(&block->vchildren, sizeof(struct symt*), 4); 433 if (parent_block) 434 p = vector_add(&parent_block->vchildren, &module->pool); 435 else 436 p = vector_add(&func->vchildren, &module->pool); 437 *p = &block->symt; 438 439 return block; 440 } 441 442 struct symt_block* symt_close_func_block(struct module* module, 443 const struct symt_function* func, 444 struct symt_block* block, unsigned pc) 445 { 446 assert(func); 447 assert(func->symt.tag == SymTagFunction); 448 449 if (pc) block->size = func->address + pc - block->address; 450 return (block->container->tag == SymTagBlock) ? 451 CONTAINING_RECORD(block->container, struct symt_block, symt) : NULL; 452 } 453 454 struct symt_hierarchy_point* symt_add_function_point(struct module* module, 455 struct symt_function* func, 456 enum SymTagEnum point, 457 const struct location* loc, 458 const char* name) 459 { 460 struct symt_hierarchy_point*sym; 461 struct symt** p; 462 463 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 464 { 465 sym->symt.tag = point; 466 sym->parent = &func->symt; 467 sym->loc = *loc; 468 sym->hash_elt.name = name ? pool_strdup(&module->pool, name) : NULL; 469 p = vector_add(&func->vchildren, &module->pool); 470 *p = &sym->symt; 471 } 472 return sym; 473 } 474 475 BOOL symt_normalize_function(struct module* module, const struct symt_function* func) 476 { 477 unsigned len; 478 struct line_info* dli; 479 480 assert(func); 481 /* We aren't adding any more locals or line numbers to this function. 482 * Free any spare memory that we might have allocated. 483 */ 484 assert(func->symt.tag == SymTagFunction); 485 486 /* EPP vector_pool_normalize(&func->vlines, &module->pool); */ 487 /* EPP vector_pool_normalize(&func->vchildren, &module->pool); */ 488 489 len = vector_length(&func->vlines); 490 if (len--) 491 { 492 dli = vector_at(&func->vlines, 0); dli->is_first = 1; 493 dli = vector_at(&func->vlines, len); dli->is_last = 1; 494 } 495 return TRUE; 496 } 497 498 struct symt_thunk* symt_new_thunk(struct module* module, 499 struct symt_compiland* compiland, 500 const char* name, THUNK_ORDINAL ord, 501 unsigned long addr, unsigned long size) 502 { 503 struct symt_thunk* sym; 504 505 TRACE_(dbghelp_symt)("Adding global thunk %s:%s @%lx-%lx\n", 506 debugstr_w(module->module.ModuleName), name, addr, addr + size - 1); 507 508 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 509 { 510 sym->symt.tag = SymTagThunk; 511 sym->hash_elt.name = pool_strdup(&module->pool, name); 512 sym->container = &compiland->symt; 513 sym->address = addr; 514 sym->size = size; 515 sym->ordinal = ord; 516 symt_add_module_ht(module, (struct symt_ht*)sym); 517 if (compiland) 518 { 519 struct symt** p; 520 p = vector_add(&compiland->vchildren, &module->pool); 521 *p = &sym->symt; 522 } 523 } 524 return sym; 525 } 526 527 struct symt_data* symt_new_constant(struct module* module, 528 struct symt_compiland* compiland, 529 const char* name, struct symt* type, 530 const VARIANT* v) 531 { 532 struct symt_data* sym; 533 534 TRACE_(dbghelp_symt)("Adding constant value %s:%s\n", 535 debugstr_w(module->module.ModuleName), name); 536 537 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 538 { 539 sym->symt.tag = SymTagData; 540 sym->hash_elt.name = pool_strdup(&module->pool, name); 541 sym->kind = DataIsConstant; 542 sym->container = compiland ? &compiland->symt : NULL; 543 sym->type = type; 544 sym->u.value = *v; 545 symt_add_module_ht(module, (struct symt_ht*)sym); 546 if (compiland) 547 { 548 struct symt** p; 549 p = vector_add(&compiland->vchildren, &module->pool); 550 *p = &sym->symt; 551 } 552 } 553 return sym; 554 } 555 556 struct symt_hierarchy_point* symt_new_label(struct module* module, 557 struct symt_compiland* compiland, 558 const char* name, unsigned long address) 559 { 560 struct symt_hierarchy_point* sym; 561 562 TRACE_(dbghelp_symt)("Adding global label value %s:%s\n", 563 debugstr_w(module->module.ModuleName), name); 564 565 if ((sym = pool_alloc(&module->pool, sizeof(*sym)))) 566 { 567 sym->symt.tag = SymTagLabel; 568 sym->hash_elt.name = pool_strdup(&module->pool, name); 569 sym->loc.kind = loc_absolute; 570 sym->loc.offset = address; 571 sym->parent = compiland ? &compiland->symt : NULL; 572 symt_add_module_ht(module, (struct symt_ht*)sym); 573 if (compiland) 574 { 575 struct symt** p; 576 p = vector_add(&compiland->vchildren, &module->pool); 577 *p = &sym->symt; 578 } 579 } 580 return sym; 581 } 582 583 /* expect sym_info->MaxNameLen to be set before being called */ 584 static void symt_fill_sym_info(struct module_pair* pair, 585 const struct symt_function* func, 586 const struct symt* sym, SYMBOL_INFO* sym_info) 587 { 588 const char* name; 589 DWORD64 size; 590 591 if (!symt_get_info(pair->effective, sym, TI_GET_TYPE, &sym_info->TypeIndex)) 592 sym_info->TypeIndex = 0; 593 sym_info->Index = symt_ptr2index(pair->effective, sym); 594 sym_info->Reserved[0] = sym_info->Reserved[1] = 0; 595 if (!symt_get_info(pair->effective, sym, TI_GET_LENGTH, &size) && 596 (!sym_info->TypeIndex || 597 !symt_get_info(pair->effective, symt_index2ptr(pair->effective, sym_info->TypeIndex), 598 TI_GET_LENGTH, &size))) 599 size = 0; 600 sym_info->Size = (DWORD)size; 601 sym_info->ModBase = pair->requested->module.BaseOfImage; 602 sym_info->Flags = 0; 603 sym_info->Value = 0; 604 605 switch (sym->tag) 606 { 607 case SymTagData: 608 { 609 const struct symt_data* data = (const struct symt_data*)sym; 610 switch (data->kind) 611 { 612 case DataIsParam: 613 sym_info->Flags |= SYMFLAG_PARAMETER; 614 /* fall through */ 615 case DataIsLocal: 616 sym_info->Flags |= SYMFLAG_LOCAL; 617 { 618 struct location loc = data->u.var; 619 620 if (loc.kind >= loc_user) 621 { 622 unsigned i; 623 struct module_format* modfmt; 624 625 for (i = 0; i < DFI_LAST; i++) 626 { 627 modfmt = pair->effective->format_info[i]; 628 if (modfmt && modfmt->loc_compute) 629 { 630 modfmt->loc_compute(pair->pcs, modfmt, func, &loc); 631 break; 632 } 633 } 634 } 635 switch (loc.kind) 636 { 637 case loc_error: 638 /* for now we report error cases as a negative register number */ 639 /* fall through */ 640 case loc_register: 641 sym_info->Flags |= SYMFLAG_REGISTER; 642 sym_info->Register = loc.reg; 643 sym_info->Address = 0; 644 break; 645 case loc_regrel: 646 sym_info->Flags |= SYMFLAG_REGREL; 647 sym_info->Register = loc.reg; 648 if (loc.reg == CV_REG_NONE || (int)loc.reg < 0 /* error */) 649 FIXME("suspicious register value %x\n", loc.reg); 650 sym_info->Address = loc.offset; 651 break; 652 case loc_absolute: 653 sym_info->Flags |= SYMFLAG_VALUEPRESENT; 654 sym_info->Value = loc.offset; 655 break; 656 default: 657 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", loc.kind); 658 assert(0); 659 } 660 } 661 break; 662 case DataIsGlobal: 663 case DataIsFileStatic: 664 switch (data->u.var.kind) 665 { 666 case loc_tlsrel: 667 sym_info->Flags |= SYMFLAG_TLSREL; 668 /* fall through */ 669 case loc_absolute: 670 symt_get_address(sym, &sym_info->Address); 671 sym_info->Register = 0; 672 break; 673 default: 674 FIXME("Shouldn't happen (kind=%d), debug reader backend is broken\n", data->u.var.kind); 675 assert(0); 676 } 677 break; 678 case DataIsConstant: 679 sym_info->Flags |= SYMFLAG_VALUEPRESENT; 680 switch (data->u.value.n1.n2.vt) 681 { 682 case VT_I4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.lVal; break; 683 case VT_I2: sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.iVal; break; 684 case VT_I1: sym_info->Value = (ULONG)(long)data->u.value.n1.n2.n3.cVal; break; 685 case VT_UI4: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.ulVal; break; 686 case VT_UI2: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.uiVal; break; 687 case VT_UI1: sym_info->Value = (ULONG)data->u.value.n1.n2.n3.bVal; break; 688 case VT_I1 | VT_BYREF: sym_info->Value = (ULONG64)(DWORD_PTR)data->u.value.n1.n2.n3.byref; break; 689 case VT_EMPTY: sym_info->Value = 0; break; 690 default: 691 FIXME("Unsupported variant type (%u)\n", data->u.value.n1.n2.vt); 692 sym_info->Value = 0; 693 break; 694 } 695 break; 696 default: 697 FIXME("Unhandled kind (%u) in sym data\n", data->kind); 698 } 699 } 700 break; 701 case SymTagPublicSymbol: 702 { 703 const struct symt_public* pub = (const struct symt_public*)sym; 704 if (pub->is_function) 705 sym_info->Flags |= SYMFLAG_PUBLIC_CODE; 706 else 707 sym_info->Flags |= SYMFLAG_EXPORT; 708 symt_get_address(sym, &sym_info->Address); 709 } 710 break; 711 case SymTagFunction: 712 symt_get_address(sym, &sym_info->Address); 713 break; 714 case SymTagThunk: 715 sym_info->Flags |= SYMFLAG_THUNK; 716 symt_get_address(sym, &sym_info->Address); 717 break; 718 default: 719 symt_get_address(sym, &sym_info->Address); 720 sym_info->Register = 0; 721 break; 722 } 723 sym_info->Scope = 0; /* FIXME */ 724 sym_info->Tag = sym->tag; 725 name = symt_get_name(sym); 726 if (sym_info->MaxNameLen) 727 { 728 if (sym->tag != SymTagPublicSymbol || !(dbghelp_options & SYMOPT_UNDNAME) || 729 ((sym_info->NameLen = UnDecorateSymbolName(name, sym_info->Name, 730 sym_info->MaxNameLen, UNDNAME_NAME_ONLY)) == 0)) 731 { 732 sym_info->NameLen = min(strlen(name), sym_info->MaxNameLen - 1); 733 memcpy(sym_info->Name, name, sym_info->NameLen); 734 sym_info->Name[sym_info->NameLen] = '\0'; 735 } 736 } 737 TRACE_(dbghelp_symt)("%p => %s %u %s\n", 738 sym, sym_info->Name, sym_info->Size, 739 wine_dbgstr_longlong(sym_info->Address)); 740 } 741 742 struct sym_enum 743 { 744 PSYM_ENUMERATESYMBOLS_CALLBACK cb; 745 PVOID user; 746 SYMBOL_INFO* sym_info; 747 DWORD index; 748 DWORD tag; 749 DWORD64 addr; 750 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 751 }; 752 753 static BOOL send_symbol(const struct sym_enum* se, struct module_pair* pair, 754 const struct symt_function* func, const struct symt* sym) 755 { 756 symt_fill_sym_info(pair, func, sym, se->sym_info); 757 if (se->index && se->sym_info->Index != se->index) return FALSE; 758 if (se->tag && se->sym_info->Tag != se->tag) return FALSE; 759 if (se->addr && !(se->addr >= se->sym_info->Address && se->addr < se->sym_info->Address + se->sym_info->Size)) return FALSE; 760 return !se->cb(se->sym_info, se->sym_info->Size, se->user); 761 } 762 763 static BOOL symt_enum_module(struct module_pair* pair, const WCHAR* match, 764 const struct sym_enum* se) 765 { 766 void* ptr; 767 struct symt_ht* sym = NULL; 768 struct hash_table_iter hti; 769 WCHAR* nameW; 770 BOOL ret; 771 772 hash_table_iter_init(&pair->effective->ht_symbols, &hti, NULL); 773 while ((ptr = hash_table_iter_up(&hti))) 774 { 775 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt); 776 nameW = symt_get_nameW(&sym->symt); 777 ret = SymMatchStringW(nameW, match, FALSE); 778 HeapFree(GetProcessHeap(), 0, nameW); 779 if (ret) 780 { 781 se->sym_info->SizeOfStruct = sizeof(SYMBOL_INFO); 782 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO); 783 if (send_symbol(se, pair, NULL, &sym->symt)) return TRUE; 784 } 785 } 786 return FALSE; 787 } 788 789 static inline unsigned where_to_insert(struct module* module, unsigned high, const struct symt_ht* elt) 790 { 791 unsigned low = 0, mid = high / 2; 792 ULONG64 addr; 793 794 if (!high) return 0; 795 symt_get_address(&elt->symt, &addr); 796 do 797 { 798 switch (cmp_sorttab_addr(module, mid, addr)) 799 { 800 case 0: return mid; 801 case -1: low = mid + 1; break; 802 case 1: high = mid; break; 803 } 804 mid = low + (high - low) / 2; 805 } while (low < high); 806 return mid; 807 } 808 809 /*********************************************************************** 810 * resort_symbols 811 * 812 * Rebuild sorted list of symbols for a module. 813 */ 814 static BOOL resort_symbols(struct module* module) 815 { 816 int delta; 817 818 if (!(module->module.NumSyms = module->num_symbols)) 819 return FALSE; 820 821 /* we know that set from 0 up to num_sorttab is already sorted 822 * so sort the remaining (new) symbols, and merge the two sets 823 * (unless the first set is empty) 824 */ 825 delta = module->num_symbols - module->num_sorttab; 826 qsort(&module->addr_sorttab[module->num_sorttab], delta, sizeof(struct symt_ht*), symt_cmp_addr); 827 if (module->num_sorttab) 828 { 829 int i, ins_idx = module->num_sorttab, prev_ins_idx; 830 static struct symt_ht** tmp; 831 static unsigned num_tmp; 832 833 if (num_tmp < delta) 834 { 835 static struct symt_ht** new; 836 if (tmp) 837 new = HeapReAlloc(GetProcessHeap(), 0, tmp, delta * sizeof(struct symt_ht*)); 838 else 839 new = HeapAlloc(GetProcessHeap(), 0, delta * sizeof(struct symt_ht*)); 840 if (!new) 841 { 842 module->num_sorttab = 0; 843 return resort_symbols(module); 844 } 845 tmp = new; 846 num_tmp = delta; 847 } 848 memcpy(tmp, &module->addr_sorttab[module->num_sorttab], delta * sizeof(struct symt_ht*)); 849 qsort(tmp, delta, sizeof(struct symt_ht*), symt_cmp_addr); 850 851 for (i = delta - 1; i >= 0; i--) 852 { 853 prev_ins_idx = ins_idx; 854 ins_idx = where_to_insert(module, ins_idx, tmp[i]); 855 memmove(&module->addr_sorttab[ins_idx + i + 1], 856 &module->addr_sorttab[ins_idx], 857 (prev_ins_idx - ins_idx) * sizeof(struct symt_ht*)); 858 module->addr_sorttab[ins_idx + i] = tmp[i]; 859 } 860 } 861 module->num_sorttab = module->num_symbols; 862 return module->sortlist_valid = TRUE; 863 } 864 865 static void symt_get_length(struct module* module, const struct symt* symt, ULONG64* size) 866 { 867 DWORD type_index; 868 869 if (symt_get_info(module, symt, TI_GET_LENGTH, size) && *size) 870 return; 871 872 if (symt_get_info(module, symt, TI_GET_TYPE, &type_index) && 873 symt_get_info(module, symt_index2ptr(module, type_index), TI_GET_LENGTH, size)) return; 874 *size = 0x1000; /* arbitrary value */ 875 } 876 877 /* neede by symt_find_nearest */ 878 int symt_get_best_at(struct module* module, int idx_sorttab) 879 { 880 ULONG64 ref_addr; 881 int idx_sorttab_orig = idx_sorttab; 882 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol) 883 { 884 symt_get_address(&module->addr_sorttab[idx_sorttab]->symt, &ref_addr); 885 while (idx_sorttab > 0 && 886 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol && 887 !cmp_sorttab_addr(module, idx_sorttab - 1, ref_addr)) 888 idx_sorttab--; 889 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol) 890 { 891 idx_sorttab = idx_sorttab_orig; 892 while (idx_sorttab < module->num_sorttab - 1 && 893 module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol && 894 !cmp_sorttab_addr(module, idx_sorttab + 1, ref_addr)) 895 idx_sorttab++; 896 } 897 /* if no better symbol fond restore original */ 898 if (module->addr_sorttab[idx_sorttab]->symt.tag == SymTagPublicSymbol) 899 idx_sorttab = idx_sorttab_orig; 900 } 901 return idx_sorttab; 902 } 903 904 /* assume addr is in module */ 905 struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr) 906 { 907 int mid, high, low; 908 ULONG64 ref_addr, ref_size; 909 910 if (!module->sortlist_valid || !module->addr_sorttab) 911 { 912 if (!resort_symbols(module)) return NULL; 913 } 914 915 /* 916 * Binary search to find closest symbol. 917 */ 918 low = 0; 919 high = module->num_sorttab; 920 921 symt_get_address(&module->addr_sorttab[0]->symt, &ref_addr); 922 if (addr <= ref_addr) 923 { 924 low = symt_get_best_at(module, 0); 925 return module->addr_sorttab[low]; 926 } 927 928 if (high) 929 { 930 symt_get_address(&module->addr_sorttab[high - 1]->symt, &ref_addr); 931 symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size); 932 if (addr >= ref_addr + ref_size) return NULL; 933 } 934 935 while (high > low + 1) 936 { 937 mid = (high + low) / 2; 938 if (cmp_sorttab_addr(module, mid, addr) < 0) 939 low = mid; 940 else 941 high = mid; 942 } 943 if (low != high && high != module->num_sorttab && 944 cmp_sorttab_addr(module, high, addr) <= 0) 945 low = high; 946 947 /* If found symbol is a public symbol, check if there are any other entries that 948 * might also have the same address, but would get better information 949 */ 950 low = symt_get_best_at(module, low); 951 952 /* finally check that we fit into the found symbol */ 953 //symt_get_address(&module->addr_sorttab[low]->symt, &ref_addr); 954 //if (addr < ref_addr) return NULL; 955 //symt_get_length(module, &module->addr_sorttab[low]->symt, &ref_size); 956 //if (addr >= ref_addr + ref_size) return NULL; 957 958 return module->addr_sorttab[low]; 959 } 960 961 static BOOL symt_enum_locals_helper(struct module_pair* pair, 962 const WCHAR* match, const struct sym_enum* se, 963 struct symt_function* func, const struct vector* v) 964 { 965 struct symt* lsym = NULL; 966 DWORD pc = pair->pcs->ctx_frame.InstructionOffset; 967 unsigned int i; 968 WCHAR* nameW; 969 BOOL ret; 970 971 for (i=0; i<vector_length(v); i++) 972 { 973 lsym = *(struct symt**)vector_at(v, i); 974 switch (lsym->tag) 975 { 976 case SymTagBlock: 977 { 978 struct symt_block* block = (struct symt_block*)lsym; 979 if (pc < block->address || block->address + block->size <= pc) 980 continue; 981 if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren)) 982 return FALSE; 983 } 984 break; 985 case SymTagData: 986 nameW = symt_get_nameW(lsym); 987 ret = SymMatchStringW(nameW, match, 988 !(dbghelp_options & SYMOPT_CASE_INSENSITIVE)); 989 HeapFree(GetProcessHeap(), 0, nameW); 990 if (ret) 991 { 992 if (send_symbol(se, pair, func, lsym)) return FALSE; 993 } 994 break; 995 case SymTagLabel: 996 case SymTagFuncDebugStart: 997 case SymTagFuncDebugEnd: 998 case SymTagCustom: 999 break; 1000 default: 1001 FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag); 1002 assert(0); 1003 } 1004 } 1005 return TRUE; 1006 } 1007 1008 static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask, 1009 const struct sym_enum* se) 1010 { 1011 struct module_pair pair; 1012 struct symt_ht* sym; 1013 DWORD_PTR pc = pcs->ctx_frame.InstructionOffset; 1014 1015 se->sym_info->SizeOfStruct = sizeof(*se->sym_info); 1016 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO); 1017 1018 pair.pcs = pcs; 1019 pair.requested = module_find_by_addr(pair.pcs, pc, DMT_UNKNOWN); 1020 if (!module_get_debug(&pair)) return FALSE; 1021 if ((sym = symt_find_nearest(pair.effective, pc)) == NULL) return FALSE; 1022 1023 if (sym->symt.tag == SymTagFunction) 1024 { 1025 return symt_enum_locals_helper(&pair, mask ? mask : starW, se, (struct symt_function*)sym, 1026 &((struct symt_function*)sym)->vchildren); 1027 } 1028 return FALSE; 1029 } 1030 1031 /****************************************************************** 1032 * copy_symbolW 1033 * 1034 * Helper for transforming an ANSI symbol info into a UNICODE one. 1035 * Assume that MaxNameLen is the same for both version (A & W). 1036 */ 1037 void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si) 1038 { 1039 siw->SizeOfStruct = si->SizeOfStruct; 1040 siw->TypeIndex = si->TypeIndex; 1041 siw->Reserved[0] = si->Reserved[0]; 1042 siw->Reserved[1] = si->Reserved[1]; 1043 siw->Index = si->Index; 1044 siw->Size = si->Size; 1045 siw->ModBase = si->ModBase; 1046 siw->Flags = si->Flags; 1047 siw->Value = si->Value; 1048 siw->Address = si->Address; 1049 siw->Register = si->Register; 1050 siw->Scope = si->Scope; 1051 siw->Tag = si->Tag; 1052 siw->NameLen = si->NameLen; 1053 siw->MaxNameLen = si->MaxNameLen; 1054 MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen); 1055 } 1056 1057 /****************************************************************** 1058 * sym_enum 1059 * 1060 * Core routine for most of the enumeration of symbols 1061 */ 1062 static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask, 1063 const struct sym_enum* se) 1064 { 1065 struct module_pair pair; 1066 const WCHAR* bang; 1067 WCHAR* mod; 1068 1069 pair.pcs = process_find_by_handle(hProcess); 1070 if (!pair.pcs) return FALSE; 1071 if (BaseOfDll == 0) 1072 { 1073 /* do local variables ? */ 1074 if (!Mask || !(bang = strchrW(Mask, '!'))) 1075 return symt_enum_locals(pair.pcs, Mask, se); 1076 1077 if (bang == Mask) return FALSE; 1078 1079 mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR)); 1080 if (!mod) return FALSE; 1081 memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR)); 1082 mod[bang - Mask] = 0; 1083 1084 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next) 1085 { 1086 if (pair.requested->type == DMT_PE && module_get_debug(&pair)) 1087 { 1088 if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) && 1089 symt_enum_module(&pair, bang + 1, se)) 1090 break; 1091 } 1092 } 1093 /* not found in PE modules, retry on the ELF ones 1094 */ 1095 if (!pair.requested && (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES)) 1096 { 1097 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next) 1098 { 1099 if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) && 1100 !module_get_containee(pair.pcs, pair.requested) && 1101 module_get_debug(&pair)) 1102 { 1103 if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) && 1104 symt_enum_module(&pair, bang + 1, se)) 1105 break; 1106 } 1107 } 1108 } 1109 HeapFree(GetProcessHeap(), 0, mod); 1110 return TRUE; 1111 } 1112 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN); 1113 if (!module_get_debug(&pair)) 1114 return FALSE; 1115 1116 /* we always ignore module name from Mask when BaseOfDll is defined */ 1117 if (Mask && (bang = strchrW(Mask, '!'))) 1118 { 1119 if (bang == Mask) return FALSE; 1120 Mask = bang + 1; 1121 } 1122 1123 symt_enum_module(&pair, Mask ? Mask : starW, se); 1124 1125 return TRUE; 1126 } 1127 1128 static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask, 1129 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 1130 PVOID UserContext) 1131 { 1132 struct sym_enum se; 1133 1134 se.cb = EnumSymbolsCallback; 1135 se.user = UserContext; 1136 se.index = 0; 1137 se.tag = 0; 1138 se.addr = 0; 1139 se.sym_info = (PSYMBOL_INFO)se.buffer; 1140 1141 return sym_enum(hProcess, BaseOfDll, Mask, &se); 1142 } 1143 1144 /****************************************************************** 1145 * SymEnumSymbols (DBGHELP.@) 1146 * 1147 * cases BaseOfDll = 0 1148 * !foo fails always (despite what MSDN states) 1149 * RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2 1150 * no ! in Mask, lookup in local Context 1151 * cases BaseOfDll != 0 1152 * !foo fails always (despite what MSDN states) 1153 * RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is) 1154 */ 1155 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, 1156 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 1157 PVOID UserContext) 1158 { 1159 BOOL ret; 1160 PWSTR maskW = NULL; 1161 1162 TRACE("(%p %s %s %p %p)\n", 1163 hProcess, wine_dbgstr_longlong(BaseOfDll), debugstr_a(Mask), 1164 EnumSymbolsCallback, UserContext); 1165 1166 if (Mask) 1167 { 1168 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0); 1169 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 1170 return FALSE; 1171 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz); 1172 } 1173 ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext); 1174 HeapFree(GetProcessHeap(), 0, maskW); 1175 return ret; 1176 } 1177 1178 struct sym_enumW 1179 { 1180 PSYM_ENUMERATESYMBOLS_CALLBACKW cb; 1181 void* ctx; 1182 PSYMBOL_INFOW sym_info; 1183 char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME]; 1184 1185 }; 1186 1187 static BOOL CALLBACK sym_enumW(PSYMBOL_INFO si, ULONG size, PVOID ctx) 1188 { 1189 struct sym_enumW* sew = ctx; 1190 1191 copy_symbolW(sew->sym_info, si); 1192 1193 return (sew->cb)(sew->sym_info, size, sew->ctx); 1194 } 1195 1196 /****************************************************************** 1197 * SymEnumSymbolsW (DBGHELP.@) 1198 * 1199 */ 1200 BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask, 1201 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, 1202 PVOID UserContext) 1203 { 1204 struct sym_enumW sew; 1205 1206 sew.ctx = UserContext; 1207 sew.cb = EnumSymbolsCallback; 1208 sew.sym_info = (PSYMBOL_INFOW)sew.buffer; 1209 1210 return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew); 1211 } 1212 1213 struct sym_enumerate 1214 { 1215 void* ctx; 1216 PSYM_ENUMSYMBOLS_CALLBACK cb; 1217 }; 1218 1219 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx) 1220 { 1221 struct sym_enumerate* se = ctx; 1222 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); 1223 } 1224 1225 /*********************************************************************** 1226 * SymEnumerateSymbols (DBGHELP.@) 1227 */ 1228 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll, 1229 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, 1230 PVOID UserContext) 1231 { 1232 struct sym_enumerate se; 1233 1234 se.ctx = UserContext; 1235 se.cb = EnumSymbolsCallback; 1236 1237 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se); 1238 } 1239 1240 struct sym_enumerate64 1241 { 1242 void* ctx; 1243 PSYM_ENUMSYMBOLS_CALLBACK64 cb; 1244 }; 1245 1246 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx) 1247 { 1248 struct sym_enumerate64* se = ctx; 1249 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); 1250 } 1251 1252 /*********************************************************************** 1253 * SymEnumerateSymbols64 (DBGHELP.@) 1254 */ 1255 BOOL WINAPI SymEnumerateSymbols64(HANDLE hProcess, DWORD64 BaseOfDll, 1256 PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback, 1257 PVOID UserContext) 1258 { 1259 struct sym_enumerate64 se; 1260 1261 se.ctx = UserContext; 1262 se.cb = EnumSymbolsCallback; 1263 1264 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb64, &se); 1265 } 1266 1267 /****************************************************************** 1268 * SymFromAddr (DBGHELP.@) 1269 * 1270 */ 1271 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address, 1272 DWORD64* Displacement, PSYMBOL_INFO Symbol) 1273 { 1274 struct module_pair pair; 1275 struct symt_ht* sym; 1276 1277 pair.pcs = process_find_by_handle(hProcess); 1278 if (!pair.pcs) return FALSE; 1279 pair.requested = module_find_by_addr(pair.pcs, Address, DMT_UNKNOWN); 1280 if (!module_get_debug(&pair)) return FALSE; 1281 if ((sym = symt_find_nearest(pair.effective, Address)) == NULL) return FALSE; 1282 1283 symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol); 1284 if (Displacement) 1285 *Displacement = (Address >= Symbol->Address) ? (Address - Symbol->Address) : (DWORD64)-1; 1286 return TRUE; 1287 } 1288 1289 /****************************************************************** 1290 * SymFromAddrW (DBGHELP.@) 1291 * 1292 */ 1293 BOOL WINAPI SymFromAddrW(HANDLE hProcess, DWORD64 Address, 1294 DWORD64* Displacement, PSYMBOL_INFOW Symbol) 1295 { 1296 PSYMBOL_INFO si; 1297 unsigned len; 1298 BOOL ret; 1299 1300 len = sizeof(*si) + Symbol->MaxNameLen * sizeof(WCHAR); 1301 si = HeapAlloc(GetProcessHeap(), 0, len); 1302 if (!si) return FALSE; 1303 1304 si->SizeOfStruct = sizeof(*si); 1305 si->MaxNameLen = Symbol->MaxNameLen; 1306 if ((ret = SymFromAddr(hProcess, Address, Displacement, si))) 1307 { 1308 copy_symbolW(Symbol, si); 1309 } 1310 HeapFree(GetProcessHeap(), 0, si); 1311 return ret; 1312 } 1313 1314 /****************************************************************** 1315 * SymGetSymFromAddr (DBGHELP.@) 1316 * 1317 */ 1318 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address, 1319 PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol) 1320 { 1321 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 1322 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; 1323 size_t len; 1324 DWORD64 Displacement64; 1325 1326 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1327 si->SizeOfStruct = sizeof(*si); 1328 si->MaxNameLen = MAX_SYM_NAME; 1329 if (!SymFromAddr(hProcess, Address, &Displacement64, si)) 1330 return FALSE; 1331 1332 if (Displacement) 1333 *Displacement = Displacement64; 1334 Symbol->Address = si->Address; 1335 Symbol->Size = si->Size; 1336 Symbol->Flags = si->Flags; 1337 len = min(Symbol->MaxNameLength, si->MaxNameLen); 1338 lstrcpynA(Symbol->Name, si->Name, len); 1339 return TRUE; 1340 } 1341 1342 /****************************************************************** 1343 * SymGetSymFromAddr64 (DBGHELP.@) 1344 * 1345 */ 1346 BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address, 1347 PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) 1348 { 1349 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 1350 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; 1351 size_t len; 1352 DWORD64 Displacement64; 1353 1354 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1355 si->SizeOfStruct = sizeof(*si); 1356 si->MaxNameLen = MAX_SYM_NAME; 1357 if (!SymFromAddr(hProcess, Address, &Displacement64, si)) 1358 return FALSE; 1359 1360 if (Displacement) 1361 *Displacement = Displacement64; 1362 Symbol->Address = si->Address; 1363 Symbol->Size = si->Size; 1364 Symbol->Flags = si->Flags; 1365 len = min(Symbol->MaxNameLength, si->MaxNameLen); 1366 lstrcpynA(Symbol->Name, si->Name, len); 1367 return TRUE; 1368 } 1369 1370 static BOOL find_name(struct process* pcs, struct module* module, const char* name, 1371 SYMBOL_INFO* symbol) 1372 { 1373 struct hash_table_iter hti; 1374 void* ptr; 1375 struct symt_ht* sym = NULL; 1376 struct module_pair pair; 1377 1378 pair.pcs = pcs; 1379 if (!(pair.requested = module)) return FALSE; 1380 if (!module_get_debug(&pair)) return FALSE; 1381 1382 hash_table_iter_init(&pair.effective->ht_symbols, &hti, name); 1383 while ((ptr = hash_table_iter_up(&hti))) 1384 { 1385 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt); 1386 1387 if (!strcmp(sym->hash_elt.name, name)) 1388 { 1389 symt_fill_sym_info(&pair, NULL, &sym->symt, symbol); 1390 return TRUE; 1391 } 1392 } 1393 return FALSE; 1394 1395 } 1396 /****************************************************************** 1397 * SymFromName (DBGHELP.@) 1398 * 1399 */ 1400 BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) 1401 { 1402 struct process* pcs = process_find_by_handle(hProcess); 1403 struct module* module; 1404 const char* name; 1405 1406 TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol); 1407 if (!pcs) return FALSE; 1408 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1409 name = strchr(Name, '!'); 1410 if (name) 1411 { 1412 char tmp[128]; 1413 assert(name - Name < sizeof(tmp)); 1414 memcpy(tmp, Name, name - Name); 1415 tmp[name - Name] = '\0'; 1416 module = module_find_by_nameA(pcs, tmp); 1417 return find_name(pcs, module, name + 1, Symbol); 1418 } 1419 for (module = pcs->lmodules; module; module = module->next) 1420 { 1421 if (module->type == DMT_PE && find_name(pcs, module, Name, Symbol)) 1422 return TRUE; 1423 } 1424 /* not found in PE modules, retry on the ELF ones 1425 */ 1426 if (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) 1427 { 1428 for (module = pcs->lmodules; module; module = module->next) 1429 { 1430 if ((module->type == DMT_ELF || module->type == DMT_MACHO) && 1431 !module_get_containee(pcs, module) && 1432 find_name(pcs, module, Name, Symbol)) 1433 return TRUE; 1434 } 1435 } 1436 return FALSE; 1437 } 1438 1439 /*********************************************************************** 1440 * SymGetSymFromName64 (DBGHELP.@) 1441 */ 1442 BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol) 1443 { 1444 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 1445 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; 1446 size_t len; 1447 1448 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1449 si->SizeOfStruct = sizeof(*si); 1450 si->MaxNameLen = MAX_SYM_NAME; 1451 if (!SymFromName(hProcess, Name, si)) return FALSE; 1452 1453 Symbol->Address = si->Address; 1454 Symbol->Size = si->Size; 1455 Symbol->Flags = si->Flags; 1456 len = min(Symbol->MaxNameLength, si->MaxNameLen); 1457 lstrcpynA(Symbol->Name, si->Name, len); 1458 return TRUE; 1459 } 1460 1461 /*********************************************************************** 1462 * SymGetSymFromName (DBGHELP.@) 1463 */ 1464 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL Symbol) 1465 { 1466 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 1467 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; 1468 size_t len; 1469 1470 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1471 si->SizeOfStruct = sizeof(*si); 1472 si->MaxNameLen = MAX_SYM_NAME; 1473 if (!SymFromName(hProcess, Name, si)) return FALSE; 1474 1475 Symbol->Address = si->Address; 1476 Symbol->Size = si->Size; 1477 Symbol->Flags = si->Flags; 1478 len = min(Symbol->MaxNameLength, si->MaxNameLen); 1479 lstrcpynA(Symbol->Name, si->Name, len); 1480 return TRUE; 1481 } 1482 1483 /****************************************************************** 1484 * sym_fill_func_line_info 1485 * 1486 * fills information about a file 1487 */ 1488 BOOL symt_fill_func_line_info(const struct module* module, const struct symt_function* func, 1489 DWORD64 addr, IMAGEHLP_LINE64* line) 1490 { 1491 struct line_info* dli = NULL; 1492 BOOL found = FALSE; 1493 int i; 1494 1495 assert(func->symt.tag == SymTagFunction); 1496 1497 for (i=vector_length(&func->vlines)-1; i>=0; i--) 1498 { 1499 dli = vector_at(&func->vlines, i); 1500 if (!dli->is_source_file) 1501 { 1502 if (found || dli->u.pc_offset > addr) continue; 1503 line->LineNumber = dli->line_number; 1504 line->Address = dli->u.pc_offset; 1505 line->Key = dli; 1506 found = TRUE; 1507 continue; 1508 } 1509 if (found) 1510 { 1511 line->FileName = (char*)source_get(module, dli->u.source_file); 1512 return TRUE; 1513 } 1514 } 1515 return FALSE; 1516 } 1517 1518 /*********************************************************************** 1519 * SymGetSymNext64 (DBGHELP.@) 1520 */ 1521 BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) 1522 { 1523 /* algo: 1524 * get module from Symbol.Address 1525 * get index in module.addr_sorttab of Symbol.Address 1526 * increment index 1527 * if out of module bounds, move to next module in process address space 1528 */ 1529 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1530 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1531 return FALSE; 1532 } 1533 1534 /*********************************************************************** 1535 * SymGetSymNext (DBGHELP.@) 1536 */ 1537 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) 1538 { 1539 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1540 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1541 return FALSE; 1542 } 1543 1544 /*********************************************************************** 1545 * SymGetSymPrev64 (DBGHELP.@) 1546 */ 1547 BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) 1548 { 1549 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1550 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1551 return FALSE; 1552 } 1553 1554 /*********************************************************************** 1555 * SymGetSymPrev (DBGHELP.@) 1556 */ 1557 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) 1558 { 1559 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1560 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1561 return FALSE; 1562 } 1563 1564 /****************************************************************** 1565 * copy_line_64_from_32 (internal) 1566 * 1567 */ 1568 static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32) 1569 1570 { 1571 l64->Key = l32->Key; 1572 l64->LineNumber = l32->LineNumber; 1573 l64->FileName = l32->FileName; 1574 l64->Address = l32->Address; 1575 } 1576 1577 /****************************************************************** 1578 * copy_line_W64_from_32 (internal) 1579 * 1580 */ 1581 static void copy_line_W64_from_64(struct process* pcs, IMAGEHLP_LINEW64* l64w, const IMAGEHLP_LINE64* l64) 1582 { 1583 unsigned len; 1584 1585 l64w->Key = l64->Key; 1586 l64w->LineNumber = l64->LineNumber; 1587 len = MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, NULL, 0); 1588 if ((l64w->FileName = fetch_buffer(pcs, len * sizeof(WCHAR)))) 1589 MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, l64w->FileName, len); 1590 l64w->Address = l64->Address; 1591 } 1592 1593 /****************************************************************** 1594 * copy_line_32_from_64 (internal) 1595 * 1596 */ 1597 static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64) 1598 1599 { 1600 l32->Key = l64->Key; 1601 l32->LineNumber = l64->LineNumber; 1602 l32->FileName = l64->FileName; 1603 l32->Address = l64->Address; 1604 } 1605 1606 /****************************************************************** 1607 * SymGetLineFromAddr (DBGHELP.@) 1608 * 1609 */ 1610 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, 1611 PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) 1612 { 1613 IMAGEHLP_LINE64 il64; 1614 1615 il64.SizeOfStruct = sizeof(il64); 1616 if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) 1617 return FALSE; 1618 copy_line_32_from_64(Line, &il64); 1619 return TRUE; 1620 } 1621 1622 /****************************************************************** 1623 * SymGetLineFromAddr64 (DBGHELP.@) 1624 * 1625 */ 1626 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, 1627 PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) 1628 { 1629 struct module_pair pair; 1630 struct symt_ht* symt; 1631 1632 TRACE("%p %s %p %p\n", hProcess, wine_dbgstr_longlong(dwAddr), pdwDisplacement, Line); 1633 1634 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; 1635 1636 pair.pcs = process_find_by_handle(hProcess); 1637 if (!pair.pcs) return FALSE; 1638 pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); 1639 if (!module_get_debug(&pair)) return FALSE; 1640 if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; 1641 1642 if (symt->symt.tag != SymTagFunction) return FALSE; 1643 if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, 1644 dwAddr, Line)) return FALSE; 1645 *pdwDisplacement = dwAddr - Line->Address; 1646 return TRUE; 1647 } 1648 1649 /****************************************************************** 1650 * SymGetLineFromAddrW64 (DBGHELP.@) 1651 * 1652 */ 1653 BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, 1654 PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line) 1655 { 1656 IMAGEHLP_LINE64 il64; 1657 1658 il64.SizeOfStruct = sizeof(il64); 1659 if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) 1660 return FALSE; 1661 copy_line_W64_from_64(process_find_by_handle(hProcess), Line, &il64); 1662 return TRUE; 1663 } 1664 1665 /****************************************************************** 1666 * SymGetLinePrev64 (DBGHELP.@) 1667 * 1668 */ 1669 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) 1670 { 1671 struct module_pair pair; 1672 struct line_info* li; 1673 BOOL in_search = FALSE; 1674 1675 TRACE("(%p %p)\n", hProcess, Line); 1676 1677 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; 1678 1679 pair.pcs = process_find_by_handle(hProcess); 1680 if (!pair.pcs) return FALSE; 1681 pair.requested = module_find_by_addr(pair.pcs, Line->Address, DMT_UNKNOWN); 1682 if (!module_get_debug(&pair)) return FALSE; 1683 1684 if (Line->Key == 0) return FALSE; 1685 li = Line->Key; 1686 /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE 1687 * element we have to go back until we find the prev one to get the real 1688 * source file name for the DLIT_OFFSET element just before 1689 * the first DLIT_SOURCEFILE 1690 */ 1691 while (!li->is_first) 1692 { 1693 li--; 1694 if (!li->is_source_file) 1695 { 1696 Line->LineNumber = li->line_number; 1697 Line->Address = li->u.pc_offset; 1698 Line->Key = li; 1699 if (!in_search) return TRUE; 1700 } 1701 else 1702 { 1703 if (in_search) 1704 { 1705 Line->FileName = (char*)source_get(pair.effective, li->u.source_file); 1706 return TRUE; 1707 } 1708 in_search = TRUE; 1709 } 1710 } 1711 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */ 1712 return FALSE; 1713 } 1714 1715 /****************************************************************** 1716 * SymGetLinePrev (DBGHELP.@) 1717 * 1718 */ 1719 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) 1720 { 1721 IMAGEHLP_LINE64 line64; 1722 1723 line64.SizeOfStruct = sizeof(line64); 1724 copy_line_64_from_32(&line64, Line); 1725 if (!SymGetLinePrev64(hProcess, &line64)) return FALSE; 1726 copy_line_32_from_64(Line, &line64); 1727 return TRUE; 1728 } 1729 1730 BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line) 1731 { 1732 struct line_info* li; 1733 1734 if (line->Key == 0) return FALSE; 1735 li = line->Key; 1736 while (!li->is_last) 1737 { 1738 li++; 1739 if (!li->is_source_file) 1740 { 1741 line->LineNumber = li->line_number; 1742 line->Address = li->u.pc_offset; 1743 line->Key = li; 1744 return TRUE; 1745 } 1746 line->FileName = (char*)source_get(module, li->u.source_file); 1747 } 1748 return FALSE; 1749 } 1750 1751 /****************************************************************** 1752 * SymGetLineNext64 (DBGHELP.@) 1753 * 1754 */ 1755 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) 1756 { 1757 struct module_pair pair; 1758 1759 TRACE("(%p %p)\n", hProcess, Line); 1760 1761 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; 1762 pair.pcs = process_find_by_handle(hProcess); 1763 if (!pair.pcs) return FALSE; 1764 pair.requested = module_find_by_addr(pair.pcs, Line->Address, DMT_UNKNOWN); 1765 if (!module_get_debug(&pair)) return FALSE; 1766 1767 if (symt_get_func_line_next(pair.effective, Line)) return TRUE; 1768 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */ 1769 return FALSE; 1770 } 1771 1772 /****************************************************************** 1773 * SymGetLineNext (DBGHELP.@) 1774 * 1775 */ 1776 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) 1777 { 1778 IMAGEHLP_LINE64 line64; 1779 1780 line64.SizeOfStruct = sizeof(line64); 1781 copy_line_64_from_32(&line64, Line); 1782 if (!SymGetLineNext64(hProcess, &line64)) return FALSE; 1783 copy_line_32_from_64(Line, &line64); 1784 return TRUE; 1785 } 1786 1787 /*********************************************************************** 1788 * SymUnDName (DBGHELP.@) 1789 */ 1790 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength) 1791 { 1792 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, 1793 UNDNAME_COMPLETE) != 0; 1794 } 1795 1796 /*********************************************************************** 1797 * SymUnDName64 (DBGHELP.@) 1798 */ 1799 BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength) 1800 { 1801 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, 1802 UNDNAME_COMPLETE) != 0; 1803 } 1804 1805 static void * CDECL und_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len); } 1806 static void CDECL und_free (void* ptr) { HeapFree(GetProcessHeap(), 0, ptr); } 1807 1808 static char *und_name(char *buffer, const char *mangled, int buflen, unsigned short flags) 1809 { 1810 /* undocumented from msvcrt */ 1811 static HANDLE hMsvcrt; 1812 static char* (CDECL *p_undname)(char*, const char*, int, void* (CDECL*)(size_t), void (CDECL*)(void*), unsigned short); 1813 static const WCHAR szMsvcrt[] = {'m','s','v','c','r','t','.','d','l','l',0}; 1814 1815 if (!p_undname) 1816 { 1817 if (!hMsvcrt) hMsvcrt = LoadLibraryW(szMsvcrt); 1818 if (hMsvcrt) p_undname = (void*)GetProcAddress(hMsvcrt, "__unDName"); 1819 if (!p_undname) return NULL; 1820 } 1821 1822 return p_undname(buffer, mangled, buflen, und_alloc, und_free, flags); 1823 } 1824 1825 /*********************************************************************** 1826 * UnDecorateSymbolName (DBGHELP.@) 1827 */ 1828 DWORD WINAPI UnDecorateSymbolName(const char *decorated_name, char *undecorated_name, 1829 DWORD undecorated_length, DWORD flags) 1830 { 1831 TRACE("(%s, %p, %d, 0x%08x)\n", 1832 debugstr_a(decorated_name), undecorated_name, undecorated_length, flags); 1833 1834 if (!undecorated_name || !undecorated_length) 1835 return 0; 1836 if (!und_name(undecorated_name, decorated_name, undecorated_length, flags)) 1837 return 0; 1838 return strlen(undecorated_name); 1839 } 1840 1841 /*********************************************************************** 1842 * UnDecorateSymbolNameW (DBGHELP.@) 1843 */ 1844 DWORD WINAPI UnDecorateSymbolNameW(const WCHAR *decorated_name, WCHAR *undecorated_name, 1845 DWORD undecorated_length, DWORD flags) 1846 { 1847 char *buf, *ptr; 1848 int len, ret = 0; 1849 1850 TRACE("(%s, %p, %d, 0x%08x)\n", 1851 debugstr_w(decorated_name), undecorated_name, undecorated_length, flags); 1852 1853 if (!undecorated_name || !undecorated_length) 1854 return 0; 1855 1856 len = WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, NULL, 0, NULL, NULL); 1857 if ((buf = HeapAlloc(GetProcessHeap(), 0, len))) 1858 { 1859 WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, buf, len, NULL, NULL); 1860 if ((ptr = und_name(NULL, buf, 0, flags))) 1861 { 1862 MultiByteToWideChar(CP_ACP, 0, ptr, -1, undecorated_name, undecorated_length); 1863 undecorated_name[undecorated_length - 1] = 0; 1864 ret = strlenW(undecorated_name); 1865 und_free(ptr); 1866 } 1867 HeapFree(GetProcessHeap(), 0, buf); 1868 } 1869 1870 return ret; 1871 } 1872 1873 #define WILDCHAR(x) (-(x)) 1874 1875 static int re_fetch_char(const WCHAR** re) 1876 { 1877 switch (**re) 1878 { 1879 case '\\': (*re)++; return *(*re)++; 1880 case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++); 1881 default: return *(*re)++; 1882 } 1883 } 1884 1885 static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case) 1886 { 1887 return _case ? ch1 - ch2 : toupperW(ch1) - toupperW(ch2); 1888 } 1889 1890 static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case) 1891 { 1892 int ch1, prev = 0; 1893 unsigned state = 0; 1894 1895 switch (ch1 = re_fetch_char(&elt)) 1896 { 1897 default: 1898 return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL; 1899 case WILDCHAR('?'): return *string ? ++string : NULL; 1900 case WILDCHAR('*'): assert(0); 1901 case WILDCHAR('['): break; 1902 } 1903 1904 for (;;) 1905 { 1906 ch1 = re_fetch_char(&elt); 1907 if (ch1 == WILDCHAR(']')) return NULL; 1908 if (state == 1 && ch1 == '-') state = 2; 1909 else 1910 { 1911 if (re_match_char(*string, ch1, _case) == 0) return ++string; 1912 switch (state) 1913 { 1914 case 0: 1915 state = 1; 1916 prev = ch1; 1917 break; 1918 case 1: 1919 state = 0; 1920 break; 1921 case 2: 1922 if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 && 1923 re_match_char(*string, ch1, _case) <= 0) 1924 return ++string; 1925 state = 0; 1926 break; 1927 } 1928 } 1929 } 1930 } 1931 1932 /****************************************************************** 1933 * re_match_multi 1934 * 1935 * match a substring of *pstring according to *pre regular expression 1936 * pstring and pre are only updated in case of successful match 1937 */ 1938 static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case) 1939 { 1940 const WCHAR* re_end = *pre; 1941 const WCHAR* string_end = *pstring; 1942 const WCHAR* re_beg; 1943 const WCHAR* string_beg; 1944 const WCHAR* next; 1945 int ch; 1946 1947 while (*re_end && *string_end) 1948 { 1949 string_beg = string_end; 1950 re_beg = re_end; 1951 switch (ch = re_fetch_char(&re_end)) 1952 { 1953 case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE; 1954 case WILDCHAR('*'): 1955 /* transform '*' into '?#' */ 1956 {static const WCHAR qmW[] = {'?',0}; re_beg = qmW;} 1957 goto closure; 1958 case WILDCHAR('['): 1959 do 1960 { 1961 if (!(ch = re_fetch_char(&re_end))) return FALSE; 1962 } while (ch != WILDCHAR(']')); 1963 /* fall through */ 1964 case WILDCHAR('?'): 1965 default: 1966 break; 1967 } 1968 1969 switch (*re_end) 1970 { 1971 case '+': 1972 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE; 1973 string_beg++; 1974 /* fall through */ 1975 case '#': 1976 re_end++; 1977 closure: 1978 while ((next = re_match_one(string_end, re_beg, _case))) string_end = next; 1979 for ( ; string_end >= string_beg; string_end--) 1980 { 1981 if (re_match_multi(&string_end, &re_end, _case)) goto found; 1982 } 1983 return FALSE; 1984 default: 1985 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE; 1986 string_end = next; 1987 } 1988 re_beg = re_end; 1989 } 1990 1991 if (*re_end || *string_end) return FALSE; 1992 1993 found: 1994 *pre = re_end; 1995 *pstring = string_end; 1996 return TRUE; 1997 } 1998 1999 /****************************************************************** 2000 * SymMatchStringA (DBGHELP.@) 2001 * 2002 */ 2003 BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case) 2004 { 2005 WCHAR* strW; 2006 WCHAR* reW; 2007 BOOL ret = FALSE; 2008 DWORD sz; 2009 2010 if (!string || !re) 2011 { 2012 SetLastError(ERROR_INVALID_HANDLE); 2013 return FALSE; 2014 } 2015 TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N'); 2016 2017 sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0); 2018 if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 2019 MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz); 2020 sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0); 2021 if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 2022 MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz); 2023 2024 if (strW && reW) 2025 ret = SymMatchStringW(strW, reW, _case); 2026 HeapFree(GetProcessHeap(), 0, strW); 2027 HeapFree(GetProcessHeap(), 0, reW); 2028 return ret; 2029 } 2030 2031 /****************************************************************** 2032 * SymMatchStringW (DBGHELP.@) 2033 * 2034 */ 2035 BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case) 2036 { 2037 TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N'); 2038 2039 if (!string || !re) 2040 { 2041 SetLastError(ERROR_INVALID_HANDLE); 2042 return FALSE; 2043 } 2044 return re_match_multi(&string, &re, _case); 2045 } 2046 2047 static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, 2048 DWORD SymTag, PCWSTR Mask, DWORD64 Address, 2049 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 2050 PVOID UserContext, DWORD Options) 2051 { 2052 struct sym_enum se; 2053 2054 if (Options != SYMSEARCH_GLOBALSONLY) 2055 { 2056 FIXME("Unsupported searching with options (%x)\n", Options); 2057 SetLastError(ERROR_INVALID_PARAMETER); 2058 return FALSE; 2059 } 2060 2061 se.cb = EnumSymbolsCallback; 2062 se.user = UserContext; 2063 se.index = Index; 2064 se.tag = SymTag; 2065 se.addr = Address; 2066 se.sym_info = (PSYMBOL_INFO)se.buffer; 2067 2068 return sym_enum(hProcess, BaseOfDll, Mask, &se); 2069 } 2070 2071 /****************************************************************** 2072 * SymSearch (DBGHELP.@) 2073 */ 2074 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, 2075 DWORD SymTag, PCSTR Mask, DWORD64 Address, 2076 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 2077 PVOID UserContext, DWORD Options) 2078 { 2079 LPWSTR maskW = NULL; 2080 BOOLEAN ret; 2081 2082 TRACE("(%p %s %u %u %s %s %p %p %x)\n", 2083 hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask, 2084 wine_dbgstr_longlong(Address), EnumSymbolsCallback, 2085 UserContext, Options); 2086 2087 if (Mask) 2088 { 2089 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0); 2090 2091 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 2092 return FALSE; 2093 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz); 2094 } 2095 ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address, 2096 EnumSymbolsCallback, UserContext, Options); 2097 HeapFree(GetProcessHeap(), 0, maskW); 2098 return ret; 2099 } 2100 2101 /****************************************************************** 2102 * SymSearchW (DBGHELP.@) 2103 */ 2104 BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, 2105 DWORD SymTag, PCWSTR Mask, DWORD64 Address, 2106 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, 2107 PVOID UserContext, DWORD Options) 2108 { 2109 struct sym_enumW sew; 2110 2111 TRACE("(%p %s %u %u %s %s %p %p %x)\n", 2112 hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, debugstr_w(Mask), 2113 wine_dbgstr_longlong(Address), EnumSymbolsCallback, 2114 UserContext, Options); 2115 2116 sew.ctx = UserContext; 2117 sew.cb = EnumSymbolsCallback; 2118 sew.sym_info = (PSYMBOL_INFOW)sew.buffer; 2119 2120 return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address, 2121 sym_enumW, &sew, Options); 2122 } 2123 2124 /****************************************************************** 2125 * SymAddSymbol (DBGHELP.@) 2126 * 2127 */ 2128 BOOL WINAPI SymAddSymbol(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR name, 2129 DWORD64 addr, DWORD size, DWORD flags) 2130 { 2131 WCHAR nameW[MAX_SYM_NAME]; 2132 2133 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, sizeof(nameW) / sizeof(WCHAR)); 2134 return SymAddSymbolW(hProcess, BaseOfDll, nameW, addr, size, flags); 2135 } 2136 2137 /****************************************************************** 2138 * SymAddSymbolW (DBGHELP.@) 2139 * 2140 */ 2141 BOOL WINAPI SymAddSymbolW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR name, 2142 DWORD64 addr, DWORD size, DWORD flags) 2143 { 2144 struct module_pair pair; 2145 2146 TRACE("(%p %s %s %u)\n", hProcess, wine_dbgstr_w(name), wine_dbgstr_longlong(addr), size); 2147 2148 pair.pcs = process_find_by_handle(hProcess); 2149 if (!pair.pcs) return FALSE; 2150 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN); 2151 if (!module_get_debug(&pair)) return FALSE; 2152 2153 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 2154 return FALSE; 2155 } 2156 2157 /****************************************************************** 2158 * SymSetScopeFromAddr (DBGHELP.@) 2159 */ 2160 BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) 2161 { 2162 struct process* pcs; 2163 2164 FIXME("(%p %s): stub\n", hProcess, wine_dbgstr_longlong(addr)); 2165 2166 if (!(pcs = process_find_by_handle(hProcess))) return FALSE; 2167 return TRUE; 2168 } 2169 2170 /****************************************************************** 2171 * SymEnumLines (DBGHELP.@) 2172 * 2173 */ 2174 BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, 2175 PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user) 2176 { 2177 struct module_pair pair; 2178 struct hash_table_iter hti; 2179 struct symt_ht* sym; 2180 WCHAR* srcmask; 2181 struct line_info* dli; 2182 void* ptr; 2183 SRCCODEINFO sci; 2184 const char* file; 2185 2186 if (!cb) return FALSE; 2187 if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE; 2188 2189 pair.pcs = process_find_by_handle(hProcess); 2190 if (!pair.pcs) return FALSE; 2191 if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland); 2192 pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN); 2193 if (!module_get_debug(&pair)) return FALSE; 2194 if (!(srcmask = file_regex(srcfile))) return FALSE; 2195 2196 sci.SizeOfStruct = sizeof(sci); 2197 sci.ModBase = base; 2198 2199 hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL); 2200 while ((ptr = hash_table_iter_up(&hti))) 2201 { 2202 unsigned int i; 2203 2204 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt); 2205 if (sym->symt.tag != SymTagFunction) continue; 2206 2207 sci.FileName[0] = '\0'; 2208 for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++) 2209 { 2210 dli = vector_at(&((struct symt_function*)sym)->vlines, i); 2211 if (dli->is_source_file) 2212 { 2213 file = source_get(pair.effective, dli->u.source_file); 2214 if (!file) sci.FileName[0] = '\0'; 2215 else 2216 { 2217 DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); 2218 WCHAR* fileW; 2219 2220 if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 2221 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz); 2222 if (SymMatchStringW(fileW, srcmask, FALSE)) 2223 strcpy(sci.FileName, file); 2224 else 2225 sci.FileName[0] = '\0'; 2226 HeapFree(GetProcessHeap(), 0, fileW); 2227 } 2228 } 2229 else if (sci.FileName[0]) 2230 { 2231 sci.Key = dli; 2232 sci.Obj[0] = '\0'; /* FIXME */ 2233 sci.LineNumber = dli->line_number; 2234 sci.Address = dli->u.pc_offset; 2235 if (!cb(&sci, user)) break; 2236 } 2237 } 2238 } 2239 HeapFree(GetProcessHeap(), 0, srcmask); 2240 return TRUE; 2241 } 2242 2243 BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, 2244 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line) 2245 { 2246 FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, 2247 dwLineNumber, plDisplacement, Line); 2248 return FALSE; 2249 } 2250 2251 BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, 2252 DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line) 2253 { 2254 FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, 2255 dwLineNumber, lpDisplacement, Line); 2256 return FALSE; 2257 } 2258 2259 BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName, 2260 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line) 2261 { 2262 FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName), 2263 dwLineNumber, plDisplacement, Line); 2264 return FALSE; 2265 } 2266 2267 /****************************************************************** 2268 * SymFromIndex (DBGHELP.@) 2269 * 2270 */ 2271 BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol) 2272 { 2273 FIXME("hProcess = %p, BaseOfDll = %s, index = %d, symbol = %p\n", 2274 hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol); 2275 2276 return FALSE; 2277 } 2278 2279 /****************************************************************** 2280 * SymFromIndexW (DBGHELP.@) 2281 * 2282 */ 2283 BOOL WINAPI SymFromIndexW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFOW symbol) 2284 { 2285 FIXME("hProcess = %p, BaseOfDll = %s, index = %d, symbol = %p\n", 2286 hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol); 2287 2288 return FALSE; 2289 } 2290 2291 /****************************************************************** 2292 * SymSetHomeDirectory (DBGHELP.@) 2293 * 2294 */ 2295 PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR dir) 2296 { 2297 FIXME("(%p, %s): stub\n", hProcess, dir); 2298 2299 return NULL; 2300 } 2301 2302 /****************************************************************** 2303 * SymSetHomeDirectoryW (DBGHELP.@) 2304 * 2305 */ 2306 PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir) 2307 { 2308 FIXME("(%p, %s): stub\n", hProcess, debugstr_w(dir)); 2309 2310 return NULL; 2311 } 2312