Skip to content

Commit

Permalink
Get modules information using proc_pidinfo() on macOS (#42900)
Browse files Browse the repository at this point in the history
Previously CreateProcessModules() parsed the output of vmmap command to get
modules addresses/paths on macOS, but on some Macs with latest macOS 10.15.6
vmmap hides full paths to some process modules (.dylibs in non-system folders),
replacing some parts with *:
```
__TEXT                 000000010d8bd000-000000010ddce000 [ 5188K  5188K     0K     0K] r-x/rwx SM=COW          /Users/USER/*/libcoreclr.dylib
```

In particular, it breaks the debugger functionality due to invalid path
`/Users/USER/*/libmscordbi.dylib`, and error code
CORDBG_E_DEBUG_COMPONENT_MISSING is returned.

Now we get modules information by iterating over regions using proc_pidinfo()
in CreateProcessModules().

Fixes #42888
  • Loading branch information
k15tfu committed Oct 12, 2020
1 parent 912e88d commit b099ab3
Showing 1 changed file with 42 additions and 43 deletions.
85 changes: 42 additions & 43 deletions src/coreclr/src/pal/src/thread/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d
#endif

#ifdef __APPLE__
#include <libproc.h>
#include <sys/sysctl.h>
#include <sys/posix_sem.h>
#endif
Expand Down Expand Up @@ -2851,65 +2852,63 @@ CreateProcessModules(

// NOTE: the module path can have spaces in the name
// __TEXT 0000000196220000-00000001965b4000 [ 3664K 2340K 0K 0K] r-x/rwx SM=COW /Volumes/Builds/builds/devmain/rawproduct/debug/build/out/Applications/Microsoft Excel.app/Contents/SharedSupport/PowerQuery/libcoreclr.dylib
char *line = NULL;
size_t lineLen = 0;
int count = 0;
ssize_t read;

char vmmapCommand[100];
int chars = snprintf(vmmapCommand, sizeof(vmmapCommand), "/usr/bin/vmmap -interleaved %d -wide", dwProcessId);
_ASSERTE(chars > 0 && chars <= sizeof(vmmapCommand));
// NOTE: Sometimes vmmap hides full paths to some process modules (.dylibs in non-system folders), causing debugger not to work.
// __TEXT 000000010d8bd000-000000010ddce000 [ 5188K 5188K 0K 0K] r-x/rwx SM=COW /Users/USER/*/libcoreclr.dylib
// So now we get modules information by iterating over regions using proc_pidinfo(). See dotnet/runtime#42888.
int count = 0;

FILE *vmmapFile = popen(vmmapCommand, "r");
if (vmmapFile == NULL)
uint64_t addr = 0;
while (true)
{
goto exit;
}
struct proc_regionwithpathinfo rwpi;
int sz = proc_pidinfo(dwProcessId, PROC_PIDREGIONPATHINFO, addr, &rwpi, sizeof rwpi);
if (sz != sizeof rwpi)
{
if (sz == 0 && errno == EINVAL)
break; // ok

// Reading maps file line by line
while ((read = getline(&line, &lineLen, vmmapFile)) != -1)
{
void *startAddress, *endAddress;
char moduleName[PATH_MAX];
DestroyProcessModules(listHead);
listHead = NULL;
count = 0;
break; // unknown error
}

const char *moduleName = rwpi.prp_vip.vip_path;

if (sscanf_s(line, "__TEXT %p-%p [ %*[0-9K ]] %*[-/rwxsp] SM=%*[A-Z] %[^\n]", &startAddress, &endAddress, moduleName, _countof(moduleName)) == 3)
bool dup = false;
for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
{
bool dup = false;
for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
if (strcmp(moduleName, entry->Name) == 0)
{
if (strcmp(moduleName, entry->Name) == 0)
{
dup = true;
break;
}
dup = true;
break;
}
}

if (!dup)
if (!dup)
{
int cbModuleName = strlen(moduleName) + 1;
ProcessModules *entry = (ProcessModules *)InternalMalloc(sizeof(ProcessModules) + cbModuleName);
if (entry == NULL)
{
int cbModuleName = strlen(moduleName) + 1;
ProcessModules *entry = (ProcessModules *)InternalMalloc(sizeof(ProcessModules) + cbModuleName);
if (entry == NULL)
{
DestroyProcessModules(listHead);
listHead = NULL;
count = 0;
break;
}
strcpy_s(entry->Name, cbModuleName, moduleName);
entry->BaseAddress = startAddress;
entry->Next = listHead;
listHead = entry;
count++;
DestroyProcessModules(listHead);
listHead = NULL;
count = 0;
break; // no memory
}
memcpy_s(entry->Name, cbModuleName, moduleName, cbModuleName);
entry->BaseAddress = (void *)rwpi.prp_prinfo.pri_address;
entry->Next = listHead;
listHead = entry;
count++;
}

addr = rwpi.prp_prinfo.pri_address + rwpi.prp_prinfo.pri_size;
}

*lpCount = count;

free(line); // We didn't allocate line, but as per contract of getline we should free it
pclose(vmmapFile);
exit:

#elif HAVE_PROCFS_MAPS

// Here we read /proc/<pid>/maps file in order to parse it and figure out what it says
Expand Down

0 comments on commit b099ab3

Please sign in to comment.