Iterates over all the modules currently loaded by the executable, according to windows, and makes sure they're all patched. Most modules will already be in loaded_modules, meaning we have already loaded and either patched them or determined they did not need to be patched. Others will not, which means we need to patch them (if necessary). Finally, we have to go through the existing g_module_lib
| 677 | // false if we were a noop. May update loaded_modules as well. |
| 678 | // NOTE: you must hold the patch_all_modules_lock to access loaded_modules. |
| 679 | bool PatchAllModules() { |
| 680 | std::vector<ModuleEntryCopy> modules; |
| 681 | bool made_changes = false; |
| 682 | |
| 683 | const HANDLE hCurrentProcess = GetCurrentProcess(); |
| 684 | DWORD num_modules = 0; |
| 685 | HMODULE hModules[kMaxModules]; // max # of modules we support in one process |
| 686 | if (!::EnumProcessModules(hCurrentProcess, hModules, sizeof(hModules), |
| 687 | &num_modules)) { |
| 688 | num_modules = 0; |
| 689 | } |
| 690 | // EnumProcessModules actually set the bytes written into hModules, |
| 691 | // so we need to divide to make num_modules actually be a module-count. |
| 692 | num_modules /= sizeof(*hModules); |
| 693 | if (num_modules >= kMaxModules) { |
| 694 | printf("PERFTOOLS ERROR: Too many modules in this executable to try" |
| 695 | " to patch them all (if you need to, raise kMaxModules in" |
| 696 | " patch_functions.cc).\n"); |
| 697 | num_modules = kMaxModules; |
| 698 | } |
| 699 | |
| 700 | // Now we handle the unpatching of modules we have in g_module_libcs |
| 701 | // but that were not found in EnumProcessModules. We need to |
| 702 | // invalidate them. To speed that up, we store the EnumProcessModules |
| 703 | // output in a set. |
| 704 | // At the same time, we prepare for the adding of new modules, by |
| 705 | // removing from hModules all the modules we know we've already |
| 706 | // patched (or decided don't need to be patched). At the end, |
| 707 | // hModules will hold only the modules that we need to consider patching. |
| 708 | std::set<HMODULE> currently_loaded_modules; |
| 709 | { |
| 710 | SpinLockHolder h(&patch_all_modules_lock); |
| 711 | if (!g_last_loaded) g_last_loaded = new std::set<HMODULE>; |
| 712 | // At the end of this loop, currently_loaded_modules contains the |
| 713 | // full list of EnumProcessModules, and hModules just the ones we |
| 714 | // haven't handled yet. |
| 715 | for (int i = 0; i < num_modules; ) { |
| 716 | currently_loaded_modules.insert(hModules[i]); |
| 717 | if (g_last_loaded->count(hModules[i]) > 0) { |
| 718 | hModules[i] = hModules[--num_modules]; // replace element i with tail |
| 719 | } else { |
| 720 | i++; // keep element i |
| 721 | } |
| 722 | } |
| 723 | // Now we do the unpatching/invalidation. |
| 724 | for (int i = 0; i < sizeof(g_module_libcs)/sizeof(*g_module_libcs); i++) { |
| 725 | if (g_module_libcs[i]->patched() && |
| 726 | currently_loaded_modules.count(g_module_libcs[i]->hmodule()) == 0) { |
| 727 | // Means g_module_libcs[i] is no longer loaded (no me32 matched). |
| 728 | // We could call Unpatch() here, but why bother? The module |
| 729 | // has gone away, so nobody is going to call into it anyway. |
| 730 | g_module_libcs[i]->set_is_valid(false); |
| 731 | made_changes = true; |
| 732 | } |
| 733 | } |
| 734 | // Update the loaded module cache. |
| 735 | g_last_loaded->swap(currently_loaded_modules); |
| 736 | } |
no test coverage detected