-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathcalc-offsets.py
74 lines (61 loc) · 2.68 KB
/
calc-offsets.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/env python
#
# calc-offsets.py <pid> <native image name>
# e.g. calc-offsets.py 1234 sample-netcore-app.ni.exe
#
# Parses /tmp/<pid>/maps and /tmp/<native image name map> file and dumps a list
# of offsets for all methods in the native image map file generated by crossgen.
# These offsets are then usable in tools like perf and bcc for dynamic tracing
#
import argparse
import os
import re
import subprocess
class Section(object):
def __init__(self, start, end, perms, offset, path):
self.start = int(start, 16)
self.end = int(end, 16)
self.perms = perms
self.offset = int(offset, 16)
self.path = path
def all_sections(pid):
sections = {}
with open("/proc/%d/maps" % pid, "r") as maps:
for line in maps:
match = re.match(r"(\S+)-(\S+)\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+(\S+)", line.strip())
if match is None:
continue
start, end, perms, offset, path = match.group(1, 2, 3, 4, 5)
if '/' not in path:
continue
filename = os.path.basename(path)
section = Section(start, end, perms, offset, path)
if filename in sections:
sections[filename].append(section)
else:
sections[filename] = [section]
return sections
parser = argparse.ArgumentParser(description="Place dynamic tracing probes on a managed method " +
"that resides in a crossgen-compiled assembly. For .NET Core on Linux.",
epilog="EXAMPLE: ./place-probe.py 1234 sample-netcore-app.ni.exe")
parser.add_argument("pid", type=int, help="the dotnet process id")
parser.add_argument("nativeimage", type=str, help="name of the native image generated by crossgen")
args = parser.parse_args()
sections = all_sections(args.pid)
output = subprocess.check_output("cat /tmp/%s*map" % os.path.splitext(args.nativeimage)[0], shell=True)
assembly = args.nativeimage
for line in output.strip().split('\n'):
parts = line.split()
address = int(parts[0], 16)
symbol = str.join(' ', parts[2:])
first_section = sections[assembly][0]
# exec section has to be be executable and contain the method in question
exec_section = [section for section in sections[assembly]
if 'r-xp' == section.perms and
(section.start - first_section.start) < address and
(section.end - first_section.start) > address][0]
offset_from_first = exec_section.start - first_section.start
offset_in_file = exec_section.offset
final_address = address - offset_from_first + offset_in_file
print("offset: %x : %s" %
(final_address, ' '.join(parts[2:]) ))