mono_attach_load_agent: Fix leaks, alloc, copy. (#15950)
[mono-project.git] / mcs / class / Mono.Management / Mono.Attach / VirtualMachine.cs
blobab2371364bc8adbdfbcab2b6bbddf3795799c3e3
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Runtime.InteropServices;
5 using System.Text;
6 using System.IO;
7 using System.Threading;
8 using System.Net;
9 using System.Net.Sockets;
11 using Mono.Unix;
12 using Mono.Unix.Native;
14 namespace Mono.Attach
17 * Represents a running mono virtual machine.
19 public class VirtualMachine {
21 long pid;
23 public VirtualMachine (long pid) {
24 // FIXME: Check for unix
25 this.pid = pid;
28 public long Pid {
29 get {
30 return pid;
34 public bool IsCurrent {
35 get {
36 return pid == Syscall.getpid ();
40 public string[] GetCommandLine () {
41 return File.OpenText ("/proc/" + pid + "/cmdline").ReadToEnd ().Split ('\0');
44 public string GetWorkingDirectory () {
45 return UnixPath.ReadLink ("/proc/" + pid + "/cwd");
49 * Return the list of running mono vms owned by the current user. The
50 * result includes the current vm too.
52 public static List<VirtualMachine> GetVirtualMachines () {
53 PerformanceCounterCategory p = new PerformanceCounterCategory (".NET CLR JIT");
54 string[] machines = p.GetInstanceNames ();
56 var res = new List<VirtualMachine> ();
58 foreach (string s in machines) {
59 // The names are in the form 'pid/name'
60 int pos = s.IndexOf ('/');
61 if (pos != -1)
62 res.Add (new VirtualMachine (Int32.Parse (s.Substring (0, pos))));
64 return res;
68 * Loads the specific agent assembly into this vm.
70 public void Attach (string agent, string args) {
71 string user = UnixUserInfo.GetRealUser ().UserName;
73 // Check whenever the attach socket exists
74 string socket_file = "/tmp/mono-" + user + "/.mono-" + pid;
76 if (!File.Exists (socket_file)) {
77 string trigger_file = "/tmp/.mono_attach_pid" + pid;
78 FileStream trigger = null;
80 try {
81 trigger = File.Create (trigger_file);
82 trigger.Close ();
84 // Ask the vm to start the attach mechanism
85 Syscall.kill ((int)pid, Signum.SIGQUIT);
87 // Wait for the socket file to materialize
88 int i;
89 for (i = 0; i < 10; ++i) {
90 if (File.Exists (socket_file))
91 break;
92 Thread.Sleep (100);
95 if (i == 10)
96 throw new Exception (String.Format ("Runtime failed to create attach socket '{0}'.", socket_file));
97 } finally {
98 File.Delete (trigger_file);
103 * We communicate with the agent inside the runtime using a simlified
104 * version of the .net remoting protocol.
107 string path = "/tmp/mono-" + user + "/.mono-" + pid;
109 UnixClient client = new UnixClient (path);
111 NetworkStream stream = client.GetStream ();
113 // Compose payload
114 MemoryStream ms = new MemoryStream ();
115 BinaryWriter writer = new BinaryWriter (ms);
116 write_string (writer, "attach");
117 write_string (writer, agent);
118 write_string (writer, args);
120 // Write header
121 byte[] magic = new byte [] { (byte)'M', (byte)'O', (byte)'N', (byte)'O', 1, 0 };
122 stream.Write (magic, 0, magic.Length);
124 // Write payload length
125 new BinaryWriter (stream).Write ((int)ms.Length);
127 // Write payload
128 stream.Write (ms.GetBuffer (), 0, (int)ms.Length);
131 enum PrimitiveType : byte {
132 PRIM_TYPE_NULL = 17,
133 PRIM_TYPE_STRING = 18
136 void write_string (BinaryWriter writer, string s) {
137 if (s == null)
138 writer.Write ((sbyte)PrimitiveType.PRIM_TYPE_NULL);
139 else {
140 writer.Write ((sbyte)PrimitiveType.PRIM_TYPE_STRING);
141 writer.Write (s);
142 writer.Write ((byte)0);
146 public override string ToString () {
147 return "VirtualMachine (pid=" + pid + ")";