|
1 | 1 | #include "gdbmiadapter.h" |
2 | 2 | #include <regex> |
| 3 | +#include <sstream> |
| 4 | +#include <map> |
3 | 5 | #include "../debuggercontroller.h" // Assuming this path is correct for your project structure |
4 | 6 | #include "../../cli/log.h" // For Log::print |
5 | 7 |
|
@@ -774,7 +776,161 @@ std::vector<DebugModule> GdbMiAdapter::GetModuleList() |
774 | 776 | if (!m_mi) |
775 | 777 | return {}; |
776 | 778 |
|
| 779 | + // Use -interpreter-exec to run the console command "info proc mappings" |
| 780 | + auto result = m_mi->SendCommand("-interpreter-exec console \"info proc mappings\""); |
| 781 | + if (result.command != "done") |
| 782 | + { |
| 783 | + LogWarn("Failed to get process mappings: %s", result.fullLine.c_str()); |
| 784 | + return {}; |
| 785 | + } |
| 786 | + |
777 | 787 | std::vector<DebugModule> modules; |
| 788 | + std::map<std::string, int> moduleNameCount; // Track module name occurrences for duplicates |
| 789 | + std::map<std::string, std::vector<std::pair<uint64_t, uint64_t>>> moduleRanges; // path -> list of (start, end) |
| 790 | + std::vector<std::string> moduleOrder; // Track the order in which modules are first seen |
| 791 | + |
| 792 | + // Parse the console output from async records |
| 793 | + // The output will be in console stream records ('~') |
| 794 | + // We need to accumulate the console output and parse it |
| 795 | + // For now, we'll try to parse from the result payload if available |
| 796 | + |
| 797 | + // Since the output is sent as console stream, we need a different approach. |
| 798 | + // Let's send the command and wait for console output. |
| 799 | + // Actually, the console output should be in the async records. |
| 800 | + // For simplicity, let's use InvokeBackendCommand which also uses -interpreter-exec |
| 801 | + std::string output = InvokeBackendCommand("info proc mappings"); |
| 802 | + |
| 803 | + if (output.empty() || output == "error, transport not ready") |
| 804 | + { |
| 805 | + LogWarn("Failed to get process mappings output"); |
| 806 | + return {}; |
| 807 | + } |
| 808 | + |
| 809 | + // Parse the output line by line |
| 810 | + // Expected format (from the issue): |
| 811 | + // process 25443 |
| 812 | + // Mapped address spaces: |
| 813 | + // |
| 814 | + // Start Addr End Addr Size Offset Perms objfile |
| 815 | + // 0x555555554000 0x555555555000 0x1000 0x0 r--p /path/to/file |
| 816 | + |
| 817 | + std::istringstream stream(output); |
| 818 | + std::string line; |
| 819 | + bool headerFound = false; |
| 820 | + |
| 821 | + while (std::getline(stream, line)) |
| 822 | + { |
| 823 | + // Skip until we find the header line |
| 824 | + if (!headerFound) |
| 825 | + { |
| 826 | + if (line.find("Start Addr") != std::string::npos && |
| 827 | + line.find("End Addr") != std::string::npos) |
| 828 | + { |
| 829 | + headerFound = true; |
| 830 | + } |
| 831 | + continue; |
| 832 | + } |
| 833 | + |
| 834 | + // Parse data lines |
| 835 | + // Format: Start_Addr End_Addr Size Offset Perms objfile |
| 836 | + std::istringstream lineStream(line); |
| 837 | + std::string startStr, endStr, sizeStr, offsetStr, perms, objfile; |
| 838 | + |
| 839 | + lineStream >> startStr >> endStr >> sizeStr >> offsetStr >> perms; |
| 840 | + |
| 841 | + // Rest of the line is the objfile (path) |
| 842 | + std::getline(lineStream, objfile); |
| 843 | + |
| 844 | + // Trim leading whitespace from objfile |
| 845 | + size_t firstNonSpace = objfile.find_first_not_of(" \t"); |
| 846 | + if (firstNonSpace != std::string::npos) |
| 847 | + { |
| 848 | + objfile = objfile.substr(firstNonSpace); |
| 849 | + } |
| 850 | + |
| 851 | + // Skip lines without valid addresses or without objfile |
| 852 | + if (startStr.empty() || endStr.empty() || objfile.empty()) |
| 853 | + continue; |
| 854 | + |
| 855 | + // Skip special mappings like [stack], [heap], [vvar], [vdso], etc. |
| 856 | + if (objfile[0] == '[') |
| 857 | + continue; |
| 858 | + |
| 859 | + try |
| 860 | + { |
| 861 | + uint64_t start = std::stoull(startStr, nullptr, 16); |
| 862 | + uint64_t end = std::stoull(endStr, nullptr, 16); |
| 863 | + |
| 864 | + // Track the order of first occurrence |
| 865 | + if (moduleRanges.find(objfile) == moduleRanges.end()) |
| 866 | + { |
| 867 | + moduleOrder.push_back(objfile); |
| 868 | + } |
| 869 | + |
| 870 | + // Accumulate ranges for each object file |
| 871 | + moduleRanges[objfile].emplace_back(start, end); |
| 872 | + } |
| 873 | + catch (const std::exception& e) |
| 874 | + { |
| 875 | + LogDebug("Failed to parse address range: %s", e.what()); |
| 876 | + continue; |
| 877 | + } |
| 878 | + } |
| 879 | + |
| 880 | + // Now create DebugModule entries in the order they were first encountered |
| 881 | + // For each unique object file, we need to determine its overall address range |
| 882 | + for (const auto& path : moduleOrder) |
| 883 | + { |
| 884 | + const auto& ranges = moduleRanges[path]; |
| 885 | + if (ranges.empty()) |
| 886 | + continue; |
| 887 | + |
| 888 | + // Find the minimum start and maximum end |
| 889 | + uint64_t minStart = ranges[0].first; |
| 890 | + uint64_t maxEnd = ranges[0].second; |
| 891 | + |
| 892 | + for (const auto& [start, end] : ranges) |
| 893 | + { |
| 894 | + minStart = std::min(minStart, start); |
| 895 | + maxEnd = std::max(maxEnd, end); |
| 896 | + } |
| 897 | + |
| 898 | + // Extract the base name from the path for m_short_name |
| 899 | + std::string shortName = path; |
| 900 | + size_t lastSlash = path.find_last_of("/\\"); |
| 901 | + if (lastSlash != std::string::npos) |
| 902 | + { |
| 903 | + shortName = path.substr(lastSlash + 1); |
| 904 | + } |
| 905 | + |
| 906 | + // Handle duplicate names by appending -1, -2, etc. |
| 907 | + // The first occurrence gets the original name, subsequent ones get -1, -2, etc. |
| 908 | + std::string finalName = path; |
| 909 | + if (moduleNameCount.find(path) != moduleNameCount.end()) |
| 910 | + { |
| 911 | + // This is a duplicate (shouldn't happen with current logic, but keep for safety) |
| 912 | + int count = ++moduleNameCount[path]; |
| 913 | + finalName = path + "-" + std::to_string(count); |
| 914 | + } |
| 915 | + else |
| 916 | + { |
| 917 | + // First occurrence |
| 918 | + moduleNameCount[path] = 0; |
| 919 | + } |
| 920 | + |
| 921 | + DebugModule module; |
| 922 | + module.m_name = finalName; |
| 923 | + module.m_short_name = shortName; |
| 924 | + module.m_address = minStart; |
| 925 | + module.m_size = maxEnd - minStart; |
| 926 | + module.m_loaded = true; |
| 927 | + |
| 928 | + modules.push_back(module); |
| 929 | + } |
| 930 | + |
| 931 | + return modules; |
| 932 | +} |
| 933 | + |
778 | 934 | return modules; |
779 | 935 | } |
780 | 936 |
|
|
0 commit comments