1 /* |
1 /* |
2 * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
23 */ |
23 */ |
24 |
24 |
25 package sun.jvm.hotspot.debugger.linux; |
25 package sun.jvm.hotspot.debugger.linux; |
26 |
26 |
27 import java.io.File; |
27 import java.io.File; |
|
28 import java.io.IOException; |
|
29 import java.io.UncheckedIOException; |
|
30 import java.nio.file.Files; |
|
31 import java.nio.file.Path; |
|
32 import java.nio.file.Paths; |
28 import java.util.ArrayList; |
33 import java.util.ArrayList; |
29 import java.util.List; |
34 import java.util.List; |
|
35 import java.util.Map; |
|
36 import java.util.NoSuchElementException; |
|
37 import java.util.stream.Collectors; |
30 |
38 |
31 import sun.jvm.hotspot.debugger.Address; |
39 import sun.jvm.hotspot.debugger.Address; |
32 import sun.jvm.hotspot.debugger.DebuggerBase; |
40 import sun.jvm.hotspot.debugger.DebuggerBase; |
33 import sun.jvm.hotspot.debugger.DebuggerException; |
41 import sun.jvm.hotspot.debugger.DebuggerException; |
34 import sun.jvm.hotspot.debugger.DebuggerUtilities; |
42 import sun.jvm.hotspot.debugger.DebuggerUtilities; |
70 |
78 |
71 // threadList and loadObjectList are filled by attach0 method |
79 // threadList and loadObjectList are filled by attach0 method |
72 private List threadList; |
80 private List threadList; |
73 private List loadObjectList; |
81 private List loadObjectList; |
74 |
82 |
|
83 // PID namespace support |
|
84 // It maps the LWPID in the host to the LWPID in the container. |
|
85 private Map<Integer, Integer> nspidMap; |
|
86 |
75 // called by native method lookupByAddress0 |
87 // called by native method lookupByAddress0 |
76 private ClosestSymbol createClosestSymbol(String name, long offset) { |
88 private ClosestSymbol createClosestSymbol(String name, long offset) { |
77 return new ClosestSymbol(name, offset); |
89 return new ClosestSymbol(name, offset); |
78 } |
90 } |
79 |
91 |
87 |
99 |
88 // native methods |
100 // native methods |
89 |
101 |
90 private native static void init0() |
102 private native static void init0() |
91 throws DebuggerException; |
103 throws DebuggerException; |
92 private native void attach0(int pid) |
104 private native void setSAAltRoot0(String altroot); |
|
105 private native void attach0(int pid, boolean isInContainer) |
93 throws DebuggerException; |
106 throws DebuggerException; |
94 private native void attach0(String execName, String coreName) |
107 private native void attach0(String execName, String coreName) |
95 throws DebuggerException; |
108 throws DebuggerException; |
96 private native void detach0() |
109 private native void detach0() |
97 throws DebuggerException; |
110 throws DebuggerException; |
252 // new C++ ABI |
265 // new C++ ABI |
253 useGCC32ABI = true; |
266 useGCC32ABI = true; |
254 } |
267 } |
255 } |
268 } |
256 |
269 |
|
270 // Get namespace PID from /proc/<PID>/status. |
|
271 private int getNamespacePID(Path statusPath) { |
|
272 try (var lines = Files.lines(statusPath)) { |
|
273 return lines.map(s -> s.split("\\s+")) |
|
274 .filter(a -> a.length == 3) |
|
275 .filter(a -> a[0].equals("NSpid:")) |
|
276 .mapToInt(a -> Integer.valueOf(a[2])) |
|
277 .findFirst() |
|
278 .getAsInt(); |
|
279 } catch (IOException | NoSuchElementException e) { |
|
280 return Integer.valueOf(statusPath.getParent() |
|
281 .toFile() |
|
282 .getName()); |
|
283 } |
|
284 } |
|
285 |
|
286 // Get LWPID in the host from the container's LWPID. |
|
287 // Returns -1 if the process is running in the host. |
|
288 public int getHostPID(int id) { |
|
289 return (nspidMap == null) ? -1 : nspidMap.get(id); |
|
290 } |
|
291 |
|
292 // Fill namespace PID map from procfs. |
|
293 // This method scans all tasks (/proc/<PID>/task) in the process. |
|
294 private void fillNSpidMap(Path proc) { |
|
295 Path task = Paths.get(proc.toString(), "task"); |
|
296 try (var tasks = Files.list(task)) { |
|
297 nspidMap = tasks.filter(p -> !p.toString().startsWith(".")) |
|
298 .collect(Collectors.toMap(p -> Integer.valueOf(getNamespacePID(Paths.get(p.toString(), "status"))), |
|
299 p -> Integer.valueOf(p.toFile().getName()))); |
|
300 } catch (IOException e) { |
|
301 throw new UncheckedIOException(e); |
|
302 } |
|
303 } |
|
304 |
257 /** From the Debugger interface via JVMDebugger */ |
305 /** From the Debugger interface via JVMDebugger */ |
258 public synchronized void attach(int processID) throws DebuggerException { |
306 public synchronized void attach(int processID) throws DebuggerException { |
259 checkAttached(); |
307 checkAttached(); |
260 threadList = new ArrayList(); |
308 threadList = new ArrayList(); |
261 loadObjectList = new ArrayList(); |
309 loadObjectList = new ArrayList(); |
|
310 |
|
311 Path proc = Paths.get("/proc", Integer.toString(processID)); |
|
312 int NSpid = getNamespacePID(Paths.get(proc.toString(), "status")); |
|
313 if (NSpid != processID) { |
|
314 // If PID different from namespace PID, we can assume the process |
|
315 // is running in the container. |
|
316 // So we need to set SA_ALTROOT environment variable that SA reads |
|
317 // binaries in the container. |
|
318 setSAAltRoot0(Paths.get(proc.toString(), "root").toString()); |
|
319 fillNSpidMap(proc); |
|
320 } |
|
321 |
262 class AttachTask implements WorkerThreadTask { |
322 class AttachTask implements WorkerThreadTask { |
263 int pid; |
323 int pid; |
|
324 boolean isInContainer; |
264 public void doit(LinuxDebuggerLocal debugger) { |
325 public void doit(LinuxDebuggerLocal debugger) { |
265 debugger.attach0(pid); |
326 debugger.attach0(pid, isInContainer); |
266 debugger.attached = true; |
327 debugger.attached = true; |
267 debugger.isCore = false; |
328 debugger.isCore = false; |
268 findABIVersion(); |
329 findABIVersion(); |
269 } |
330 } |
270 } |
331 } |
271 |
332 |
272 AttachTask task = new AttachTask(); |
333 AttachTask task = new AttachTask(); |
273 task.pid = processID; |
334 task.pid = processID; |
|
335 task.isInContainer = (processID != NSpid); |
274 workerThread.execute(task); |
336 workerThread.execute(task); |
275 } |
337 } |
276 |
338 |
277 /** From the Debugger interface via JVMDebugger */ |
339 /** From the Debugger interface via JVMDebugger */ |
278 public synchronized void attach(String execName, String coreName) { |
340 public synchronized void attach(String execName, String coreName) { |