Guest User

Untitled

a guest
Feb 20th, 2018
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.21 KB | None | 0 0
  1. #!/usr/bin/env python
  2. #
  3. # USAGE: place-probe [-h] [--dry-run] [--debug] PID METHOD
  4. #
  5. # This tool helps place dynamic probes on .NET methods that were
  6. # CrossGen-generated (compiled ahead of time). To use the tool,
  7. # the CrossGen-generated assemblies need to have perfmaps generated
  8. # by CrossGen /CreatePerfMap, expected in the /tmp directory.
  9. #
  10. # Copyright (C) 2018, Sasha Goldshtein
  11. # Licensed under the MIT License
  12.  
  13. import argparse
  14. import os
  15. import re
  16. import subprocess
  17.  
  18. class Section(object):
  19. def __init__(self, start, perms, offset, path):
  20. self.start = int(start, 16)
  21. self.perms = perms
  22. self.offset = int(offset, 16)
  23. self.path = path
  24.  
  25. def assembly_from_map_file(map_file):
  26. return re.match("/tmp/(.*)\.ni\.{.*}.map", map_file).group(1) + ".dll"
  27.  
  28. def all_sections(pid):
  29. sections = {}
  30. with open("/proc/%d/maps" % pid, "r") as maps:
  31. for line in maps:
  32. match = re.match(r"(\S+)-\S+\s+(\S+)\s+(\S+)\s+\S+\s+\S+\s+(\S+)", line.strip())
  33. if match is None:
  34. continue
  35. start, perms, offset, path = match.group(1, 2, 3, 4)
  36. if '/' not in path:
  37. continue
  38. filename = os.path.basename(path)
  39. section = Section(start, perms, offset, path)
  40. if filename in sections:
  41. sections[filename].append(section)
  42. else:
  43. sections[filename] = [section]
  44. return sections
  45.  
  46. def place_probe(path, offset):
  47. command = "sudo perf probe -x %s --add 0x%x" % (path, offset)
  48. if args.dry_run:
  49. print(command)
  50. else:
  51. subprocess.check_call(command, shell=True)
  52.  
  53. parser = argparse.ArgumentParser(description="Place dynamic tracing probes on a managed method " +
  54. "that resides in a crossgen-compiled assembly. For .NET Core on Linux.",
  55. epilog="EXAMPLE: ./place-probe.py 1234 'Thread::Sleep'")
  56. parser.add_argument("pid", type=int, help="the dotnet process id")
  57. parser.add_argument("symbol", type=str, help="the symbol on which to place the probe")
  58. parser.add_argument("--dry-run", action="store_true",
  59. help="print the symbol and the command but don't place the probe")
  60. parser.add_argument("--debug", action="store_true", help="print diagnostic information")
  61. args = parser.parse_args()
  62.  
  63. sections = all_sections(args.pid)
  64.  
  65. output = subprocess.check_output("grep '%s' /tmp/*.ni.*.map" % args.symbol,
  66. shell=True)
  67. for line in output.strip().split('\n'):
  68. parts = line.split()
  69. map_file, address = parts[0].split(':')
  70. address = int(address, 16)
  71. assembly = assembly_from_map_file(map_file)
  72.  
  73. symbol = str.join(' ', parts[2:])
  74. if args.dry_run:
  75. print("\n" + symbol)
  76.  
  77. first_section = sections[assembly][0]
  78. exec_section = [section for section in sections[assembly] if 'r-xp' == section.perms][0]
  79. offset_from_first = exec_section.start - first_section.start
  80. offset_in_file = exec_section.offset
  81. final_address = address - offset_from_first + offset_in_file
  82.  
  83. if args.debug:
  84. print("address: %x, offset_from_first: %x, offset_in_file: %x, final_address: %x" %
  85. (address, offset_from_first, offset_in_file, final_address))
  86.  
  87. place_probe(exec_section.path, final_address)
Add Comment
Please, Sign In to add comment