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 /* assume addr is in module */ 878 struct symt_ht* symt_find_nearest(struct module* module, DWORD_PTR addr) 879 { 880 int mid, high, low; 881 ULONG64 ref_addr, ref_size; 882 883 if (!module->sortlist_valid || !module->addr_sorttab) 884 { 885 if (!resort_symbols(module)) return NULL; 886 } 887 888 /* 889 * Binary search to find closest symbol. 890 */ 891 low = 0; 892 high = module->num_sorttab; 893 894 symt_get_address(&module->addr_sorttab[0]->symt, &ref_addr); 895 if (addr < ref_addr) return NULL; 896 if (high) 897 { 898 symt_get_address(&module->addr_sorttab[high - 1]->symt, &ref_addr); 899 symt_get_length(module, &module->addr_sorttab[high - 1]->symt, &ref_size); 900 if (addr >= ref_addr + ref_size) return NULL; 901 } 902 903 while (high > low + 1) 904 { 905 mid = (high + low) / 2; 906 if (cmp_sorttab_addr(module, mid, addr) < 0) 907 low = mid; 908 else 909 high = mid; 910 } 911 if (low != high && high != module->num_sorttab && 912 cmp_sorttab_addr(module, high, addr) <= 0) 913 low = high; 914 915 /* If found symbol is a public symbol, check if there are any other entries that 916 * might also have the same address, but would get better information 917 */ 918 if (module->addr_sorttab[low]->symt.tag == SymTagPublicSymbol) 919 { 920 symt_get_address(&module->addr_sorttab[low]->symt, &ref_addr); 921 if (low > 0 && 922 module->addr_sorttab[low - 1]->symt.tag != SymTagPublicSymbol && 923 !cmp_sorttab_addr(module, low - 1, ref_addr)) 924 low--; 925 else if (low < module->num_sorttab - 1 && 926 module->addr_sorttab[low + 1]->symt.tag != SymTagPublicSymbol && 927 !cmp_sorttab_addr(module, low + 1, ref_addr)) 928 low++; 929 } 930 /* finally check that we fit into the found symbol */ 931 symt_get_address(&module->addr_sorttab[low]->symt, &ref_addr); 932 if (addr < ref_addr) return NULL; 933 symt_get_length(module, &module->addr_sorttab[low]->symt, &ref_size); 934 if (addr >= ref_addr + ref_size) return NULL; 935 936 return module->addr_sorttab[low]; 937 } 938 939 static BOOL symt_enum_locals_helper(struct module_pair* pair, 940 const WCHAR* match, const struct sym_enum* se, 941 struct symt_function* func, const struct vector* v) 942 { 943 struct symt* lsym = NULL; 944 DWORD pc = pair->pcs->ctx_frame.InstructionOffset; 945 unsigned int i; 946 WCHAR* nameW; 947 BOOL ret; 948 949 for (i=0; i<vector_length(v); i++) 950 { 951 lsym = *(struct symt**)vector_at(v, i); 952 switch (lsym->tag) 953 { 954 case SymTagBlock: 955 { 956 struct symt_block* block = (struct symt_block*)lsym; 957 if (pc < block->address || block->address + block->size <= pc) 958 continue; 959 if (!symt_enum_locals_helper(pair, match, se, func, &block->vchildren)) 960 return FALSE; 961 } 962 break; 963 case SymTagData: 964 nameW = symt_get_nameW(lsym); 965 ret = SymMatchStringW(nameW, match, 966 !(dbghelp_options & SYMOPT_CASE_INSENSITIVE)); 967 HeapFree(GetProcessHeap(), 0, nameW); 968 if (ret) 969 { 970 if (send_symbol(se, pair, func, lsym)) return FALSE; 971 } 972 break; 973 case SymTagLabel: 974 case SymTagFuncDebugStart: 975 case SymTagFuncDebugEnd: 976 case SymTagCustom: 977 break; 978 default: 979 FIXME("Unknown type: %u (%x)\n", lsym->tag, lsym->tag); 980 assert(0); 981 } 982 } 983 return TRUE; 984 } 985 986 static BOOL symt_enum_locals(struct process* pcs, const WCHAR* mask, 987 const struct sym_enum* se) 988 { 989 struct module_pair pair; 990 struct symt_ht* sym; 991 DWORD_PTR pc = pcs->ctx_frame.InstructionOffset; 992 993 se->sym_info->SizeOfStruct = sizeof(*se->sym_info); 994 se->sym_info->MaxNameLen = sizeof(se->buffer) - sizeof(SYMBOL_INFO); 995 996 pair.pcs = pcs; 997 pair.requested = module_find_by_addr(pair.pcs, pc, DMT_UNKNOWN); 998 if (!module_get_debug(&pair)) return FALSE; 999 if ((sym = symt_find_nearest(pair.effective, pc)) == NULL) return FALSE; 1000 1001 if (sym->symt.tag == SymTagFunction) 1002 { 1003 return symt_enum_locals_helper(&pair, mask ? mask : starW, se, (struct symt_function*)sym, 1004 &((struct symt_function*)sym)->vchildren); 1005 } 1006 return FALSE; 1007 } 1008 1009 /****************************************************************** 1010 * copy_symbolW 1011 * 1012 * Helper for transforming an ANSI symbol info into a UNICODE one. 1013 * Assume that MaxNameLen is the same for both version (A & W). 1014 */ 1015 void copy_symbolW(SYMBOL_INFOW* siw, const SYMBOL_INFO* si) 1016 { 1017 siw->SizeOfStruct = si->SizeOfStruct; 1018 siw->TypeIndex = si->TypeIndex; 1019 siw->Reserved[0] = si->Reserved[0]; 1020 siw->Reserved[1] = si->Reserved[1]; 1021 siw->Index = si->Index; 1022 siw->Size = si->Size; 1023 siw->ModBase = si->ModBase; 1024 siw->Flags = si->Flags; 1025 siw->Value = si->Value; 1026 siw->Address = si->Address; 1027 siw->Register = si->Register; 1028 siw->Scope = si->Scope; 1029 siw->Tag = si->Tag; 1030 siw->NameLen = si->NameLen; 1031 siw->MaxNameLen = si->MaxNameLen; 1032 MultiByteToWideChar(CP_ACP, 0, si->Name, -1, siw->Name, siw->MaxNameLen); 1033 } 1034 1035 /****************************************************************** 1036 * sym_enum 1037 * 1038 * Core routine for most of the enumeration of symbols 1039 */ 1040 static BOOL sym_enum(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask, 1041 const struct sym_enum* se) 1042 { 1043 struct module_pair pair; 1044 const WCHAR* bang; 1045 WCHAR* mod; 1046 1047 pair.pcs = process_find_by_handle(hProcess); 1048 if (!pair.pcs) return FALSE; 1049 if (BaseOfDll == 0) 1050 { 1051 /* do local variables ? */ 1052 if (!Mask || !(bang = strchrW(Mask, '!'))) 1053 return symt_enum_locals(pair.pcs, Mask, se); 1054 1055 if (bang == Mask) return FALSE; 1056 1057 mod = HeapAlloc(GetProcessHeap(), 0, (bang - Mask + 1) * sizeof(WCHAR)); 1058 if (!mod) return FALSE; 1059 memcpy(mod, Mask, (bang - Mask) * sizeof(WCHAR)); 1060 mod[bang - Mask] = 0; 1061 1062 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next) 1063 { 1064 if (pair.requested->type == DMT_PE && module_get_debug(&pair)) 1065 { 1066 if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) && 1067 symt_enum_module(&pair, bang + 1, se)) 1068 break; 1069 } 1070 } 1071 /* not found in PE modules, retry on the ELF ones 1072 */ 1073 if (!pair.requested && (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES)) 1074 { 1075 for (pair.requested = pair.pcs->lmodules; pair.requested; pair.requested = pair.requested->next) 1076 { 1077 if ((pair.requested->type == DMT_ELF || pair.requested->type == DMT_MACHO) && 1078 !module_get_containee(pair.pcs, pair.requested) && 1079 module_get_debug(&pair)) 1080 { 1081 if (SymMatchStringW(pair.requested->module.ModuleName, mod, FALSE) && 1082 symt_enum_module(&pair, bang + 1, se)) 1083 break; 1084 } 1085 } 1086 } 1087 HeapFree(GetProcessHeap(), 0, mod); 1088 return TRUE; 1089 } 1090 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN); 1091 if (!module_get_debug(&pair)) 1092 return FALSE; 1093 1094 /* we always ignore module name from Mask when BaseOfDll is defined */ 1095 if (Mask && (bang = strchrW(Mask, '!'))) 1096 { 1097 if (bang == Mask) return FALSE; 1098 Mask = bang + 1; 1099 } 1100 1101 symt_enum_module(&pair, Mask ? Mask : starW, se); 1102 1103 return TRUE; 1104 } 1105 1106 static inline BOOL doSymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask, 1107 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 1108 PVOID UserContext) 1109 { 1110 struct sym_enum se; 1111 1112 se.cb = EnumSymbolsCallback; 1113 se.user = UserContext; 1114 se.index = 0; 1115 se.tag = 0; 1116 se.addr = 0; 1117 se.sym_info = (PSYMBOL_INFO)se.buffer; 1118 1119 return sym_enum(hProcess, BaseOfDll, Mask, &se); 1120 } 1121 1122 /****************************************************************** 1123 * SymEnumSymbols (DBGHELP.@) 1124 * 1125 * cases BaseOfDll = 0 1126 * !foo fails always (despite what MSDN states) 1127 * RE1!RE2 looks up all modules matching RE1, and in all these modules, lookup RE2 1128 * no ! in Mask, lookup in local Context 1129 * cases BaseOfDll != 0 1130 * !foo fails always (despite what MSDN states) 1131 * RE1!RE2 gets RE2 from BaseOfDll (whatever RE1 is) 1132 */ 1133 BOOL WINAPI SymEnumSymbols(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR Mask, 1134 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 1135 PVOID UserContext) 1136 { 1137 BOOL ret; 1138 PWSTR maskW = NULL; 1139 1140 TRACE("(%p %s %s %p %p)\n", 1141 hProcess, wine_dbgstr_longlong(BaseOfDll), debugstr_a(Mask), 1142 EnumSymbolsCallback, UserContext); 1143 1144 if (Mask) 1145 { 1146 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0); 1147 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 1148 return FALSE; 1149 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz); 1150 } 1151 ret = doSymEnumSymbols(hProcess, BaseOfDll, maskW, EnumSymbolsCallback, UserContext); 1152 HeapFree(GetProcessHeap(), 0, maskW); 1153 return ret; 1154 } 1155 1156 struct sym_enumW 1157 { 1158 PSYM_ENUMERATESYMBOLS_CALLBACKW cb; 1159 void* ctx; 1160 PSYMBOL_INFOW sym_info; 1161 char buffer[sizeof(SYMBOL_INFOW) + MAX_SYM_NAME]; 1162 1163 }; 1164 1165 static BOOL CALLBACK sym_enumW(PSYMBOL_INFO si, ULONG size, PVOID ctx) 1166 { 1167 struct sym_enumW* sew = ctx; 1168 1169 copy_symbolW(sew->sym_info, si); 1170 1171 return (sew->cb)(sew->sym_info, size, sew->ctx); 1172 } 1173 1174 /****************************************************************** 1175 * SymEnumSymbolsW (DBGHELP.@) 1176 * 1177 */ 1178 BOOL WINAPI SymEnumSymbolsW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR Mask, 1179 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, 1180 PVOID UserContext) 1181 { 1182 struct sym_enumW sew; 1183 1184 sew.ctx = UserContext; 1185 sew.cb = EnumSymbolsCallback; 1186 sew.sym_info = (PSYMBOL_INFOW)sew.buffer; 1187 1188 return doSymEnumSymbols(hProcess, BaseOfDll, Mask, sym_enumW, &sew); 1189 } 1190 1191 struct sym_enumerate 1192 { 1193 void* ctx; 1194 PSYM_ENUMSYMBOLS_CALLBACK cb; 1195 }; 1196 1197 static BOOL CALLBACK sym_enumerate_cb(PSYMBOL_INFO syminfo, ULONG size, void* ctx) 1198 { 1199 struct sym_enumerate* se = ctx; 1200 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); 1201 } 1202 1203 /*********************************************************************** 1204 * SymEnumerateSymbols (DBGHELP.@) 1205 */ 1206 BOOL WINAPI SymEnumerateSymbols(HANDLE hProcess, DWORD BaseOfDll, 1207 PSYM_ENUMSYMBOLS_CALLBACK EnumSymbolsCallback, 1208 PVOID UserContext) 1209 { 1210 struct sym_enumerate se; 1211 1212 se.ctx = UserContext; 1213 se.cb = EnumSymbolsCallback; 1214 1215 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb, &se); 1216 } 1217 1218 struct sym_enumerate64 1219 { 1220 void* ctx; 1221 PSYM_ENUMSYMBOLS_CALLBACK64 cb; 1222 }; 1223 1224 static BOOL CALLBACK sym_enumerate_cb64(PSYMBOL_INFO syminfo, ULONG size, void* ctx) 1225 { 1226 struct sym_enumerate64* se = ctx; 1227 return (se->cb)(syminfo->Name, syminfo->Address, syminfo->Size, se->ctx); 1228 } 1229 1230 /*********************************************************************** 1231 * SymEnumerateSymbols64 (DBGHELP.@) 1232 */ 1233 BOOL WINAPI SymEnumerateSymbols64(HANDLE hProcess, DWORD64 BaseOfDll, 1234 PSYM_ENUMSYMBOLS_CALLBACK64 EnumSymbolsCallback, 1235 PVOID UserContext) 1236 { 1237 struct sym_enumerate64 se; 1238 1239 se.ctx = UserContext; 1240 se.cb = EnumSymbolsCallback; 1241 1242 return SymEnumSymbols(hProcess, BaseOfDll, NULL, sym_enumerate_cb64, &se); 1243 } 1244 1245 /****************************************************************** 1246 * SymFromAddr (DBGHELP.@) 1247 * 1248 */ 1249 BOOL WINAPI SymFromAddr(HANDLE hProcess, DWORD64 Address, 1250 DWORD64* Displacement, PSYMBOL_INFO Symbol) 1251 { 1252 struct module_pair pair; 1253 struct symt_ht* sym; 1254 1255 pair.pcs = process_find_by_handle(hProcess); 1256 if (!pair.pcs) return FALSE; 1257 pair.requested = module_find_by_addr(pair.pcs, Address, DMT_UNKNOWN); 1258 if (!module_get_debug(&pair)) return FALSE; 1259 if ((sym = symt_find_nearest(pair.effective, Address)) == NULL) return FALSE; 1260 1261 symt_fill_sym_info(&pair, NULL, &sym->symt, Symbol); 1262 if (Displacement) 1263 *Displacement = Address - Symbol->Address; 1264 return TRUE; 1265 } 1266 1267 /****************************************************************** 1268 * SymFromAddrW (DBGHELP.@) 1269 * 1270 */ 1271 BOOL WINAPI SymFromAddrW(HANDLE hProcess, DWORD64 Address, 1272 DWORD64* Displacement, PSYMBOL_INFOW Symbol) 1273 { 1274 PSYMBOL_INFO si; 1275 unsigned len; 1276 BOOL ret; 1277 1278 len = sizeof(*si) + Symbol->MaxNameLen * sizeof(WCHAR); 1279 si = HeapAlloc(GetProcessHeap(), 0, len); 1280 if (!si) return FALSE; 1281 1282 si->SizeOfStruct = sizeof(*si); 1283 si->MaxNameLen = Symbol->MaxNameLen; 1284 if ((ret = SymFromAddr(hProcess, Address, Displacement, si))) 1285 { 1286 copy_symbolW(Symbol, si); 1287 } 1288 HeapFree(GetProcessHeap(), 0, si); 1289 return ret; 1290 } 1291 1292 /****************************************************************** 1293 * SymGetSymFromAddr (DBGHELP.@) 1294 * 1295 */ 1296 BOOL WINAPI SymGetSymFromAddr(HANDLE hProcess, DWORD Address, 1297 PDWORD Displacement, PIMAGEHLP_SYMBOL Symbol) 1298 { 1299 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 1300 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; 1301 size_t len; 1302 DWORD64 Displacement64; 1303 1304 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1305 si->SizeOfStruct = sizeof(*si); 1306 si->MaxNameLen = MAX_SYM_NAME; 1307 if (!SymFromAddr(hProcess, Address, &Displacement64, si)) 1308 return FALSE; 1309 1310 if (Displacement) 1311 *Displacement = Displacement64; 1312 Symbol->Address = si->Address; 1313 Symbol->Size = si->Size; 1314 Symbol->Flags = si->Flags; 1315 len = min(Symbol->MaxNameLength, si->MaxNameLen); 1316 lstrcpynA(Symbol->Name, si->Name, len); 1317 return TRUE; 1318 } 1319 1320 /****************************************************************** 1321 * SymGetSymFromAddr64 (DBGHELP.@) 1322 * 1323 */ 1324 BOOL WINAPI SymGetSymFromAddr64(HANDLE hProcess, DWORD64 Address, 1325 PDWORD64 Displacement, PIMAGEHLP_SYMBOL64 Symbol) 1326 { 1327 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 1328 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; 1329 size_t len; 1330 DWORD64 Displacement64; 1331 1332 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1333 si->SizeOfStruct = sizeof(*si); 1334 si->MaxNameLen = MAX_SYM_NAME; 1335 if (!SymFromAddr(hProcess, Address, &Displacement64, si)) 1336 return FALSE; 1337 1338 if (Displacement) 1339 *Displacement = Displacement64; 1340 Symbol->Address = si->Address; 1341 Symbol->Size = si->Size; 1342 Symbol->Flags = si->Flags; 1343 len = min(Symbol->MaxNameLength, si->MaxNameLen); 1344 lstrcpynA(Symbol->Name, si->Name, len); 1345 return TRUE; 1346 } 1347 1348 static BOOL find_name(struct process* pcs, struct module* module, const char* name, 1349 SYMBOL_INFO* symbol) 1350 { 1351 struct hash_table_iter hti; 1352 void* ptr; 1353 struct symt_ht* sym = NULL; 1354 struct module_pair pair; 1355 1356 pair.pcs = pcs; 1357 if (!(pair.requested = module)) return FALSE; 1358 if (!module_get_debug(&pair)) return FALSE; 1359 1360 hash_table_iter_init(&pair.effective->ht_symbols, &hti, name); 1361 while ((ptr = hash_table_iter_up(&hti))) 1362 { 1363 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt); 1364 1365 if (!strcmp(sym->hash_elt.name, name)) 1366 { 1367 symt_fill_sym_info(&pair, NULL, &sym->symt, symbol); 1368 return TRUE; 1369 } 1370 } 1371 return FALSE; 1372 1373 } 1374 /****************************************************************** 1375 * SymFromName (DBGHELP.@) 1376 * 1377 */ 1378 BOOL WINAPI SymFromName(HANDLE hProcess, PCSTR Name, PSYMBOL_INFO Symbol) 1379 { 1380 struct process* pcs = process_find_by_handle(hProcess); 1381 struct module* module; 1382 const char* name; 1383 1384 TRACE("(%p, %s, %p)\n", hProcess, Name, Symbol); 1385 if (!pcs) return FALSE; 1386 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1387 name = strchr(Name, '!'); 1388 if (name) 1389 { 1390 char tmp[128]; 1391 assert(name - Name < sizeof(tmp)); 1392 memcpy(tmp, Name, name - Name); 1393 tmp[name - Name] = '\0'; 1394 module = module_find_by_nameA(pcs, tmp); 1395 return find_name(pcs, module, name + 1, Symbol); 1396 } 1397 for (module = pcs->lmodules; module; module = module->next) 1398 { 1399 if (module->type == DMT_PE && find_name(pcs, module, Name, Symbol)) 1400 return TRUE; 1401 } 1402 /* not found in PE modules, retry on the ELF ones 1403 */ 1404 if (dbghelp_options & SYMOPT_WINE_WITH_NATIVE_MODULES) 1405 { 1406 for (module = pcs->lmodules; module; module = module->next) 1407 { 1408 if ((module->type == DMT_ELF || module->type == DMT_MACHO) && 1409 !module_get_containee(pcs, module) && 1410 find_name(pcs, module, Name, Symbol)) 1411 return TRUE; 1412 } 1413 } 1414 return FALSE; 1415 } 1416 1417 /*********************************************************************** 1418 * SymGetSymFromName64 (DBGHELP.@) 1419 */ 1420 BOOL WINAPI SymGetSymFromName64(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL64 Symbol) 1421 { 1422 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 1423 SYMBOL_INFO*si = (SYMBOL_INFO*)buffer; 1424 size_t len; 1425 1426 if (Symbol->SizeOfStruct < sizeof(*Symbol)) return FALSE; 1427 si->SizeOfStruct = sizeof(*si); 1428 si->MaxNameLen = MAX_SYM_NAME; 1429 if (!SymFromName(hProcess, Name, si)) return FALSE; 1430 1431 Symbol->Address = si->Address; 1432 Symbol->Size = si->Size; 1433 Symbol->Flags = si->Flags; 1434 len = min(Symbol->MaxNameLength, si->MaxNameLen); 1435 lstrcpynA(Symbol->Name, si->Name, len); 1436 return TRUE; 1437 } 1438 1439 /*********************************************************************** 1440 * SymGetSymFromName (DBGHELP.@) 1441 */ 1442 BOOL WINAPI SymGetSymFromName(HANDLE hProcess, PCSTR Name, PIMAGEHLP_SYMBOL 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 * sym_fill_func_line_info 1463 * 1464 * fills information about a file 1465 */ 1466 BOOL symt_fill_func_line_info(const struct module* module, const struct symt_function* func, 1467 DWORD64 addr, IMAGEHLP_LINE64* line) 1468 { 1469 struct line_info* dli = NULL; 1470 BOOL found = FALSE; 1471 int i; 1472 1473 assert(func->symt.tag == SymTagFunction); 1474 1475 for (i=vector_length(&func->vlines)-1; i>=0; i--) 1476 { 1477 dli = vector_at(&func->vlines, i); 1478 if (!dli->is_source_file) 1479 { 1480 if (found || dli->u.pc_offset > addr) continue; 1481 line->LineNumber = dli->line_number; 1482 line->Address = dli->u.pc_offset; 1483 line->Key = dli; 1484 found = TRUE; 1485 continue; 1486 } 1487 if (found) 1488 { 1489 line->FileName = (char*)source_get(module, dli->u.source_file); 1490 return TRUE; 1491 } 1492 } 1493 return FALSE; 1494 } 1495 1496 /*********************************************************************** 1497 * SymGetSymNext64 (DBGHELP.@) 1498 */ 1499 BOOL WINAPI SymGetSymNext64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) 1500 { 1501 /* algo: 1502 * get module from Symbol.Address 1503 * get index in module.addr_sorttab of Symbol.Address 1504 * increment index 1505 * if out of module bounds, move to next module in process address space 1506 */ 1507 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1508 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1509 return FALSE; 1510 } 1511 1512 /*********************************************************************** 1513 * SymGetSymNext (DBGHELP.@) 1514 */ 1515 BOOL WINAPI SymGetSymNext(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) 1516 { 1517 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1518 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1519 return FALSE; 1520 } 1521 1522 /*********************************************************************** 1523 * SymGetSymPrev64 (DBGHELP.@) 1524 */ 1525 BOOL WINAPI SymGetSymPrev64(HANDLE hProcess, PIMAGEHLP_SYMBOL64 Symbol) 1526 { 1527 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1528 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1529 return FALSE; 1530 } 1531 1532 /*********************************************************************** 1533 * SymGetSymPrev (DBGHELP.@) 1534 */ 1535 BOOL WINAPI SymGetSymPrev(HANDLE hProcess, PIMAGEHLP_SYMBOL Symbol) 1536 { 1537 FIXME("(%p, %p): stub\n", hProcess, Symbol); 1538 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 1539 return FALSE; 1540 } 1541 1542 /****************************************************************** 1543 * copy_line_64_from_32 (internal) 1544 * 1545 */ 1546 static void copy_line_64_from_32(IMAGEHLP_LINE64* l64, const IMAGEHLP_LINE* l32) 1547 1548 { 1549 l64->Key = l32->Key; 1550 l64->LineNumber = l32->LineNumber; 1551 l64->FileName = l32->FileName; 1552 l64->Address = l32->Address; 1553 } 1554 1555 /****************************************************************** 1556 * copy_line_W64_from_32 (internal) 1557 * 1558 */ 1559 static void copy_line_W64_from_64(struct process* pcs, IMAGEHLP_LINEW64* l64w, const IMAGEHLP_LINE64* l64) 1560 { 1561 unsigned len; 1562 1563 l64w->Key = l64->Key; 1564 l64w->LineNumber = l64->LineNumber; 1565 len = MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, NULL, 0); 1566 if ((l64w->FileName = fetch_buffer(pcs, len * sizeof(WCHAR)))) 1567 MultiByteToWideChar(CP_ACP, 0, l64->FileName, -1, l64w->FileName, len); 1568 l64w->Address = l64->Address; 1569 } 1570 1571 /****************************************************************** 1572 * copy_line_32_from_64 (internal) 1573 * 1574 */ 1575 static void copy_line_32_from_64(IMAGEHLP_LINE* l32, const IMAGEHLP_LINE64* l64) 1576 1577 { 1578 l32->Key = l64->Key; 1579 l32->LineNumber = l64->LineNumber; 1580 l32->FileName = l64->FileName; 1581 l32->Address = l64->Address; 1582 } 1583 1584 /****************************************************************** 1585 * SymGetLineFromAddr (DBGHELP.@) 1586 * 1587 */ 1588 BOOL WINAPI SymGetLineFromAddr(HANDLE hProcess, DWORD dwAddr, 1589 PDWORD pdwDisplacement, PIMAGEHLP_LINE Line) 1590 { 1591 IMAGEHLP_LINE64 il64; 1592 1593 il64.SizeOfStruct = sizeof(il64); 1594 if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) 1595 return FALSE; 1596 copy_line_32_from_64(Line, &il64); 1597 return TRUE; 1598 } 1599 1600 /****************************************************************** 1601 * SymGetLineFromAddr64 (DBGHELP.@) 1602 * 1603 */ 1604 BOOL WINAPI SymGetLineFromAddr64(HANDLE hProcess, DWORD64 dwAddr, 1605 PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line) 1606 { 1607 struct module_pair pair; 1608 struct symt_ht* symt; 1609 1610 TRACE("%p %s %p %p\n", hProcess, wine_dbgstr_longlong(dwAddr), pdwDisplacement, Line); 1611 1612 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; 1613 1614 pair.pcs = process_find_by_handle(hProcess); 1615 if (!pair.pcs) return FALSE; 1616 pair.requested = module_find_by_addr(pair.pcs, dwAddr, DMT_UNKNOWN); 1617 if (!module_get_debug(&pair)) return FALSE; 1618 if ((symt = symt_find_nearest(pair.effective, dwAddr)) == NULL) return FALSE; 1619 1620 if (symt->symt.tag != SymTagFunction) return FALSE; 1621 if (!symt_fill_func_line_info(pair.effective, (struct symt_function*)symt, 1622 dwAddr, Line)) return FALSE; 1623 *pdwDisplacement = dwAddr - Line->Address; 1624 return TRUE; 1625 } 1626 1627 /****************************************************************** 1628 * SymGetLineFromAddrW64 (DBGHELP.@) 1629 * 1630 */ 1631 BOOL WINAPI SymGetLineFromAddrW64(HANDLE hProcess, DWORD64 dwAddr, 1632 PDWORD pdwDisplacement, PIMAGEHLP_LINEW64 Line) 1633 { 1634 IMAGEHLP_LINE64 il64; 1635 1636 il64.SizeOfStruct = sizeof(il64); 1637 if (!SymGetLineFromAddr64(hProcess, dwAddr, pdwDisplacement, &il64)) 1638 return FALSE; 1639 copy_line_W64_from_64(process_find_by_handle(hProcess), Line, &il64); 1640 return TRUE; 1641 } 1642 1643 /****************************************************************** 1644 * SymGetLinePrev64 (DBGHELP.@) 1645 * 1646 */ 1647 BOOL WINAPI SymGetLinePrev64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) 1648 { 1649 struct module_pair pair; 1650 struct line_info* li; 1651 BOOL in_search = FALSE; 1652 1653 TRACE("(%p %p)\n", hProcess, Line); 1654 1655 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; 1656 1657 pair.pcs = process_find_by_handle(hProcess); 1658 if (!pair.pcs) return FALSE; 1659 pair.requested = module_find_by_addr(pair.pcs, Line->Address, DMT_UNKNOWN); 1660 if (!module_get_debug(&pair)) return FALSE; 1661 1662 if (Line->Key == 0) return FALSE; 1663 li = Line->Key; 1664 /* things are a bit complicated because when we encounter a DLIT_SOURCEFILE 1665 * element we have to go back until we find the prev one to get the real 1666 * source file name for the DLIT_OFFSET element just before 1667 * the first DLIT_SOURCEFILE 1668 */ 1669 while (!li->is_first) 1670 { 1671 li--; 1672 if (!li->is_source_file) 1673 { 1674 Line->LineNumber = li->line_number; 1675 Line->Address = li->u.pc_offset; 1676 Line->Key = li; 1677 if (!in_search) return TRUE; 1678 } 1679 else 1680 { 1681 if (in_search) 1682 { 1683 Line->FileName = (char*)source_get(pair.effective, li->u.source_file); 1684 return TRUE; 1685 } 1686 in_search = TRUE; 1687 } 1688 } 1689 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */ 1690 return FALSE; 1691 } 1692 1693 /****************************************************************** 1694 * SymGetLinePrev (DBGHELP.@) 1695 * 1696 */ 1697 BOOL WINAPI SymGetLinePrev(HANDLE hProcess, PIMAGEHLP_LINE Line) 1698 { 1699 IMAGEHLP_LINE64 line64; 1700 1701 line64.SizeOfStruct = sizeof(line64); 1702 copy_line_64_from_32(&line64, Line); 1703 if (!SymGetLinePrev64(hProcess, &line64)) return FALSE; 1704 copy_line_32_from_64(Line, &line64); 1705 return TRUE; 1706 } 1707 1708 BOOL symt_get_func_line_next(const struct module* module, PIMAGEHLP_LINE64 line) 1709 { 1710 struct line_info* li; 1711 1712 if (line->Key == 0) return FALSE; 1713 li = line->Key; 1714 while (!li->is_last) 1715 { 1716 li++; 1717 if (!li->is_source_file) 1718 { 1719 line->LineNumber = li->line_number; 1720 line->Address = li->u.pc_offset; 1721 line->Key = li; 1722 return TRUE; 1723 } 1724 line->FileName = (char*)source_get(module, li->u.source_file); 1725 } 1726 return FALSE; 1727 } 1728 1729 /****************************************************************** 1730 * SymGetLineNext64 (DBGHELP.@) 1731 * 1732 */ 1733 BOOL WINAPI SymGetLineNext64(HANDLE hProcess, PIMAGEHLP_LINE64 Line) 1734 { 1735 struct module_pair pair; 1736 1737 TRACE("(%p %p)\n", hProcess, Line); 1738 1739 if (Line->SizeOfStruct < sizeof(*Line)) return FALSE; 1740 pair.pcs = process_find_by_handle(hProcess); 1741 if (!pair.pcs) return FALSE; 1742 pair.requested = module_find_by_addr(pair.pcs, Line->Address, DMT_UNKNOWN); 1743 if (!module_get_debug(&pair)) return FALSE; 1744 1745 if (symt_get_func_line_next(pair.effective, Line)) return TRUE; 1746 SetLastError(ERROR_NO_MORE_ITEMS); /* FIXME */ 1747 return FALSE; 1748 } 1749 1750 /****************************************************************** 1751 * SymGetLineNext (DBGHELP.@) 1752 * 1753 */ 1754 BOOL WINAPI SymGetLineNext(HANDLE hProcess, PIMAGEHLP_LINE Line) 1755 { 1756 IMAGEHLP_LINE64 line64; 1757 1758 line64.SizeOfStruct = sizeof(line64); 1759 copy_line_64_from_32(&line64, Line); 1760 if (!SymGetLineNext64(hProcess, &line64)) return FALSE; 1761 copy_line_32_from_64(Line, &line64); 1762 return TRUE; 1763 } 1764 1765 /*********************************************************************** 1766 * SymUnDName (DBGHELP.@) 1767 */ 1768 BOOL WINAPI SymUnDName(PIMAGEHLP_SYMBOL sym, PSTR UnDecName, DWORD UnDecNameLength) 1769 { 1770 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, 1771 UNDNAME_COMPLETE) != 0; 1772 } 1773 1774 /*********************************************************************** 1775 * SymUnDName64 (DBGHELP.@) 1776 */ 1777 BOOL WINAPI SymUnDName64(PIMAGEHLP_SYMBOL64 sym, PSTR UnDecName, DWORD UnDecNameLength) 1778 { 1779 return UnDecorateSymbolName(sym->Name, UnDecName, UnDecNameLength, 1780 UNDNAME_COMPLETE) != 0; 1781 } 1782 1783 static void * CDECL und_alloc(size_t len) { return HeapAlloc(GetProcessHeap(), 0, len); } 1784 static void CDECL und_free (void* ptr) { HeapFree(GetProcessHeap(), 0, ptr); } 1785 1786 static char *und_name(char *buffer, const char *mangled, int buflen, unsigned short flags) 1787 { 1788 /* undocumented from msvcrt */ 1789 static HANDLE hMsvcrt; 1790 static char* (CDECL *p_undname)(char*, const char*, int, void* (CDECL*)(size_t), void (CDECL*)(void*), unsigned short); 1791 static const WCHAR szMsvcrt[] = {'m','s','v','c','r','t','.','d','l','l',0}; 1792 1793 if (!p_undname) 1794 { 1795 if (!hMsvcrt) hMsvcrt = LoadLibraryW(szMsvcrt); 1796 if (hMsvcrt) p_undname = (void*)GetProcAddress(hMsvcrt, "__unDName"); 1797 if (!p_undname) return NULL; 1798 } 1799 1800 return p_undname(buffer, mangled, buflen, und_alloc, und_free, flags); 1801 } 1802 1803 /*********************************************************************** 1804 * UnDecorateSymbolName (DBGHELP.@) 1805 */ 1806 DWORD WINAPI UnDecorateSymbolName(const char *decorated_name, char *undecorated_name, 1807 DWORD undecorated_length, DWORD flags) 1808 { 1809 TRACE("(%s, %p, %d, 0x%08x)\n", 1810 debugstr_a(decorated_name), undecorated_name, undecorated_length, flags); 1811 1812 if (!undecorated_name || !undecorated_length) 1813 return 0; 1814 if (!und_name(undecorated_name, decorated_name, undecorated_length, flags)) 1815 return 0; 1816 return strlen(undecorated_name); 1817 } 1818 1819 /*********************************************************************** 1820 * UnDecorateSymbolNameW (DBGHELP.@) 1821 */ 1822 DWORD WINAPI UnDecorateSymbolNameW(const WCHAR *decorated_name, WCHAR *undecorated_name, 1823 DWORD undecorated_length, DWORD flags) 1824 { 1825 char *buf, *ptr; 1826 int len, ret = 0; 1827 1828 TRACE("(%s, %p, %d, 0x%08x)\n", 1829 debugstr_w(decorated_name), undecorated_name, undecorated_length, flags); 1830 1831 if (!undecorated_name || !undecorated_length) 1832 return 0; 1833 1834 len = WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, NULL, 0, NULL, NULL); 1835 if ((buf = HeapAlloc(GetProcessHeap(), 0, len))) 1836 { 1837 WideCharToMultiByte(CP_ACP, 0, decorated_name, -1, buf, len, NULL, NULL); 1838 if ((ptr = und_name(NULL, buf, 0, flags))) 1839 { 1840 MultiByteToWideChar(CP_ACP, 0, ptr, -1, undecorated_name, undecorated_length); 1841 undecorated_name[undecorated_length - 1] = 0; 1842 ret = strlenW(undecorated_name); 1843 und_free(ptr); 1844 } 1845 HeapFree(GetProcessHeap(), 0, buf); 1846 } 1847 1848 return ret; 1849 } 1850 1851 #define WILDCHAR(x) (-(x)) 1852 1853 static int re_fetch_char(const WCHAR** re) 1854 { 1855 switch (**re) 1856 { 1857 case '\\': (*re)++; return *(*re)++; 1858 case '*': case '[': case '?': case '+': case '#': case ']': return WILDCHAR(*(*re)++); 1859 default: return *(*re)++; 1860 } 1861 } 1862 1863 static inline int re_match_char(WCHAR ch1, WCHAR ch2, BOOL _case) 1864 { 1865 return _case ? ch1 - ch2 : toupperW(ch1) - toupperW(ch2); 1866 } 1867 1868 static const WCHAR* re_match_one(const WCHAR* string, const WCHAR* elt, BOOL _case) 1869 { 1870 int ch1, prev = 0; 1871 unsigned state = 0; 1872 1873 switch (ch1 = re_fetch_char(&elt)) 1874 { 1875 default: 1876 return (ch1 >= 0 && re_match_char(*string, ch1, _case) == 0) ? ++string : NULL; 1877 case WILDCHAR('?'): return *string ? ++string : NULL; 1878 case WILDCHAR('*'): assert(0); 1879 case WILDCHAR('['): break; 1880 } 1881 1882 for (;;) 1883 { 1884 ch1 = re_fetch_char(&elt); 1885 if (ch1 == WILDCHAR(']')) return NULL; 1886 if (state == 1 && ch1 == '-') state = 2; 1887 else 1888 { 1889 if (re_match_char(*string, ch1, _case) == 0) return ++string; 1890 switch (state) 1891 { 1892 case 0: 1893 state = 1; 1894 prev = ch1; 1895 break; 1896 case 1: 1897 state = 0; 1898 break; 1899 case 2: 1900 if (prev >= 0 && ch1 >= 0 && re_match_char(prev, *string, _case) <= 0 && 1901 re_match_char(*string, ch1, _case) <= 0) 1902 return ++string; 1903 state = 0; 1904 break; 1905 } 1906 } 1907 } 1908 } 1909 1910 /****************************************************************** 1911 * re_match_multi 1912 * 1913 * match a substring of *pstring according to *pre regular expression 1914 * pstring and pre are only updated in case of successful match 1915 */ 1916 static BOOL re_match_multi(const WCHAR** pstring, const WCHAR** pre, BOOL _case) 1917 { 1918 const WCHAR* re_end = *pre; 1919 const WCHAR* string_end = *pstring; 1920 const WCHAR* re_beg; 1921 const WCHAR* string_beg; 1922 const WCHAR* next; 1923 int ch; 1924 1925 while (*re_end && *string_end) 1926 { 1927 string_beg = string_end; 1928 re_beg = re_end; 1929 switch (ch = re_fetch_char(&re_end)) 1930 { 1931 case WILDCHAR(']'): case WILDCHAR('+'): case WILDCHAR('#'): return FALSE; 1932 case WILDCHAR('*'): 1933 /* transform '*' into '?#' */ 1934 {static const WCHAR qmW[] = {'?',0}; re_beg = qmW;} 1935 goto closure; 1936 case WILDCHAR('['): 1937 do 1938 { 1939 if (!(ch = re_fetch_char(&re_end))) return FALSE; 1940 } while (ch != WILDCHAR(']')); 1941 /* fall through */ 1942 case WILDCHAR('?'): 1943 default: 1944 break; 1945 } 1946 1947 switch (*re_end) 1948 { 1949 case '+': 1950 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE; 1951 string_beg++; 1952 /* fall through */ 1953 case '#': 1954 re_end++; 1955 closure: 1956 while ((next = re_match_one(string_end, re_beg, _case))) string_end = next; 1957 for ( ; string_end >= string_beg; string_end--) 1958 { 1959 if (re_match_multi(&string_end, &re_end, _case)) goto found; 1960 } 1961 return FALSE; 1962 default: 1963 if (!(next = re_match_one(string_end, re_beg, _case))) return FALSE; 1964 string_end = next; 1965 } 1966 re_beg = re_end; 1967 } 1968 1969 if (*re_end || *string_end) return FALSE; 1970 1971 found: 1972 *pre = re_end; 1973 *pstring = string_end; 1974 return TRUE; 1975 } 1976 1977 /****************************************************************** 1978 * SymMatchStringA (DBGHELP.@) 1979 * 1980 */ 1981 BOOL WINAPI SymMatchStringA(PCSTR string, PCSTR re, BOOL _case) 1982 { 1983 WCHAR* strW; 1984 WCHAR* reW; 1985 BOOL ret = FALSE; 1986 DWORD sz; 1987 1988 if (!string || !re) 1989 { 1990 SetLastError(ERROR_INVALID_HANDLE); 1991 return FALSE; 1992 } 1993 TRACE("%s %s %c\n", string, re, _case ? 'Y' : 'N'); 1994 1995 sz = MultiByteToWideChar(CP_ACP, 0, string, -1, NULL, 0); 1996 if ((strW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 1997 MultiByteToWideChar(CP_ACP, 0, string, -1, strW, sz); 1998 sz = MultiByteToWideChar(CP_ACP, 0, re, -1, NULL, 0); 1999 if ((reW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 2000 MultiByteToWideChar(CP_ACP, 0, re, -1, reW, sz); 2001 2002 if (strW && reW) 2003 ret = SymMatchStringW(strW, reW, _case); 2004 HeapFree(GetProcessHeap(), 0, strW); 2005 HeapFree(GetProcessHeap(), 0, reW); 2006 return ret; 2007 } 2008 2009 /****************************************************************** 2010 * SymMatchStringW (DBGHELP.@) 2011 * 2012 */ 2013 BOOL WINAPI SymMatchStringW(PCWSTR string, PCWSTR re, BOOL _case) 2014 { 2015 TRACE("%s %s %c\n", debugstr_w(string), debugstr_w(re), _case ? 'Y' : 'N'); 2016 2017 if (!string || !re) 2018 { 2019 SetLastError(ERROR_INVALID_HANDLE); 2020 return FALSE; 2021 } 2022 return re_match_multi(&string, &re, _case); 2023 } 2024 2025 static inline BOOL doSymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, 2026 DWORD SymTag, PCWSTR Mask, DWORD64 Address, 2027 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 2028 PVOID UserContext, DWORD Options) 2029 { 2030 struct sym_enum se; 2031 2032 if (Options != SYMSEARCH_GLOBALSONLY) 2033 { 2034 FIXME("Unsupported searching with options (%x)\n", Options); 2035 SetLastError(ERROR_INVALID_PARAMETER); 2036 return FALSE; 2037 } 2038 2039 se.cb = EnumSymbolsCallback; 2040 se.user = UserContext; 2041 se.index = Index; 2042 se.tag = SymTag; 2043 se.addr = Address; 2044 se.sym_info = (PSYMBOL_INFO)se.buffer; 2045 2046 return sym_enum(hProcess, BaseOfDll, Mask, &se); 2047 } 2048 2049 /****************************************************************** 2050 * SymSearch (DBGHELP.@) 2051 */ 2052 BOOL WINAPI SymSearch(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, 2053 DWORD SymTag, PCSTR Mask, DWORD64 Address, 2054 PSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, 2055 PVOID UserContext, DWORD Options) 2056 { 2057 LPWSTR maskW = NULL; 2058 BOOLEAN ret; 2059 2060 TRACE("(%p %s %u %u %s %s %p %p %x)\n", 2061 hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, Mask, 2062 wine_dbgstr_longlong(Address), EnumSymbolsCallback, 2063 UserContext, Options); 2064 2065 if (Mask) 2066 { 2067 DWORD sz = MultiByteToWideChar(CP_ACP, 0, Mask, -1, NULL, 0); 2068 2069 if (!(maskW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 2070 return FALSE; 2071 MultiByteToWideChar(CP_ACP, 0, Mask, -1, maskW, sz); 2072 } 2073 ret = doSymSearch(hProcess, BaseOfDll, Index, SymTag, maskW, Address, 2074 EnumSymbolsCallback, UserContext, Options); 2075 HeapFree(GetProcessHeap(), 0, maskW); 2076 return ret; 2077 } 2078 2079 /****************************************************************** 2080 * SymSearchW (DBGHELP.@) 2081 */ 2082 BOOL WINAPI SymSearchW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD Index, 2083 DWORD SymTag, PCWSTR Mask, DWORD64 Address, 2084 PSYM_ENUMERATESYMBOLS_CALLBACKW EnumSymbolsCallback, 2085 PVOID UserContext, DWORD Options) 2086 { 2087 struct sym_enumW sew; 2088 2089 TRACE("(%p %s %u %u %s %s %p %p %x)\n", 2090 hProcess, wine_dbgstr_longlong(BaseOfDll), Index, SymTag, debugstr_w(Mask), 2091 wine_dbgstr_longlong(Address), EnumSymbolsCallback, 2092 UserContext, Options); 2093 2094 sew.ctx = UserContext; 2095 sew.cb = EnumSymbolsCallback; 2096 sew.sym_info = (PSYMBOL_INFOW)sew.buffer; 2097 2098 return doSymSearch(hProcess, BaseOfDll, Index, SymTag, Mask, Address, 2099 sym_enumW, &sew, Options); 2100 } 2101 2102 /****************************************************************** 2103 * SymAddSymbol (DBGHELP.@) 2104 * 2105 */ 2106 BOOL WINAPI SymAddSymbol(HANDLE hProcess, ULONG64 BaseOfDll, PCSTR name, 2107 DWORD64 addr, DWORD size, DWORD flags) 2108 { 2109 WCHAR nameW[MAX_SYM_NAME]; 2110 2111 MultiByteToWideChar(CP_ACP, 0, name, -1, nameW, ARRAY_SIZE(nameW)); 2112 return SymAddSymbolW(hProcess, BaseOfDll, nameW, addr, size, flags); 2113 } 2114 2115 /****************************************************************** 2116 * SymAddSymbolW (DBGHELP.@) 2117 * 2118 */ 2119 BOOL WINAPI SymAddSymbolW(HANDLE hProcess, ULONG64 BaseOfDll, PCWSTR name, 2120 DWORD64 addr, DWORD size, DWORD flags) 2121 { 2122 struct module_pair pair; 2123 2124 TRACE("(%p %s %s %u)\n", hProcess, wine_dbgstr_w(name), wine_dbgstr_longlong(addr), size); 2125 2126 pair.pcs = process_find_by_handle(hProcess); 2127 if (!pair.pcs) return FALSE; 2128 pair.requested = module_find_by_addr(pair.pcs, BaseOfDll, DMT_UNKNOWN); 2129 if (!module_get_debug(&pair)) return FALSE; 2130 2131 SetLastError(ERROR_CALL_NOT_IMPLEMENTED); 2132 return FALSE; 2133 } 2134 2135 /****************************************************************** 2136 * SymSetScopeFromAddr (DBGHELP.@) 2137 */ 2138 BOOL WINAPI SymSetScopeFromAddr(HANDLE hProcess, ULONG64 addr) 2139 { 2140 struct process* pcs; 2141 2142 FIXME("(%p %s): stub\n", hProcess, wine_dbgstr_longlong(addr)); 2143 2144 if (!(pcs = process_find_by_handle(hProcess))) return FALSE; 2145 return TRUE; 2146 } 2147 2148 /****************************************************************** 2149 * SymEnumLines (DBGHELP.@) 2150 * 2151 */ 2152 BOOL WINAPI SymEnumLines(HANDLE hProcess, ULONG64 base, PCSTR compiland, 2153 PCSTR srcfile, PSYM_ENUMLINES_CALLBACK cb, PVOID user) 2154 { 2155 struct module_pair pair; 2156 struct hash_table_iter hti; 2157 struct symt_ht* sym; 2158 WCHAR* srcmask; 2159 struct line_info* dli; 2160 void* ptr; 2161 SRCCODEINFO sci; 2162 const char* file; 2163 2164 if (!cb) return FALSE; 2165 if (!(dbghelp_options & SYMOPT_LOAD_LINES)) return TRUE; 2166 2167 pair.pcs = process_find_by_handle(hProcess); 2168 if (!pair.pcs) return FALSE; 2169 if (compiland) FIXME("Unsupported yet (filtering on compiland %s)\n", compiland); 2170 pair.requested = module_find_by_addr(pair.pcs, base, DMT_UNKNOWN); 2171 if (!module_get_debug(&pair)) return FALSE; 2172 if (!(srcmask = file_regex(srcfile))) return FALSE; 2173 2174 sci.SizeOfStruct = sizeof(sci); 2175 sci.ModBase = base; 2176 2177 hash_table_iter_init(&pair.effective->ht_symbols, &hti, NULL); 2178 while ((ptr = hash_table_iter_up(&hti))) 2179 { 2180 unsigned int i; 2181 2182 sym = CONTAINING_RECORD(ptr, struct symt_ht, hash_elt); 2183 if (sym->symt.tag != SymTagFunction) continue; 2184 2185 sci.FileName[0] = '\0'; 2186 for (i=0; i<vector_length(&((struct symt_function*)sym)->vlines); i++) 2187 { 2188 dli = vector_at(&((struct symt_function*)sym)->vlines, i); 2189 if (dli->is_source_file) 2190 { 2191 file = source_get(pair.effective, dli->u.source_file); 2192 if (!file) sci.FileName[0] = '\0'; 2193 else 2194 { 2195 DWORD sz = MultiByteToWideChar(CP_ACP, 0, file, -1, NULL, 0); 2196 WCHAR* fileW; 2197 2198 if ((fileW = HeapAlloc(GetProcessHeap(), 0, sz * sizeof(WCHAR)))) 2199 MultiByteToWideChar(CP_ACP, 0, file, -1, fileW, sz); 2200 if (SymMatchStringW(fileW, srcmask, FALSE)) 2201 strcpy(sci.FileName, file); 2202 else 2203 sci.FileName[0] = '\0'; 2204 HeapFree(GetProcessHeap(), 0, fileW); 2205 } 2206 } 2207 else if (sci.FileName[0]) 2208 { 2209 sci.Key = dli; 2210 sci.Obj[0] = '\0'; /* FIXME */ 2211 sci.LineNumber = dli->line_number; 2212 sci.Address = dli->u.pc_offset; 2213 if (!cb(&sci, user)) break; 2214 } 2215 } 2216 } 2217 HeapFree(GetProcessHeap(), 0, srcmask); 2218 return TRUE; 2219 } 2220 2221 BOOL WINAPI SymGetLineFromName(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, 2222 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINE Line) 2223 { 2224 FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, 2225 dwLineNumber, plDisplacement, Line); 2226 return FALSE; 2227 } 2228 2229 BOOL WINAPI SymGetLineFromName64(HANDLE hProcess, PCSTR ModuleName, PCSTR FileName, 2230 DWORD dwLineNumber, PLONG lpDisplacement, PIMAGEHLP_LINE64 Line) 2231 { 2232 FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, ModuleName, FileName, 2233 dwLineNumber, lpDisplacement, Line); 2234 return FALSE; 2235 } 2236 2237 BOOL WINAPI SymGetLineFromNameW64(HANDLE hProcess, PCWSTR ModuleName, PCWSTR FileName, 2238 DWORD dwLineNumber, PLONG plDisplacement, PIMAGEHLP_LINEW64 Line) 2239 { 2240 FIXME("(%p) (%s, %s, %d %p %p): stub\n", hProcess, debugstr_w(ModuleName), debugstr_w(FileName), 2241 dwLineNumber, plDisplacement, Line); 2242 return FALSE; 2243 } 2244 2245 /****************************************************************** 2246 * SymFromIndex (DBGHELP.@) 2247 * 2248 */ 2249 BOOL WINAPI SymFromIndex(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFO symbol) 2250 { 2251 FIXME("hProcess = %p, BaseOfDll = %s, index = %d, symbol = %p\n", 2252 hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol); 2253 2254 return FALSE; 2255 } 2256 2257 /****************************************************************** 2258 * SymFromIndexW (DBGHELP.@) 2259 * 2260 */ 2261 BOOL WINAPI SymFromIndexW(HANDLE hProcess, ULONG64 BaseOfDll, DWORD index, PSYMBOL_INFOW symbol) 2262 { 2263 FIXME("hProcess = %p, BaseOfDll = %s, index = %d, symbol = %p\n", 2264 hProcess, wine_dbgstr_longlong(BaseOfDll), index, symbol); 2265 2266 return FALSE; 2267 } 2268 2269 /****************************************************************** 2270 * SymSetHomeDirectory (DBGHELP.@) 2271 * 2272 */ 2273 PCHAR WINAPI SymSetHomeDirectory(HANDLE hProcess, PCSTR dir) 2274 { 2275 FIXME("(%p, %s): stub\n", hProcess, dir); 2276 2277 return NULL; 2278 } 2279 2280 /****************************************************************** 2281 * SymSetHomeDirectoryW (DBGHELP.@) 2282 * 2283 */ 2284 PWSTR WINAPI SymSetHomeDirectoryW(HANDLE hProcess, PCWSTR dir) 2285 { 2286 FIXME("(%p, %s): stub\n", hProcess, debugstr_w(dir)); 2287 2288 return NULL; 2289 } 2290